Flowdock

Recent good notes

RSS feed
August 25, 2010 - (>= v2.3.8)
7 thanks

Undocumented :inverse_of option

Support for the :inverse_of option was backported to 2.3.6+.

Here’s the description from the original commit: http://github.com/rails/rails/commit/ccea98389abbf150b886c9f964b1def47f00f237


You can now add an :inverse_of option to has_one, has_many and belongs_to associations. This is best described with an example:

class Man < ActiveRecord::Base
  has_one :face, :inverse_of => :man
end

class Face < ActiveRecord::Base
  belongs_to :man, :inverse_of => :face
end

m = Man.first
f = m.face

Without :inverse_of m and f.man would be different instances of the same object (f.man being pulled from the database again). With these new :inverse_of options m and f.man are the same in memory instance.

Currently :inverse_of supports has_one and has_many (but not the :through variants) associations. It also supplies inverse support for belongs_to associations where the inverse is a has_one and it’s not a polymorphic.

August 25, 2010 - (>= v2.3.8)
3 thanks

Validating presence of parent in child

When creating a parent and its children using nested attributes, you can use the :inverse_of option on the association to correctly set the parent back references:

class Parent < ActiveRecord::Base
  has_many :children, :inverse_of => :parent
  accepts_nested_attributes_for :children
end

class Child < ActiveRecord::Base
  belongs_to :parent
  validates_presence_of :parent
end
August 13, 2010
10 thanks

add_to_base in Rails 3

use

model_instance.errors[:base] << "Msg" 

instead of depracated

model_instance.errors.add_to_base("Msg")

for Rails 3

August 11, 2010
3 thanks

In Rails3 use "unscoped" instead

The with_exclusive_scope examples no longer work in Rails3 because with_exclusive_scope is now a protected method which can and should not be used in a controller. Use the new unscoped method instead:

Article.unscoped

For mor details and examples have a look at: http://github.com/rails/rails/commit/bd1666ad1de88598ed6f04ceffb8488a77be4385.

July 29, 2010
4 thanks

Getting (n..end) reloaded

You can do

array[n..-1]
July 23, 2010
3 thanks

Moved in Rails 3

In Rails 3, this has moved to ActionDispatch::TestProcess

(Which means, if you want to use it in a test, you need to add the following to test_helper.rb:)

include ActionDispatch::TestProcess
July 20, 2010
3 thanks

When scripts don't end in .js

For example, Google Custom Search’s URL is http://www.google.com/jsapi

It’s an ugly hack, but works:

= javascript_include_tag('http://www.google.com/jsapi').sub('.js', '')
July 16, 2010
3 thanks

to set NULL => NO

use :null => false

change_column :my_table, :my_column, :integer, :default => 0, :null => false
July 14, 2010
5 thanks

uniqueness

You can scope uniqueness as well

validates :user_name, :presence => true, :uniqueness => {:scope => :account_id}

# the old way  
validates_uniqueness_of :user_name, :scope => :account_id
June 18, 2010
7 thanks

multiple attributes with the same validations

You can list multiple attributes if they share the same validations

validates :title, :body, :presence => true

sending the attributes as an array will return an error

validates [:title, :body], :presence => true
#=> ArgumentError: Attribute names must be symbols
May 31, 2010
4 thanks

Naming fragment cache

One of the common ways of using fragment caching is to cache content that’s shared across the site (eg. left navigation, menus, widgets etc.) that looks and works the same regardless of the name of the action or controller calling it. In such cases it’s very easy to just use named fragment caching eg.:

<% cache('left_nav') do -%>
  <%= display_left_nav -%>
<% end -%>
April 16, 2010
5 thanks

Require file from the same folder

If you want to require file from the same folder, the simplest way is

require File.expand_path('../file-to-require', __FILE__)

If your file is /lib/book.rb

File.expand_path('../page', '/lib/book.rb') => '/lib/page.rb'
April 3, 2010 - (>= v2.2.1)
3 thanks

Careful with this method.

Despite the name and description, it will actually update any changed fields on the model rather than just the desired attribute.

def update_attribute(name, value)
  send(name.to_s + '=', value)
  save(false)
end

See? Use update_all and pass in the model ID as a condition, instead.

April 1, 2010
3 thanks

Doesn't return nil on empty array when param is given

This does not return nil if the array is empty and n is given.

[].shift(2) # => []

a = []
a.shift(2) # => []
a # => []
March 31, 2010
3 thanks

Interpolating

Note that to interpolate, the sequences must be inside single quotes:

# replace /ll/ with itself
'hello'.gsub(/ll/, '\0') # returns 'hello'
'hello'.gsub(/ll/, "\0") # returns 'he\000o'
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
end

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
end

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)
  controller.stub!(:current_site).and_return(site)
  assigns[:user].should == u
end

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
  # ...
end

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

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

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"
end
class OrdersController < BaseController
  layout :determine_layout, :only => :new
  # index, show, new, create, edit, update, destroy ...
end

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
  # ...
end
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}
end

Article.new.published? # => true

However:

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

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
  ...
end
class Task < ActiveRecord::Base
  belongs_to :person
  delegate :team, :to => :person
end

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

February 19, 2010
8 thanks

Hash#except

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:

http://apidock.com/rails/ActiveSupport/CoreExtensions/Hash/Except/except

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:

Shirt.red.medium.alphabetical.current_scoped_methods
# ==>
{
  :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.