Recent good notes

RSS feed
January 24, 2009
8 thanks

How to test different responses of respond_to

You can shorten this:

@request.env['HTTP_ACCEPT'] = "application/rss"

To this:

@request.accept = "application/rss"

Also, if you send more than one Mime type, it will render the first one:

@request.accept = "text/javascript, text/html" #=> renders JS
@request.accept = "text/html, text/javascript" #=> renders HTML
January 22, 2009
7 thanks

Using fields_for with has_many associations

If you want to edit each element of an array of objects (such as with a has_many type association), you will need to include “[]” in your field parameter name, like so:

<% fields_for "object[]" do |subfield| -%>
 <% end -%>

Because you named the field parameter “object[]”, fields_for will assume you have an instance variable @object to use for the fields’ values. To fake this, you can do something like:

<% objects.each do |@object| -%>
  <% fields_for "object[]" do |subfield| -%>
  <% end -%>
<% end -%>

If that looks like sacrilegious Rails code to you, then you could consider:

<% objects.each do |object| -%>
  <% fields_for "object[]", object do |subfield| -%>
  <% end -%>
<% end -%>

In either case, params[:object] will be a hash where the ID of each object (determined via ActiveRecord::Base#to_param ) is associated with a hash of its new values:

params = { 'object' => { '123' => { 'field' => 'newval' }, '159' => { 'field' => 'newval' } } }
January 20, 2009 - (>= v2.2.1)
5 thanks

Reloading memoized values

Memoize is used to cache the result of a method. It’s roughly equivalent of having:

def memoized_method(*args)
  @result[args] ||= (
    # do calculation here

However, the result is cached so that it’s not calculated for every request.

To recalculate cached value use either



January 20, 2009
5 thanks

Javascript encoding DOES work!

grosser assertion is false :

mail_to('xxx@xxx.com', nil, :encode => :javascript)
# => "<script type=\"text/javascript\">eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%78%78%78%40%78%78%78%2e%63%6f%6d%22%3e%78%78%78%40%78%78%78%2e%63%6f%6d%3c%2f%61%3e%27%29%3b'))</script>"

Use “nil” as the second parameter to tell mail_to that you want to use the first parameter for both text and email link

January 16, 2009 - (>= v2.2.1)
4 thanks

Remember to mixin the ActiveSupport::Memoizable module

To use memoize in your model you need to extend the model class with the module, like this:

class Person < ActiveRecord::Base
  # Mixin the module
  extend ActiveSupport::Memoizable

  def expensive_method
    # do something that is worth remembering
  memoize :expensive_method

If you use memoizable in most of your models you could consider mixing the module into all ActiveRecord models by doing this in an initializer:

January 16, 2009
7 thanks


Code example

# => true
January 15, 2009
4 thanks

Convert String to Class in Rails

ncancelliere gave us a very useful tip below, and I just want to make an addendum for it:

If you are using Rails, there is a CoreExtension for this called String#constantize.

"Foo::BarKeeper".constantize #=> Foo::BarKeeper

You can use it with String#camelize if you have to convert the name too

"foo/bar_keeper".camelize             #=> "Foo::BarKeeper"
"foo/bar_keeper".camelize.constantize #=> Foo::BarKeeper

Don’t forget to rescue NameError in case there was an invalid class name. :-)

January 14, 2009
6 thanks

File open permissions

Usage: File.open path, flags, [permissions]

Flags (bitmasks)







Read and write

If the file exists:







If the file doesn’t exist:



Flags (strings)










File.open path, File::RDONLY
File.open path, 'w'
File.open path, File::WRONLY|File::TRUNC|File::CREAT
File.open path, File::WRONLY|File::TRUNC|File::CREAT, '0666'
January 13, 2009
6 thanks

Universal partial

polymorphic_url is very useful if you want to create an universal partial that works for more than 1 type of object passed to it.

For example in you sidebar you might have a _sidebar.html.erb partial that’s supposed to display links to “Edit” and “Delete” actions. You can write it in such a way that it can be reused for different types of objects (in the example below we pass either a Post or a Note).


<%= render :partial => 'shared/sidebar', :locals => { :obj => Post.new -%>


<%= render :partial => 'shared/sidebar', :locals => { :obj => Note.new -%>


<%= link_to "Edit", polymorhpic_url(obj, :action => 'edit') -%>
<%= link_to "Delete", polymorphic_url(obj), :method => :delete -%>
January 9, 2009
3 thanks

Adding params to generated url

Whenever you want to append custom parameters to a to be generated url it might be necessary to stop url_for from escaping.

url_for(:action => 'some_action', :custom1 => 'some_value', :custom2 => 'some_value', :escape => false)

If the escape => false option is not passed the generated url contains &amp; instead of the correct &-sign.

January 8, 2009
10 thanks

Refactoring excessive code for selects

@garg: It is not recommended to have excessive code in the views. You should refactor your code a bit.

<%= f.select(:manufacturer_id, Manufacturer.find(:all).collect {|u| [u.name, u.id]}, :prompt => 'Select') %>

could be changed to this:

# in app/helpers/manufacturer_helper.rb
def manufacturers_for_select
  Manufacturer.all.collect { |m| [m.name, m.id] }

# in the view
<%= f.select(:manufacturer_id, manufacturers_for_select, :prompt => 'Select') %>

I would look into collection_select though:

<%= f.collection_select(:manufacturer_id, Manufacturer.all, :id, :name, :prompt => 'Select') %>

It’s much more clean and you don’t have to define a helper for it to be readable (altough it’s still quite long).

If you have to do this often, you should define a FormBuilder extension, so you get methods like f.manufacturer_select:

<%= f.manufacturer_select(:manufacturer_id, Manufacturer.all) %>

IMO, most projects should have a custom form builder anyway, so the addition would be very small. This is my personal opinion, so you don’t have to listen to it. :-)

January 8, 2009
5 thanks

Watch out for syntax errors

Watch out when you are using returning with hashes. If you would write code like

def foo(bars)
  returning {} do |map|
    bars.each { |bar| map[bar.first] = bar }

you will get a syntax error since it looks like you tried to supply two blocks! Instead you should write it with parenthesis around the hash:

def foo(bars)
  returning({}) do |map|
    bars.each { |bar| map[bar.first] = bar }
January 6, 2009
5 thanks

Default allowed tags and attributes

I found it a bit hard to find the default tags and attributes in the docs.

As of Rails 2.2.2 they are:


del, dd, h3, address, big, sub, tt, a, ul, h4, cite, dfn, h5, small, kbd, code,
b, ins, img, h6, sup, pre, strong, blockquote, acronym, dt, br, p, div, samp,
li, ol, var, em, h1, i, abbr, h2, span, hr


name, href, cite, class, title, src, xml:lang, height, datetime, alt, abbr, width

Getting the latest list

You can query for this list yourself with the following code on the console:

>> puts helper.sanitized_allowed_tags.to_a * ", "
... will output tag list ...
>> puts helper.sanitized_allowed_attributes.to_a * ", "
... will output attribute list ...

The same principal can probably be applied to sanitize_css.

January 2, 2009 - (v2.0.0 - v2.2.1)
3 thanks

What to use instead

For versions 2.0+, use ActiveRecord::Base::sanitize_sql_array

January 2, 2009
3 thanks

current_action? and current_controller?

I use them in link_unless_current_controller helper.

def current_action?(options)
  url_string = CGI.escapeHTML(url_for(options))
  params = ActionController::Routing::Routes.recognize_path(url_string, :method => :get)
  params[:controller] == @controller.controller_name && params[:action] == @controller.action_name

def current_controller?(options)
  url_string = CGI.escapeHTML(url_for(options))
  params = ActionController::Routing::Routes.recognize_path(url_string, :method => :get)
  params[:controller] == @controller.controller_name
December 24, 2008 - (>= v2.2.1)
5 thanks

uninitialized constant ActionView::Base::CompiledTemplates::TimeZone

If you get this error, you need to use ActiveSupport::TimeZone.us_zones instead of TimeZone.us_zones.


<%= form.time_zone_select(:time_zone, ActiveSupport::TimeZone.us_zones) %>
December 16, 2008 - (v1.0.0 - v2.2.1)
13 thanks

Force initial value

If you want to force an initial value for your text_field which is normally based on your object attribute value, you can use :

text_field :ecard, :sender, :value => 'contact@host.com'
December 12, 2008
7 thanks

acts_as_state_machine named scopes

If you are using the acts_as_state_machine plugin, this will generate all named scopes for your various states.

Place it after the acts_as_state_machine and state declarations.

class Task < ActiveRecord::Base
  acts_as_state_machine :initial => :waiting
  state :waiting
  state :running
  state :finished    

  states.each { |s| named_scope s, :conditions => { :state => s.to_s } }

Then doing a Task.waiting will return the corresponding tasks.

December 11, 2008
3 thanks

with resources



# => true
December 11, 2008 - (>= v1.0.0)
5 thanks

Calling migrations within migrations

It’s very occasionally a wise strategy to call migrations from within other migrations. This is typically done when you are adding a migration that deletes a now-obsolete table.

Let’s say one night when you were drunk or otherwise not thinking straight you did something like this:

class CreateExGirlfriendTexts < ActiveRecord::Migration
  def self(dot)up
    create_table :ex_girlfriend_texts { |t| ... }

  def self(dot)down
    drop_table :ex_girlfriend_texts

Oops! You could add this for your “undo” migration the next morning:

class FixDrunkMistake < ActiveRecord::Migration
  def self(dot)up

  def self(dot)down

Now, in the event you decide you really did like that table, you can always get it back easily. Keep in mind this will be made more complicated if your table is modified over multiple transactions.

December 11, 2008
6 thanks

Accessing aggregate methods with :group

You can access aggregate methods (such as SUM, COUNT, etc.) when using a JOIN and GROUP BY query by simply naming the aggregate columns and calling them as methods on the returned objects:

hits_by_page = WebpageHit.all({
  :select => "webpages.*, COUNT(webpage_hit.id) AS view_count",
  :joins => :webpage,
  :group => "webpages.id"
homepage_hits = hits_by_page[homepage.id].view_count

The view_count method is added to the Webpage model by this call. Note, however, that this method returns a string, and is not typecasted by Rails.

December 6, 2008
5 thanks

Array expansion in blocks

The syntax can be improved as changing the second parameter of the block (values) and using an array of two variables instead, which will be used by Ruby as the key and value of “array”.

array = [['A', 'a'], ['B', 'b'], ['C', 'c']]

hash = array.inject({}) do |memo, (key, value)|
  memo[key] = value

# => {'A' => 'a', 'B' => 'b', 'C' => 'c'}
December 3, 2008 - (v2.2.1)
5 thanks

Method doesn't exists

Don’t confuse it with new_record? in ActiveRecord

December 2, 2008
5 thanks

From the official docs

enum.inject(initial) {| memo, obj | block } => obj enum.inject {| memo, obj | block } => obj

Combines the elements of enum by applying the block to an accumulator value (memo) and each element in turn. At each step, memo is set to the value returned by the block. The first form lets you supply an initial value for memo. The second form uses the first element of the collection as a the initial value (and skips that element while iterating).

# Sum some numbers
(5..10).inject {|sum, n| sum + n }              #=> 45
# Multiply some numbers
(5..10).inject(1) {|product, n| product * n }   #=> 151200

# find the longest word
longest = %w{ cat sheep bear }.inject do |memo,word|
   memo.length > word.length ? memo : word
longest                                         #=> "sheep"

# find the length of the longest word
longest = %w{ cat sheep bear }.inject(0) do |memo,word|
   memo >= word.length ? memo : word.length
longest                                         #=> 5


November 26, 2008
10 thanks

Types array shorthand

You can have respond_to blocks that look like this:

respond_to do |format|

Here each individual format doesn’t receive a block and so Rails automatically tries to render the appropriate view for the mime type (e.g. action.html.erb, action.xml.erb or as a last resort action.erb)

You can do exactly the same thing by passing an array of Mime types to respond_to like this:

respond_to(:html, :xml)
November 24, 2008 - (<= v2.2.1)
7 thanks

Full List of Supported Formats

With a sample date of December 25th, 2008, at 14:35:05:

:db           # => 2008-12-25 14:35:05
:number       # => 20081225143505
:time         # => 14:35
:short        # => 25 Dec 14:35
:long         # => December 25, 2008 14:35
:long_ordinal # => December 25th, 2008 14:35
:rfc822       # => Thu, 25 Dec 2008 14:35:05 +0000
November 19, 2008
9 thanks

Formatting options

Readable strftime

%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 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 name %% - Literal “%’’ character t = Time.now t.strftime(“Printed on %m/%d/%Y”) #=> “Printed on 04/09/2003” t.strftime(“at %I:%M%p”) #=> “at 08:56AM”

November 18, 2008
9 thanks

Pop for last, Shift for first

If you want to pop the first element instead of the last one, use shift .