Notes posted to Ruby on Rails

RSS feed
October 22, 2008
10 thanks

Gotcha when defining :finder_sql or :counter_sql

When setting custom SQL statements in the :finder_sql or :counter_sql queries, if you need to inject attributes from the current object, such as the ID, make sure to disable string interpolation of the statement by using single quotes or %q().


has_many :relationships, :class_name => 'Relationship', :finder_sql => %q(
  SELECT DISTINCT relationships.*
  FROM relationships
  WHERE contact_id = #{id}

Surrounding this SQL with double-quotes or %Q() will expand #{id} too early, resulting in a warning about Object#id being deprecated and general brokenness.

October 22, 2008 - (>= v2.1.0)
2 thanks

HABTM relation

When you want to create a has_and_belong_to_many relation (og just a has_many :through) use this setup.

class CreateCourses < ActiveRecord::Migration
  def self.up
    create_table :seasons do |t|
      t.integer :year
      t.string :period

    create_table :courses do |t|
      t.string :courseCode

    create_table :courses_seasons, :id => false do |t|
      t.references :course, :null => false
      t.references :season, :null => false
    add_index :courses_seasons, [:course_id, :season_id], :unique => true


  def self.down
    drop_table :seasons
    drop_table :courses
    drop_table :courses_seasons
October 22, 2008
2 thanks

Regenerate the JavaScript after each RJS call

I had a sortable_element that was also a drop_receiving_element. After an element was dropped onto this div, an RJS action refreshed the div with the new elements. The div expanded with these new elements, but the sortable portion remained the same size.

To correctly be able to reorder elements after an Element.update call (from an RJS action or wherever), you need to include a second call to Sortable.create in your RJS view (or other JavaScript), using sortable_element_js or whatever method you please.

October 21, 2008
5 thanks

Using a Loading Graphic

If you want to make a little loading graphic, typically you use an animated gif (like a little spinner or something). Both link_to_remote and remote_form_for allow you to easily do this by using the :loaded and :loading triggers to call javascript.

For example:

<% remote_form_for @survey, :loading => "$('loading').show();", :loaded => "$('loading').hide();" do |f| %>
  <%= submit_tag ' Save' %>
  <%= image_tag "indicator_circle.gif", :style => 'display: none;', :id => 'loading' %>
<% end %>

The ‘loading’ parameter used for the ‘$’ prototype selector is the id of the animated gif. It starts out hidden, and is toggled by the loading/loaded triggers.

October 20, 2008
3 thanks


in small cells:

12def number_to_euro(amount)
  number_to_currency(amount,:unit=>'').gsub(' ',nbsp)
October 18, 2008
0 thanks

Single Table Inheritance and Fixtures

All entries for fixtures for classes derived from the base class must go into the fixture file of the base class. Also, their type must be set. Example fixture:

  name: My Company

  name: A Firm
  type: Firm

  name: SuperVIPClient
  type: PriorityClient
  priority: 1
October 16, 2008
0 thanks

Only error message

<%= error_messages_for :order, :header_message => nil, :message => nil %>

Browser view code

<div id=“errorExplanation” class=“errorExplanation”>

    <li>Weight 只有 1000.0</li>
    <li>Volume 只有 10.0</li>
October 15, 2008
29 thanks

List of status codes and their symbols

Note that the :status option accepts not only an HTTP status code (such as 500), but also a symbol representing that code (such as :created), if that makes more sense to you. Here’s a list of which symbols map to which numbers (derived from ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE):

100 = :continue
101 = :switching_protocols
102 = :processing
200 = :ok
201 = :created
202 = :accepted
203 = :non_authoritative_information
204 = :no_content
205 = :reset_content
206 = :partial_content
207 = :multi_status
226 = :im_used
300 = :multiple_choices
301 = :moved_permanently
302 = :found
303 = :see_other
304 = :not_modified
305 = :use_proxy
307 = :temporary_redirect
400 = :bad_request
401 = :unauthorized
402 = :payment_required
403 = :forbidden
404 = :not_found
405 = :method_not_allowed
406 = :not_acceptable
407 = :proxy_authentication_required
408 = :request_timeout
409 = :conflict
410 = :gone
411 = :length_required
412 = :precondition_failed
413 = :request_entity_too_large
414 = :request_uri_too_long
415 = :unsupported_media_type
416 = :requested_range_not_satisfiable
417 = :expectation_failed
422 = :unprocessable_entity
423 = :locked
424 = :failed_dependency
426 = :upgrade_required
500 = :internal_server_error
501 = :not_implemented
502 = :bad_gateway
503 = :service_unavailable
504 = :gateway_timeout
505 = :http_version_not_supported
507 = :insufficient_storage
510 = :not_extended
October 14, 2008 - (>= v2.0.0)
0 thanks

Wrapping peculiarities as of 2.x

In Rails 2.x word_wrap has been improved so that it no longer consumes multiple line-breaks or leading & trailing line-breaks.

word_wrap("\nOnce upon a time\n\nThe End\n")
# => \nOnce upon a time\n\nThe End

However it still doesn’t break long words

# => 30
word_wrap("\nOnce upon a supercalifragilisticexpialidocious time", 15)
# => \nOnce upon a\nsupercalifragilisticexpialidocious\ntime
October 14, 2008 - (v1.0.0 - v1.2.6)
1 thank

Wrapping peculiarities

word_wrap will consume multiple line-breaks as well as leading & trailing line-breaks.

word_wrap("\nOnce upon a time\n\nThe End\n")
# => Once upon a time\nThe End

word_wrap will NOT break long words

# => 34
word_wrap("\nOnce upon a supercalifragilisticexpialidocious time", 15)
# => Once upon a\nsupercalifragilisticexpialidocious\ntime

If you want a function that will break long words & maintain multiple line-breaks try this alternative. Note it does add a line break at the end of the output.

def breaking_wrap_wrap(txt, col = 80)
  txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,

breaking_wrap_wrap("\nOnce upon a supercalifragilisticexpialidocious time", 15)
# => \nOnce upon a\nsupercalifragil\nisticexpialidoc\nious time\n

Regex-based code from http://blog.macromates.com/2006/wrapping-text-with-regular-expressions/

October 11, 2008 - (v2.0.0 - v2.0.3)
1 thank

Assert tag children


#<div id="example">
#  <ul>
#    <li class="btn_1"><a href="#">link1</a></li>
#    <li class="btn_2"><a href="#">link2</a></li>
#  </ul>

assert_tag :tag => 'div',
  :attributes => {:id => "example"},
  :child => {
    :tag => 'ul',
    :child => {
      :tag => 'li',
      :attributes => {:class => 'btn_1'},
      :child => {
        :tag => 'a',
        :attributes => {:href => '#'},
        :content => 'link1'
      :sibling => {
        :tag => 'li',
        :attributes => {:class => 'btn_2'},
        :child => {
          :tag => 'a',
          :attributes => {:href => '#'},
          :content => /link/
October 10, 2008
2 thanks

Make an action onchange

collection_select(nil, :provincia_id, @provincias, :id, :nombre, {:prompt => “Seleccione una provincia”}, {:onchange => “#{remote_function(:url => {:controller => ‘direccions’, :action => ”update_pueblos“}, :with => ”‘provincia_id=’+value“)}”})

October 10, 2008
8 thanks

Implemented in database adapters

These methods are not implemented in the abstract classes. Instead, all database adapters implement these separately, if the feature is supported.

October 10, 2008 - (v2.1.0)
1 thank

Not implented yet

According to this method’s source, change_column_default is not implemented as well as change_column

October 9, 2008 - (v1.2.0 - v2.1.0)
12 thanks

Rendering nothing

If your controller action does not explicitly call render, Rails will, by default, attempt to locate and render the template corresponding to the action. It’s not uncommon, for example with Ajax calls, to want to render nothing. This will circumvent the default rendering and prevent errors on missing templates. To render nothing simply do the following:

render :nothing => true

Its important to note that this isn’t the same as returning no HTTP response. In fact, this results in an HTTP response with a status code of 200 OK being sent back with a blank content body. Why does it matter? Well, you can still test your controller by asserting that a :success response was returned.

October 8, 2008
3 thanks

Seriously! Do not forget the brackets

thank you source jamesandre.ws

the form_for([:admin, @user]) must have the [] brackets to avoid errors like “Only get requests are allowed”

<% form_for([:admin, @user]) do |f| %>
<%= render :partial => 'form' %>
<%= submit_tag "Create" %>
<% end %>
October 7, 2008 - (v2.0.3 - v2.1.0)
0 thanks

Validate Mixup

Looks like the docs from validate got mixed up here. Only the last example is actually relevant to validates_each.

October 7, 2008 - (v2.0.3 - v2.1.0)
4 thanks

More on deprecation

This is not deprecated. I think the docs are confused because the validate, validate_on_create, and validate_on_update methods are actually callbacks and not explicitly defined on their own. The correct usage is the same as in the docs above.

October 6, 2008 - (<= v2.1.0)
1 thank

Multiple select and observe form

To make an observe form send all of the values selected in a multiple select html list, ensure you have the square brackets set in the name for the select tag e.g: group[]. This makes it pass the selected options in the params hash as an array.

<% remote_form_for :model, :url => {:action => ‘list’}, :html =>{:id => ‘model_id’} do |form| %>

<%= select_tag(‘group[]’, options_for_select(Model.find(:all).collect{|v|v.property}), :multiple => true) %>

<% end %>

<%= observe_form( ‘model’, :frequency => 2, :url => {:action => ‘list’} ) %>

October 2, 2008
9 thanks

:prefix option

Be aware!

By default, if you do select_month(Date.today, :field_name => ‘start’) it will generate select tag with name “date[start]”. If you want it to be something other than date[], add :prefix option, like this:

select_month(Date.today, :field_name => 'start', :prefix => 'timer')

This will render select tag with name “timer[start]”.

Taken from sources of name_and_id_from_options method.

October 2, 2008
1 thank

Setting ttl

Use the expires_in option to set a TTL for the cached item.

Rails.cache.write("top_items", :expires_in => 5.minutes)

You can use this with the fetch method as well:

Rails.cache.fetch("top_items", :expires_in => 5.minutes) do
  # some very expensive calculations

Note: this only works with supporting cache stores, like the MemCacheStore

October 1, 2008
5 thanks
September 30, 2008
5 thanks

If you're not using resource

If you don’t use resource for your remote_form_for, then :url option is necessary.

For example:

<% remote_form_for "not_resource" do |f| ... %> 

won’t work. But with :url option, it will:

<% remote_form_for "not_resource", 
     :url => { :controller => "recommend", :action => "send" } do ... %> 
September 28, 2008 - (v2.0.0 - v2.1.0)
3 thanks

has_one Nesting in Rails 2.0


map.resources :user, :has_one => [:avatar]


form_for [@user, @avatar], :url => user_avatar_url(@user) do |f|
September 26, 2008 - (v1.2.6 - v2.1.0)
5 thanks

Pass the observed fields value as a parameter in the Ajax request

Use encodeURIComponent with with to pass an encoded value as a parameter (POST or GET) of the AJAX request. For example:

<%= observe_field :company_id,

:url => {:action => ‘facilities’, :only_path => false}, :with => “‘company=’ + encodeURIComponent(value)” %> Also, setting only_path => false for the URL ensures that the full URL (including host and protocol) is used for the AJAX request.

September 26, 2008
4 thanks

Example of composed_of composition class implementation

If we have following code in model:

composed_of :temperature, :mapping => %w(celsius)

Then our composition class can be this:

class Temperature
  def initialize(celsius)
    @celsius = celsius

  # This method is called by ActiveRecord, when record is saved.
  # Result of this method will be stored in table in "celsius" field,
  # and later when the record is loaded again, this will go to 
  # our Temperature#new constructor.
  def celsius

  # This is example of method that we can add to make this composition useful.
  def farenheit 
    @celsius * 9/5 + 32
September 25, 2008
4 thanks

has_many :through

It’s is recommended to use has_many :through association instead of has_and_belongs_to_many. has_many :through is better supported and generally easier to work with once you grasp the idea.