Recent good notes

RSS feed
March 13, 2010
3 thanks

Can be used with has_many associations

You can also use this to validate that a has_many association has a specified number of records on the other end:

has_many :members

validates_length_of :members, :minimum => 1
March 12, 2010
3 thanks

Complete Formatting Codes

NOTE: Some of these seem only to work for DateTime (e.g. %L, %N)

%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

%C - Century (20 in 2009)

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

%D - Date (%m/%d/%y)

%e - Day of the month, blank-padded ( 1..31)

%F - Equivalent to %Y-%m-%d (the ISO 8601 date format)

%h - Equivalent to %b

%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)

%k - hour, 24-hour clock, blank-padded ( 0..23)

%l - hour, 12-hour clock, blank-padded ( 0..12)

%L - Millisecond of the second (000..999)

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

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

%n - Newline (n)

%N - Fractional seconds digits, default is 9 digits (nanosecond)

  • %3N millisecond (3 digits)

  • %6N microsecond (6 digits)

  • %9N nanosecond (9 digits)

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

%P - Meridian indicator (“am” or “pm”)

%r - time, 12-hour (same as %I:%M:%S %p)

%R - time, 24-hour (%H:%M)

%s - Number of seconds since 1970-01-01 00:00:00 UTC.

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

%t - Tab character (t)

%T - time, 24-hour (%H:%M:%S)

%u - Day of the week as a decimal, Monday being 1. (1..7)

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

%v - VMS date (%e-%b-%Y)

%V - Week number of year according to ISO 8601 (01..53)

%W - Week number of the current year, starting with the first Monday as the first day 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 as hour offset from UTC (e.g. +0900)

%Z - Time zone name

%% - Literal “%” character

t = Time.now                        #=> 2007-11-19 08:37:48 -0600
t.strftime("Printed on %m/%d/%Y")   #=> "Printed on 11/19/2007"
t.strftime("at %I:%M%p")            #=> "at 08:37AM"
March 11, 2010
3 thanks

Available statuses

All the available statuses (extracted from SYMBOL_TO_STATUS_CODE hash) in a slightly more readable form:

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

stub_chain is very useful when testing controller code

or any other chained method call type that you’d like to stub, example:

in your controller:

def new
  @user = current_site.users.new

in your spec:

it "#new should assign a @user" do 
  u = mock("User")
  controller.stub_chain(:current_site, :users, :new).and_return(u)
  assigns[:user].should == u

whereas before you had to stub each chained method call separately:

it "#new should assign a @user" do 
  u = mock("User")
  users = mock("Users collection", :new => u)
  site = mock("Site", :users => users)
  assigns[:user].should == u

Please note that stub_chain was added to RSpec in version 1.2.6

March 4, 2010
3 thanks

Re: Caveat when using dynamic layouts

Since there’s no way to edit posts on here, I need to correct myself and say that what I posted before doesn’t work, since you can’t specify layout multiple times:

class OrdersController < BaseController
  layout :determine_layout, :only => :new
  layout "public", :except => :new
  # ...

So don’t do that. The only way to ensure that the other actions get the default theme is to drop :only/:except and do the conditions yourself:

class OrdersController < BaseController
  layout :determine_layout

  def determine_layout
    %w(new).include?(action_name) ? "some_layout" : "public"

All this to say, beware of :only/:except – they aren’t as useful as you think they are.

March 3, 2010
3 thanks

Deprecated in 1.9.x!

Use FileUtils::copy instead. It is also in 1.8.x, FileUtils, so call that one instead.

March 3, 2010 - (>= v1_8_6_287)
4 thanks

makedirs(path) to create file path

mkdir will only create a single directory on an existing path. If you want to create a full path, like the `mkdir -p /full/path` command, use the makedirs method.

1.8: File.makedirs(path) 1.9: FileUtils.makedirs(path)

February 27, 2010
4 thanks

Caveat when using dynamic layouts

Worth noting that if you have a controller which inherits from another controller which has a layout, and in this child controller you’re determining the layout at runtime using a method for specific actions, the other actions you are excluding will not inherit the layout from the parent controller.

For example, if you’ve got this

class BaseController < ApplicationController
  layout "public"
class OrdersController < BaseController
  layout :determine_layout, :only => :new
  # index, show, new, create, edit, update, destroy ...

then OrdersController#index, #show, and #edit won’t get the “public” layout – in fact they won’t get a layout at all. So you’ll need to do this instead:

class OrdersController < BaseController
  layout :determine_layout, :only => :new
  layout "public", :except => :new
  # ...
February 26, 2010
3 thanks

default_scope on create

If you specify :conditions in your default_scope in form of a Hash, they will also be applied as default values for newly created objects. Example:

class Article
  default_scope :conditions => {:published => true}

Article.new.published? # => true


class Article
  default_scope :conditions => 'published = 1'

Article.new.published? # => false
February 23, 2010
3 thanks

Easy workaround for missing :through option

Note that belongs_to does not support :through option like has_many (although IMHO it would make sense in some cases), but you can easily simulate it with delegate.

For example:

class Person < ActiveRecord::Base
  belongs_to :team
class Task < ActiveRecord::Base
  belongs_to :person
  delegate :team, :to => :person

There is of course more ways to do it, but this seems to be the easiest to me.

February 19, 2010
8 thanks


Note that the ActiveSupport library provides the except and except! methods, which return the Hash minus the given keys. So you don’t need to write your own wrapper if you happen to be using Rails or ActiveSupport as a stand-alone library:


February 16, 2010 - (>= v2.1.0)
3 thanks

Extract the aggregated scoping options

If you want to get the aggregated scoping options of a chain of named scopes use ActiveRecord::Base.current_scoped_methods

It works in the fashion of:

# ==>
  :create => {}, 
  :find => {
    :conditions => {:color => 'red', :size => 'medium'}, 
    :order => 'shirts.name ASC'
February 11, 2010
4 thanks

reload equivalent for models

The reset_column_information method provides a similar function for the model itself. Most useful during migrations.

February 5, 2010
3 thanks

Rmoving preceding 0's

In most *nix system, adding a - after the % will remove preceding 0s.

So %-d for a single digit day, or %-I for a single digit hour, etc.

January 30, 2010
3 thanks

Paying attention to query parameters

Standard action caching ignores query parameters, which means you’d get the same results for a URL with and without query parameters if it was action cached. You can make it pay attention to them by using a custom cache path like so:

caches_action :my_action, :cache_path => Proc.new { |c| c.params }

Or, maybe you want some of the query parameters, but not all to factor into different versions of that action’s cache:

:cache_path => Proc.new { |c| c.params.delete_if { |k,v| k.starts_with?('utm_') } }

Beware of things like pagination if you use expires_in to expire the cache, as pages could get out of sync.

January 27, 2010
3 thanks
January 21, 2010
3 thanks

W3CDTF Format

Here is the formatted string for the W3CDTF datetime format (http://www.w3.org/TR/NOTE-datetime). It has a semicolon in the timezone part, therefore you cannot use ‘%z’:

Time::DATE_FORMATS[:w3cdtf] = lambda { |time| time.strftime("%Y-%m-%dT%H:%M:%S#{time.formatted_offset}") }
January 20, 2010
4 thanks

Using html text instead of default response

If you have a string containing html and want to assert_select against it, as the doc states you have to pass in an element (HTML::Node) as the first argument. You can do something like this:

doc = HTML::Document.new('<p><span>example</span></p>')
assert_select doc.root, 'span'
January 20, 2010
3 thanks
January 16, 2010 - (>= v2.2.1)
8 thanks

Pretty way to test for current environment

You can check your current Rails environment using nice methods such as:

January 15, 2010
3 thanks

Use this in controllers

Sometimes you’re gonna need this in controllers. Just put this in the controller:

include ActionView::Helpers::NumberHelper
January 6, 2010
6 thanks

Doesn't return nil if the object you try from isn't nil.

Note that this doesn’t prevent a NoMethodError if you attempt to call a method that doesn’t exist on a valid object.

a = Article.new

a.try(:author) #=> #<Author ...>

nil.try(:doesnt_exist) #=> nil

a.try(:doesnt_exist) #=> NoMethodError: undefined method `doesnt_exist' for #<Article:0x106c7d5d8>

This is on Ruby 1.8.7 patchlevel 174

December 28, 2009
4 thanks

Attribute names are Strings, not Symbols

Another possible gotcha – the returned hash keys are of type String, not Symbol:

user.attributes["login"] # => "joe"
user.attributes[:login] # => nil
December 18, 2009
4 thanks

Version Ranges

To specify a version range, use array syntax like this:

config.gem 'paperclip', :version => ['>=', '< 3.0']

The example will, of course, match any version or newer up until (not including) 3.0 or later.

November 23, 2009
3 thanks

Make directory if not exists

If the directory already exists, mkdir raises exception. To prevent this:

Dir.mkdir(dir) unless File.exists?(dir)
November 18, 2009 - (>= v1_8_6_287)
4 thanks



class Klass
  def set(string)
    var_name = "@#{string}"  # the '@' is required
    self.instance_variable_set(var_name, 'bar')
  def puts_foo
    puts @foo
k = Klass.new
k.puts_foo  # nil
k.puts_foo  # 'bar'
November 12, 2009
8 thanks

Use hash form of updates argument

The examples are unfortunate, because passing a string as the updates argument is an invitation to SQL injection attacks. Don’t do this!


Use the hash form of updates instead:

Billing.update_all(:author => author)

Then the SQL adapter will quote everything safely. Even if [you think] you’re sure there’s no quoting issue, it’s better to cultivate the habit of using the hash form just in case you missed something.

Same with conditions–use the hash or array form rather than a string if there are variables involved.

BTW, to do this and give options, of course you’ll need to put the braces back in:

Billing.update_all({:author => author},
                   ['title like ?', "#{prefix}%"])
November 5, 2009
9 thanks

define_method with parameters

Just to be clear, you can do this:

define_method(:my_method) do |foo, bar| # or even |*args|
  # do something

This means same as:

def my_method(foo, bar)
  # do something

If you want to define method with parameters that have default values, you need to get a bit more creative and do something like this:

define_method(:my_method) do |foo, bar|
  bar ||= {}
  # do something
November 5, 2009 - (>= v2.1.0)
7 thanks

Named scope better than conditions

In modern versions of Rails, in most cases a named_scope is a better alternative to using :conditions on your has_many relations. Compare:

class User
  has_many :published_posts, :conditions => {:published => true}


class Post
  named_scope :published, :conditions => {:published => true}
class User
  has_many :posts

It’s better because the Post’s logic (“am I published?”) should not be coupled within User class. This makes it easier to refactor: e.g. if you wanted to refactor the boolean :published field into a :status field with more available values, you would not have to modify User class. Having to modify User when you refactor some implementation detail of Post class is clearly a code smell.

This also applies to :order, :group, :having and similar options.

October 30, 2009
7 thanks

How FormBuilders work

What, you were expecting documentation? :)

An excellent survey of how FormBuilders work is here: