Notes posted to Ruby on Rails
RSS feedStreaming XML with Builder
To generate larger XMLs, it’s a good idea to a) stream the XML and b) use Active Record batch finders.
Here’s one way of doing it:
def my_action @items = Enumerable::Enumerator.new( Item.some_named_scope, :find_each, :batch_size => 500) respond_to do |format| format.xml do render :text => lambda { |response, output| extend ApplicationHelper xml = Builder::XmlMarkup.new( :target => StreamingOutputWrapper.new(output), :indent => 2) eval(default_template.source, binding, default_template.path) } end end end
The Builder template does not need to be modified.
Use camelize with singular words
To make the business example work, use camelize instead of classify:
"business".camelize # => "Business"
sort_by
array.sort_by {|element| [element.foo, element.bar.name, element.baz]}
Taken from http://redcorundum.blogspot.com/2006/10/using-sortby-instead-of-sort.html
Making ActiveRecord models readonly
To force an ActiveRecord model to be read only you can do something along these lines:
class DelicateInfo < ActiveRecord::Base def readonly? true end end
When you try to save the model it will raise an ActiveRecord::ReadOnlyRecord exception:
info = DelicateInfo.first info.save # => ActiveRecord::ReadOnlyRecord
Note, however, that destroy and delete will still work on the model unless you intercept those calls
form_tag with named route and html class
<% form_tag position_user_card_path(@user, card), :method => :put, :class => ‘position-form’ do %>
This code prevent's frome redirect_to(:back) looping
Prevent redirect_to(:back) looop
begin
# loop check if session[:last_back] != request.env['HTTP_REFERER'] redirect_to(:back) session[:last_back] = request.env['HTTP_REFERER'] else # raise on error raise ActionController::RedirectBackError end
rescue ActionController::RedirectBackError
# fallback on loop or other :back error redirect_to(:action => :index)
end
ActiveResource validation is a little different
Given the following model on the remote end:
class Person < ActiveRecord::Base validates_presence_of :first_name, :last_name, :email end
And this ActiveResource on the client end:
class Person < ActiveResource::Base self.site = "http://api.people.com:3000/" end
Validation messages will only be returned after an attempted save call on the client end - eg:
person = Person.new( :first_name => 'Billy', :emails => "william@anotherplanet.co.za" ) person.valid? # => true person.errors.full_messages # => [] person.save # => false person.valid? # => false person.errors.full_messages # => ["Last name can't be empty"]
In ActiveResource::Base it is suggested that you can perform client site validation with something like this:
class Person < ActiveResource::Base self.site = "http://api.people.com:3000/" protected def validate errors.add("last name", "can't be empty") if last_name.blank? end end
Update attributes on mulitple models
Updates attributes on multiple models, saves each if validations pass.
def update_multiple
@items = Item.find(params[:item_ids]) @items.each do |item| item.attributes = params[:item].reject { |k,v| v.blank? } end if @items.all?(&:valid?) @items.each(&:save!) flash[:notice] = "Updated items!" redirect_to items_path else flash[:notice] = "Please enter valid data." render :action => 'edit_multiple' end end
See also: ActiveRecord::Base#increment
This is a class-level method. For the instance-level equivalent see: ActiveRecord::Base#increment
item = Item.find(1) item.foo_count # => 0 Item.increment_counter(:foo_count, 1) item.foo_count # => 0 item.reload item.foo_count # => 1 item.increment(:foo_count) item.foo_count # => 2
Passing parameters to before_filter
I’ve found on the net 2 ways to pass parameters to before_filter:
method 1:
before_filter do |c| c.class.module_eval do private def custom_filter authorize(args) end end end before_filter :custom_filter
method 2:
before_filter do |c| c.send(:authorize, args) end
This method has been moved
This method has been moved to ActiveSupport::Inflector#demodulize
This method has been moved
This method has been moved to ActiveSupport::Inflector#foreign_key
This method has been moved
This method has been moved to ActiveSupport::Inflector#humanize
This method has been moved
This method has been moved to ActiveSupport::Inflector#inflections
This method has been moved
This method has been moved to ActiveSupport::Inflector#ordinalize
This method has been moved
This method has been moved to ActiveSupport::Inflector#singularize
This method has been moved
This method has been moved to ActiveSupport::Inflector#tableize
This method has been moved
This method has been moved to ActiveSupport::Inflector#titleize
This method has been moved
This method has been moved to ActiveSupport::Inflector#underscore
This method has been moved
This method has been moved to ActiveSupport::Inflector#dasherize
This method has been moved
This method has been moved to ActiveSupport::Inflector#constantize
This method has been moved
This method has been moved to ActiveSupport::Inflector#classify
This method has been moved
This method has been moved to ActiveSupport::Inflector#camelize
Regenerate the JavaScript after each RJS call
RISCfuture - I had trouble using sortable_element_js in my rjs (javascript error when I used options), but had success with page.sortable(‘the_id’,{a_hash_of_my_options}) in my rjs
Pluralize Without Count
Helper method that returns the word without the count.
application_helper.rb
def pluralize_without_count(count, noun, text = nil) if count != 0 count == 1 ? "#{noun}#{text}" : "#{noun.pluralize}#{text}" end end
Example usage:
_form.html.erb
<%= pluralize_without_count(item.categories.count, 'Category', ':') %>
Will discard any order option
order_by(:created_at).find_each == FAIL!!!
class ActiveRecord::Base # normal find_each does not use given order but uses id asc def self.find_each_with_order(options={}) raise "offset is not yet supported" if options[:offset] page = 1 limit = options[:limit] || 1000 loop do offset = (page-1) * limit batch = find(:all, options.merge(:limit=>limit, :offset=>offset)) page += 1 batch.each{|x| yield x } break if batch.size < limit end end end
Attachment's name
Files attached in a standard way are shown up as “noname”. You can specify any name by using the :filename key:
attachment :content_type => "application/pdf", :filename => "Othersheet.pdf", :body => File.read("example.pdf")
:popup gotcha in IE
If your popup title contains spaces or escaped HTML characters, Internet Explorer (at least 6/7) will not pop up a new window but open the link in the existing browser window.
Add last_week to core_extensions
If you want to implement last_week as posted by Mange, save it as:
lib/core_extensions.rb
class Date def last_week(day = :monday) days_into_week = { :monday => 0, :tuesday => 1, :wednesday => 2, :thursday => 3, :friday => 4, :saturday => 5, :sunday => 6} result = (self - 7).beginning_of_week + days_into_week[day] self.acts_like?(:time) ? result.change(:hour => 0) : result end end
And add to:
config/environment.rb
require 'core_extensions'


