Recent notes

RSS feed
March 3, 2009 - (<= v2.2.1)
1 thank

Multiple associations on the same level

You can also specify multiple associations that are on the same level, like this:

konata = User.find(1)
konata.to_json(:include => [:posts, :roles])

{"id": 1, "name": "Konata Izumi", "age": 16,
 "created_at": "2006/08/01", "awesome": true,
 "posts": [{"id": 1, "author_id": 1, "title": "Welcome to the weblog"},
           {"id": 2, author_id: 1, "title": "So I was thinking"}],
 "roles": [{"id":1, "user_id":1, "name": "Admin"},
           {"id":2, "user_id":1, "name": "Moderator"}]}
March 2, 2009
2 thanks

Valid options changed in Rails v2.3.0 RC1

The valid options in Rails v2.3.0 RC1 are no longer

:connector and :skip_last_comma, but

:words_connector, :two_words_connector, and :last_word_connector:

>> %w(lorem ipsum dolor sit).to_sentence
=> "lorem, ipsum, dolor, and sit"

>> %w(lorem ipsum dolor sit).to_sentence(:words_connector => ' + ')
=> "lorem + ipsum + dolor, and sit"

>> %w(lorem ipsum).to_sentence(:two_words_connector => ' through ')
=> "lorem through ipsum"

# No effect if more than two words
>> %w(lorem ipsum dolor sit).to_sentence(:two_words_connector => ' through ')
=> "lorem, ipsum, dolor, and sit"

>> %w(lorem ipsum dolor sit).to_sentence(:last_word_connector => ' or ')
=> "lorem, ipsum, dolor or sit"
March 1, 2009
2 thanks

used for testing

for example, to use the @message instance variable in a view test,

assigns[:message] = @message

you could type

assigns[:foo] = @message

and then message would be available to the view as @foo.

February 28, 2009
0 thanks

Exceptions while debugging

If the error wasn’t stored in a variable, you can still see it by looking at the global variable $ERROR_INFO.

February 28, 2009
1 thank


Store exceptions using ‘rescue => var’

  x = factorial(-1)             
rescue => ex                       
  puts "#{ex.class}: #{ex.message}"
February 27, 2009
6 thanks

Extend with an anonymous module

You can extend with an anonymous module for one-off cases that won’t be repeated:

belongs_to :container, :polymorphic => true, :extend => ( Module.new do
    def find_target
  end )

The parentheses are important, will fail silently without them.

February 27, 2009 - (v1.2.6 - v2.2.1)
0 thanks


The source if this method and other methods indicate the reading of read_attribute (protected)

there is no documentation about the insides of this method, the only entry listed is read_attribute (private) which is deprecated since 1.2.6?

February 26, 2009 - (v1.0.0 - v2.1.0)
0 thanks

Conflicts with Ruby 1.8.7

Using this with Rails < 2.2.x and Ruby 1.8.7 will create a conflict between ActiveSupport and Ruby, generating the following error:

>> '/'.first
NoMethodError: undefined method `[]' for #<Enumerable::Enumerator:0x176b974>
  from /opt/local/lib/ruby/gems/1.8/gems/activesupport-2.0.2/lib/active_support/core_ext/string/access.rb:43:in `first'

So if using an older version of Rails with Ruby 1.8.7, use String to instead of String.first

February 25, 2009
0 thanks

Always a String

Remember that even if you ask for one field that is a number, a String will be returned:

Time.now.strftime("%j") #=> "055"
February 24, 2009
9 thanks

Specialized versions of find with method_missing

Check ActiveRecord::Base.method_missing for documentation on the family of “magic” find methods (find_by_x, find_all_by_x, find_or_create_by_x, etc.).

February 24, 2009 - (>= v2.2.1)
5 thanks

ATM does not work in Rails 2.3 Edge

add to test/spec_helper to make it work again…

#spec_helper / test_helper
include ActionController::TestProcess
February 24, 2009
2 thanks

Test if one array includes the elements of another v2

Maybe a bit more readable way to write the previous snippet would’ve been

puts "yay" if [1, 2, 3].all? { |i| (1..9).include?(i) }
# => "yay"

puts "nope" if [1, 2, 3, 'A'].any? { |i| not (1..9).include?(i) }
# => "nope"
February 24, 2009
0 thanks

Test if one array includes the elements of another

Recently I’ve written this little snippet:

puts "yay" if [1, 2, 3].each {|i| break unless (1..9).to_a.include?(i)}
# => "yay"

puts "nope" unless [1, 2, 3, 'A'].each {|i| break unless (1..9).to_a.include?(i)}
# => "nope"
February 24, 2009
0 thanks

Validate an optional URL field

Let’s say that you have an optional URL field to one of your models and you want to validate the URL. You can accomplish this by using the URI library:

require 'uri' # Put this at the beginning of your model file

validates_each :url, :allow_blank => true do |record, field, value|
    valid = (URI.parse(value).scheme =~ /https?/)
  rescue URI::InvalidURIError
    valid = false
  record.errors.add field, "not a valid url" unless valid

If you want to add even more testing in there, just go ahead. For now, we just check that the link is to a HTTP resource, but you might have other requirements. This will allow stuff like “http://example” since “example” might be a valid intranet domain. If you want to check for a TLD in there, you can do so with a simple regexp.

For more information about the URI library, check out http://apidock.com/ruby/URI/

February 23, 2009 - (<= v2.2.1)
1 thank

You can't have many :through with habtm

Imagine the following

a has_many b
b has_and_belongs_to_many c
a has_many c :through => b

a.b works fine

b.c works fine

a.c throws an error!

has_many :through where the through association is a habtm is not supported in Rails. The error is:

ActiveRecord::HasManyThroughSourceAssociationMacroError: Invalid source reflection macro :has_and_belongs_to_many for has_many :stories, :through => :subcategories. Use :source to specify the source reflection

Specifying the source reflection still won’t help you though, because this kind of has_many :through isn’t supported at all.

February 23, 2009 - (>= v2.0.0)
5 thanks

Nested with_options

You can nest with_options blocks, and you can even use the same name for the block parameter each time. E.g.:

class Product
  with_options :dependent => :destroy do |product|
    product.with_options :class_name => 'Media' do |product|
      product.has_many :images, :conditions => {:content_type => 'image'}
      product.has_many :videos, :conditions => {:content_type => 'video'}

    product.has_many :comments
February 23, 2009
2 thanks

Check if value is included in array of valid values

If you want to check the value of an attribute using an array of valid values, the array has to be defined before the validation, so

validates_inclusion_of :name, :in => VALID_NAMES
VALID_NAMES = %w(Peter Paul Mary)

won’t work, but

VALID_NAMES = %w(Peter Paul Mary)
validates_inclusion_of :name, :in => VALID_NAMES


February 22, 2009
3 thanks

CAUTION! :frequency option description is misleading

To use event-based observer, don’t supply :frequency param at all. :frequency => 0 causes JS error.

Use this option only if time-based observer is what you need.

February 20, 2009
5 thanks

Static and dynamic attachments

You can attach static files directly:

attachment :content_type => "image/jpeg", :body => File.read("someimage.jpg")

and you can also define attachments dynamically by using a block:

attachment "text/csv" do |a|
  a.body = my_data.to_csv
February 18, 2009
4 thanks

Turn off for individual controllers/actions

To disable protection for all actions in your controller use skip_before_filter:

skip_before_filter :verify_authenticity_token

You can also pass :only and :except to disable protection for specific actions, e.g:

skip_before_filter :verify_authenticity_token, :only => :index
February 17, 2009
4 thanks

Date_select with assert_valid_keys

If you are using date_select with assert_valid_keys you have to allow 3 parameters named field(1i), field(2i) and field(3i).

For example with field

date_select("post", "written_on")

You have to allow following fields:

  'written_on(1i)', 'written_on(2i)', 'written_on(3i)'
February 17, 2009
7 thanks

Usage examples

Basic usage:

User.should_receive(:find).with(:all, anything).and_return("hello world")


User.find(:all, :conditions => "foo")  #=> "hello world"

But you can also use blocks for more complex matching logic. For example:

User.should_receive(:find) { |*args|
  if args.size == 2
    "received two arguments"
    "something else"


User.find(:all, :conditions => "bar")  #=> "received two arguments"
User.find(5)                           #=> "something else"

Of course normally you’d return mocks instead of strings.

February 17, 2009
9 thanks

Empty elements

If you want to output an empty element (self-closed) like “br”, “img” or “input”, use the tag method instead.

February 17, 2009
2 thanks

Remember to sanitize name

While useful when in need of richer markup inside a link, the name parameter isn’t sanitized or escaped and thus should be escaped when its content can’t be guaranteed to be safe.


link_to(url, url)

may cause problems with character entities if url contains ampersands.

Correct usage
link_to(h(url), url)

This applies to all dynamic content.

February 17, 2009
2 thanks

See column

See the end part of the docs on column for example uses.

February 16, 2009
1 thank

See max

See max for comments and more usage examples.

February 16, 2009
2 thanks

Capping values

This method is very useful when you want to cap values:

# minimum ≤ value 
value = [input.to_i, minimum].max

# value ≤ maximum
value = [input.to_i, maximum].min

# minimum ≤ value ≤ maximum
value = [ [input.to_i, minimum].max, maximum ].min

# Practical example: Make sure destination is within container
destination.x = [ [current.x + current.velocity.x, 0].max, container.width  ].min
destination.y = [ [current.y + current.velocity.y, 0].max, container.height ].min
February 16, 2009
5 thanks

Usage example

Some examples:

# Remove even numbers
(1..30).reject { |n| n % 2 == 0 }
# => [1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29]

# Remove years dividable with 4 (this is *not* the full leap years rule)
(1950..2000).reject { |y| y % 4 != 0 }
# => [1952, 1956, 1960, 1964, 1968, 1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000]

# Remove users with karma below arithmetic mean
total = users.inject(0) { |total, user| total += user.karma }
mean = total / users.size
good_users = users.reject { |u| u.karma < mean }