Recent good notes

RSS feed
October 30, 2009
7 thanks

How FormBuilders work

What, you were expecting documentation? :)

An excellent survey of how FormBuilders work is here:


October 30, 2009
3 thanks

Map-like Manipulation of Hash Values

Let’s say you want to multiply all values of the following hash by 2:

hash = { :a => 1, :b => 2, :c => 3 }

You can’t use map to do so:

hash.map {|k, v| v*2 }   # => [6, 2, 4]

However, with merge you can:

hash.merge(hash) {|k,v| v*2 }   => {:c=>6, :a=>2, :b=>4}

(The above is Ruby 1.8, in Ruby 1.9 the order is preserved.)

October 28, 2009
7 thanks


The opposite of this is #blank?

October 27, 2009
4 thanks


The opposite of this is #present?

October 22, 2009 - (>= v2.1.0)
4 thanks

Update statement won't include all attributes with ActiveRecord::Dirty

With the addition of ActiveRecord::Dirty, the update statement will only feature changed columns, as opposed to the comment of railsmonk below.

October 20, 2009
3 thanks

See Dir#glob

See glob for more usage information and comments.

October 15, 2009
4 thanks

Have check_box checked by default

In addition to comment below, you can make a column with default value so in your forms it will be enabled by default and behave correctly with validation errors unlike :checked => true

in your migration

add_column :accounts, :ssl_enabled, :boolean, :default => 1
October 7, 2009
4 thanks


Here’s a small helper for doing the “opposite” of this method:

class Hash
  def without(*keys)
    cpy = self.dup
    keys.each { |key| cpy.delete(key) }

h = { :a => 1, :b => 2, :c => 3 }
h.without(:a)      #=> { :b => 2, :c => 3 }
h.without(:a, :c)  #=> { :b => 2 }
October 7, 2009 - (>= v2.3.2)
3 thanks

Streaming 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(
    :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)

The Builder template does not need to be modified.

October 2, 2009
5 thanks

form_tag with named route and html class

<% form_tag position_user_card_path(@user, card), :method => :put, :class => ‘position-form’ do %>

September 14, 2009
6 thanks

Pluralize Without Count

Helper method that returns the word without the count.


def pluralize_without_count(count, noun, text = nil)
  if count != 0
    count == 1 ? "#{noun}#{text}" : "#{noun.pluralize}#{text}"

Example usage:


<%= pluralize_without_count(item.categories.count, 'Category', ':') %>
September 9, 2009
3 thanks

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
August 20, 2009
4 thanks


@tadman - or simply defining:

class Symbol
  def to_proc
    proc { |obj, *args| obj.send(self, *args) }
August 18, 2009
3 thanks

Auto-submitting select tag

If you want your form to be submitted when user selects something, use:

:onchange => "this.form.submit();"

For example:

select_tag "people", "<option>David</option>", :onchange => "this.form.submit();"
August 13, 2009
3 thanks

With multiple parameters


   :url => some_remote_function_path, 
   :with => "'key1='+$('elem_id').value +'&key2='+$('elem_id').value+ '&this_elem_value='+value"
August 13, 2009 - (>= v2.3.2)
3 thanks

with_exclusive_scope example by Ramon broken in latest Rails

The example Ramon gave works within the model itself, i.e.

class Article
  def closed
    with_exclusive_scope { find(:all) }

However, from what I can see, this approach does not work within a controller. You may be wanting to use

Article.with_exclusive_scope { find(:all) }  #=> "SELECT * FROM 'articles'

But it will error out about find(:all) not existing on ArticlesController. To get around this, you must now do

Article.with_exclusive_scope { Article.find(:all) }  #=> "SELECT * FROM 'articles'

In otherwards, find(:all) isn’t being executed in the scope of the model, but in the controller in which its called.

Took me a minute or two to find out, so I thought I’d let others know.

August 7, 2009
7 thanks

Join multiple tables

It’s easy to join multiple tables too. In this case we have:

class Article
  belongs_to :feed

class Feed
  has_many :articles
  belongs_to :source

class Source
  has_many :feeds
  # t.bool :visible

You can search articles and specify a condition on the sources table.

  :conditions => { :feeds => { :sources => { :visible => true }}}, 
  :joins => [:feed => :source],
August 7, 2009
3 thanks


This method only returns a cache manager object of sorts, to see what you can do with it, see ActiveSupport::Cache::Store.

August 6, 2009
4 thanks

Documentation bug

When adding the :target option, the documentation states that you should user :href_options like so:

auto_link(post_body, :href_options => { :target => '_blank' })

However, I could only get it to work using :html instead:

auto_link(post_body, :html => { :target => '_blank' })

I’m using Rails 2.2.2, but I believe that this also happens for more recent version .

July 28, 2009
8 thanks

Return True

As is the case with the before_validation and before_save callbacks, returning false will break the callback chain. For example, the expire_cache_id method will not run if Rails.cache.expire returns false (as it will if the key is not cached with memcache).

Returning False Example (Bad)

after_save :expire_cache_by_name
after_save :expire_cache_by_id

def expire_cache_by_name

def expire_cache_by_id

Returning True Example (Good)

def expire_cache_by_name
  return true

def expire_cache_by_id
  return true
July 27, 2009 - (>= v2.2.1)
3 thanks

Overriding default validation messages

Before Rails 2.2 you could globally customize the default validation error messages by changing AR::Base.default_error_messages. The messages have now been moved to i18n, so to customize them in 2.2 and up, just create a locales/ folder in your config/ folder, copy activerecord/lib/active_record/locale/en.yml (in Rails source) to config/locales/en.yml, and then change the strings inside. As szeryf indicated below, the strings of interest are activerecord.errors.messages.

July 23, 2009 - (v1.0.0 - v2.3.2)
7 thanks

Format meaning

%a - The abbreviated weekday name (“Sun”)

%A - The full weekday name (“Sunday”)

%b - The abbreviated month name (“Jan”)

%B - The full month name (“January”)

%c - The preferred local date and time representation

%d - Day of the month (01..31)

%H - Hour of the day, 24-hour clock (00..23)

%I - Hour of the day, 12-hour clock (01..12)

%j - Day of the year (001..366)

%m - Month of the year (01..12)

%M - Minute of the hour (00..59)

%p - Meridian indicator (“AM” or “PM”)

%S - Second of the minute (00..60)

%U - Week number of the current year, starting with the first Sunday as the first day of the first week (00..53)

%W - Week number of the current year, starting with the first Monday as the firstday of the first week (00..53)

%w - Day of the week (Sunday is 0, 0..6)

%x - Preferred representation for the date alone, no time

%X - Preferred representation for the time alone, no date

%y - Year without a century (00..99)

%Y - Year with century

%Z - Time zone name

%% - Literal “%” character

July 8, 2009 - (<= v1_8_7_72)
5 thanks

Using block version in Ruby < 1.8.7

The block usage was added in 1.8.7, so to get the same functionality in an earlier version of Ruby, you need to utilize the find method.

Here is a quick example:

match = list.find { |l| l.owner == myself }
match_index = list.index(match)

If you do some gymnastics, you can have it on one line without extra variables:

match_index = list.index(list.find { |l| l.owner == myself })
July 7, 2009 - (<= v2.3.2)
5 thanks


Available options are (none of these exists by default):

* :limit - Requests a maximum column length. This is number of characters for :string and :text columns and number of bytes for :binary and :integer columns.
* :default - The column‘s default value. Use nil for NULL.
* :null - Allows or disallows NULL values in the column. This option could have been named :null_allowed.
* :precision - Specifies the precision for a :decimal column.
* :scale - Specifies the scale for a :decimal column.
July 1, 2009
4 thanks


User = Struct.new(:name, :phone)

marc = User.new(“Marc”, “555-5555”)

June 30, 2009
3 thanks

Be careful with name of attribute writer

If restricting access to attributes you normally get code like

attr_accessible :foo,  

When using these nested attributes you end up with code like

attr_accessible :foo, :bar_attributes

Its very easy to leave of the _attributes suffix e.g

attr_accessible :foo, :bar

which will cause you all sorts of problems

June 22, 2009
3 thanks

Optional local assigns

When you have a partial with optional local assigns, for instance:

<%= render :partial => 'articles/preview' %>
<%= render :partial => 'articles/preview', :locals => { :show_call_out => true } %>

And you don’t want the partial to break when the local isn’t assigned, you can reference it through the local_assigns local variable instead of through the template binding:

<% if local_assigns[:show_call_out] %>
  <em><%= format @article.call_out %></em>
<% end %>
June 18, 2009
3 thanks

Not really deprecated

This isn’t really deprecated, it’s just relocated to ActiveRecord::AttributeMethods#read_attribute

June 18, 2009
12 thanks

Important note

It has been said that “it can be compared to, but isn’t the same thing as”:

class Bar
  class << self
    attr_accessor :greeting

Which is true. However, they are “inherited” isn’t exactly the case. Rather, cattr_accessor uses class variables.

The problem with class variables in Ruby, is that a class variable is the same object across all subclasses of a class. Consider the following example of what happens with cattr_accessor:

class A
  @@foo = 'foo'

  def self.foo

p A.foo # => "foo"

class B < A

p B.foo # => "foo"

class B
  @@foo = 'bar'

p B.foo # => "bar"

So far so good you might think. However, something you might not have expected is that the variable has now also changed in class A:

p A.foo # => "bar"

This is in my opinion almost never what you’d want. More probable is that you’d want the individual class instance to have an accessor. (Remember classes are objects in Ruby). I do the following in regular Ruby:

class A
  class << self
    attr_accessor :foo

  self.foo = 'foo'

p A.foo # => "foo"

class B < A

p B.foo # => nil

class B
  self.foo = 'bar'

p B.foo # => "bar"

p A.foo # => "foo"

As you can see, this returns nil when a value hasn’t explicitly been set yet on the new class instance. If you’d like to have inheritance without messing with the superclasses variables, have a look at ActiveSupport’s class_inheritable_accessor, which does the same as I just explained, but creates a clone of the object and assigns it to the subclass whenever a class is inherited.

What I’d normally do in Ruby to fix the issue of it returning nil is to create the accessor manually and have it set the instance variable to the default if it’s nil:

class A
  class << self
    def foo
      @foo ||= 'foo'

class B < A

p B.foo # => nil

So to recap:

  • cattr_accessor uses class variables (@@foo), in which case the object is shared across all subclasses of a class. Use it mainly for static data, in which case you’d probably best use a constant.

  • class_inheritable_accessor (or what I showed) uses instance variables (@foo) at the Class instance level. These variables are not shared across all subclasses.

June 18, 2009
3 thanks

Expensive method!

This method builds the a new hash every time it’s called, so be cautious not to use it in loops etc.