Recent notes

RSS feed
March 21, 2009
0 thanks

Remember, named_scope returns an array

named_scope always returns a named_scope object, that acts like an array, even if you’re using it to only find one record. So if you’re trying to perform an association on the results of a named_scope, use the first method to return the model object and not the named_scope object.


user = User.my_name_scope
user.articles   # assuming User has_many Articles

will return an error. use this instead:

user = User.my_named_scope.first

(Of course this is a poor example because what you should be doing is performing the named_scope on Article with user as the condition, instead of on User. But if you do need to use the results of a named_scope to perform an association call, you have to do it this way to avoid an error.)

March 21, 2009
7 thanks

Use helpers in your ActionMailer views

It’s very easy to give your mailer access to helpers:

# Let your mailer user the ApplicationHelper methods
class MyMailer < ActionMailer::Base
  helper :application
March 20, 2009 - (>= v2.0.0)
9 thanks

Use the current URL, with changes

You can use the current URL, whatever it is, with changes, as in:

# Create a link to the current page in RSS form
url_for(:overwrite_params => {:format => :rss})

This can be super-helpful because it preserves any GET params (like search parameters)

March 20, 2009
2 thanks

Broadened Flash helper

Building on the below excellent example, you can create something with default options for how long it’s displayed and how long the fade is, and highlight:

def show_flash(options={})
  options = {:fade => 3, :display => 3, :highlight => true}.merge(options)
  html = content_tag(:div, flash.collect{ |key,msg| content_tag(:div, msg, :class => key, :attributes => "style = display: none;") }, :id => 'flash-message')
  html << content_tag(:script, "new Effect.Highlight('flash-message');") if options[:highlight]
  html << content_tag(:script, "$('flash-message').appear();")
  html << content_tag(:script, "setTimeout(\"$('flash-message').fade({duration: #{options[:fade]}});\", #{options[:display]*1000});")
March 20, 2009 - (v2.2.1)
0 thanks
March 20, 2009 - (>= v2.3.2)
1 thank
March 20, 2009 - (>= v2.3.2)
0 thanks

Nested Model Forms

For a good example of nested model forms check out the rails blog.


March 19, 2009
2 thanks


You can put some expression too. For example for I18n (using haml on view):

# some_locale.yml

  contacts: "My contacts"

# index.html.haml

= link_to "#{t "links.contacts"}", :action => 'contacts'
March 18, 2009
2 thanks


Just wanted to point out that you can also use the :format option:

url_for :controller=>'posts', :action=>'index', :format=>:xml

Results in:

March 18, 2009
4 thanks

Better autopad numbers

There is a much better way than to use diwadn’s method if you want to pad numbers with zeros. Here’s my recommended way to do it:

"Number: %010d" % 12345 #=> "Number: 0000012345"

It’s very easy. First we begin our placeholder with “%”, then we specify a zero (0) to signify padding with zeros. If we omitted this zero, the number would be padded with spaces instead. When we have done that, just specify the target length of the string. At last a single “d” is placed to signify that we are inserting a number.

Please see String#% and Kernel#sprintf for more information about how to do this.

Here’s another example of how to do it:

12345.to_s.rjust(10, "0") #=> "0000012345"

See String#rjust for more information.

Any of these methods are a lot better than the method outlined below.

March 17, 2009
0 thanks

Post =form post, NOT the http POST method

Post =forum post, NOT the http POST method

Note: any “Post” on this page has nothing to do with http methods. When I just looked at the collection_select code I was thrown off.

March 12, 2009
1 thank

Comparing Date with Numeric in mixed sort



can accept a Numeric object as other, the reverse is not true:


cannot accept a Date object as other.

So if you are sorting a list containing a mix of dates and numbers, you can get different results depending on the starting order!

a = Date.parse("2008-01-01")
b = Date.parse("2009-10-22")
c = Date.parse("2005-01-04")
d = 0

[a,b,c,d].sort #=> [0, Tue, 04 Jan 2005, Tue, 01 Jan 2008, Thu, 22 Oct 2009]

[b,c,d,a].sort #=> ArgumentError: comparison of Fixnum with Date failed
March 12, 2009
3 thanks
March 12, 2009
11 thanks

User a block to extend your associations

You can use blocks to extend your associations with extra methods.

code sample

has_many :children, :dependent => :destroy do
  def at(time)
    proxy_owner.children.find_with_deleted :all, :conditions => [
      "created_at <= :time AND (deleted_at > :time OR deleted_at IS NULL)", { :time => time }

Model.children.each # do stuff
Model.children.at( 1.week.ago ).each # do old stuff

you must use ‘proxy_owner’ to link back to your model.

March 12, 2009 - (v1_8_6_287 - v1_8_7_72)
1 thank

Autopad Numbers with Zeros (0s)

Here’s a handy code for padding 0s in a string. This is useful when you need to generate numbers for forms, such as invoices or orders. For example, you want to turn an invoice number 12345 to 0012345:

$ irb

>> s = "0000000"
=> "0000000"

>> num = "12345"
=> "12345"

>> s.insert(-(num.to_s.length + 1), num.to_s)[0, s.length - num.to_s.length] if num.to_s.length <= s.length
=> "0012345"
March 12, 2009 - (<= v2.1.0)
0 thanks

Another fix

Another way around this problem, with code that already employs String.first, is to change the ActiveSupport definition as follows (in environment.rb)

module ActiveSupport
  module CoreExtensions 
    module String 
      module Access
        def first(limit = 1)
          chars.to_a[0..(limit - 1)].to_s
March 12, 2009
2 thanks

Incompatible with Ruby 1.8.7

If using Rails < 2.2 with Ruby 1.8.7, calling truncate will result in the following error:

undefined method `length' for #<Enumerable::Enumerator:0xb74f952c>

The workaround (other than upgrading to Rails 2.2 or higher), is to overwrite the truncate method, by inserting the following at the end of environment.rb (or where it will be called on startup):

module ActionView
  module Helpers
    module TextHelper
      def truncate(text, length = 30, truncate_string = "...")
        if text.nil? then return end
        l = length - truncate_string.chars.to_a.size
        (text.chars.to_a.size > length ? text.chars.to_a[0...l].join + truncate_string : text).to_s
March 12, 2009
0 thanks


That didn’t render properly. Use:


instead of

March 12, 2009
1 thank

Selected parameter

batasrki’s note on “selected” parameter is only true for cases which “value_method” returns an int also.

The strictly correct requirement for it to work is:

object.value_method == selected

(“object” is the current object on the iteration over collection)

Since the params hash returns Strings, using it against a value_method with return type of int will never give a valid match (thus no auto-selection is done), i.e., “13” != 13.

When you’ll be using other types of value_method, like String, there’s no need to append “.to_i”, e.g:

options_from_collection_for_select(@posts, "slug", "title", params[:slug])

where “slug” is a String, it will work as expected (current selected post is auto-selected by default).

March 11, 2009
2 thanks

Use table_exists? in initializers

When using ActiveRecords in initializers, eg. for creating small constant data on startup, use table_exists? for those statements.

the initalizers are also called for migrations, etc, and if you are installing a new instance of the project these initializers will fail the migration to create those tables in the first place.

March 11, 2009 - (>= v2.1.0)
2 thanks

Can also be used to conditionally apply filters

For example:

# Skip login filter if the request is for CSS
before_filter :require_login, :unless => lambda { |controller| controller.request.format.css? }

Calling request.format on the controller returns a Mime::Type object, which can then be queried for mime types, other examples:

March 10, 2009 - (>= v2.1.0)
8 thanks

Use lambda to avoid caching of generated query

If you’re using a named_scope that includes a changing variable you need to wrap it in a lambda to avoid the query being cached and thus becoming unaffected by future changes to the variable, example:

named_scope :translated, :conditions => { :locale => I18n.locale }

Will always return the same locale after the first hit even though I18n.locale might change. So do this instead:

named_scope :translated, lambda { { :conditions => { :locale => I18n.locale } } }

Ugly, but at least it’s working as we expect it…

March 10, 2009
1 thank

Image as a submit button

use image_sugmit_tag to use an image as a submit button

March 9, 2009
0 thanks

Memoize will not cache singleton methods

The following does not work:

class PersonType < ActiveRecord::Base
  extend ActiveSupport::Memoizable
  class << self
    def mister
    memoize :mister

I guess one could extend the superclass, Class, with Memoizable support, but that seems Evil.

March 6, 2009
2 thanks

Selected parameter needs an int

In order to pre-select an option, you can pass a fourth parameter. However, that parameter MUST be of integer type, so if you’re trying to set selected from the params hash, you must add to_i at the end of it.

<%= select_tag("job[state_id]", options_from_collection_for_select(State.find(:all), "id", "name", params[:state_id].to_i)) %>
March 5, 2009
7 thanks

String#match will match single token only

>> s = “{{person}} ate {{thing}}”

> “{{person}} ate {{thing}}”

>> r = /{{(.*?)}}/

> {{}}

>> s.match®.captures

> [“person”]

Using String#scan pulls out all tokens you were searching for:

>> s.scan®.flatten

> [“person”, “thing”]

March 5, 2009
1 thank


It’s not:

user = User.find_by_name('Phusion')


user = User.find_by_name('Phusion')
March 4, 2009
10 thanks

Differences between normal or-assign operator

Differences between this method and normal memoization with ||=:

  • memoize works with false/nil values

  • Potential arguments are memoized

Take the following example:

def allowed?
  @allowed ||= begin
    # Big calculation
    puts "Worked"

allowed? # Outputs "Worked"
allowed? # Outputs "Worked" again

Since @allowed is set to false (this is also applicable with nil), the ||= operator will move on the the next statement and will not be short-circuited.

When you use memoize you will not have this problem.

def allowed?
  # Big calculation
  puts "Worked"
memoize :allowed?

allowed? # Outputs "Worked"
allowed? # No output

Now, look at the case where we have parameters:

def random(max=10)
  @random ||= rand(max)

random     # => 4
random     # => 4 -- Yay!
random(20) # => 4 -- Oops!

Better use memoize again!

def random(max=10)
memoize :random

random     # => 6
random     # => 6 -- Yay!
random(20) # => 12 -- Double-Yay!
random     # => 6 -- Head a'splode
March 4, 2009
5 thanks


This defines attr_accessors at a class level instead of instance level.

class Foo
  cattr_accessor :greeting

Foo.greeting = "Hello"

This could be compared to, but is not the same as doing this:

class Bar
  class << self
    attr_accessor :greeting

Bar.greeting = "Hello"

The difference might not be apparent at first, but cattr_accessor will make the accessor inherited to the instances:

Foo.new.greeting #=> "Hello"
Bar.new.greeting # NoMethodError: undefined method `greeting' for #<Bar:0x18e4d78>

This inheritance is also not copy-on-write in case you assumed that:

Foo.greeting  #=> "Hello"
foo1, foo2 = Foo.new, Foo.new

foo1.greeting = "Hi!"

Foo.greeting  #=> "Hi!"
foo2.greeting #=> "Hi!"

This makes it possible to share common state (queues, semaphores, etc.), configuration (max value, etc.) or temporary values through this.