Flowdock

Good notes posted to Ruby on Rails

RSS feed
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.

Example:

<%= form.time_zone_select(:time_zone, ActiveSupport::TimeZone.us_zones) %>
December 16, 2008 - (v1.0.0 - v2.2.1)
11 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 } }
end

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

December 11, 2008
3 thanks

with resources

/products

current_page?(products_path)

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

  def self(dot)down
    drop_table :ex_girlfriend_texts
  end
end

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

class FixDrunkMistake < ActiveRecord::Migration
  def self(dot)up
    CreateExGirlfriendTexts.down
  end

  def self(dot)down
    CreateExGirlfriendTexts.up
  end
end

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 3, 2008 - (v2.2.1)
5 thanks

Method doesn't exists

Don’t confuse it with new_record? in ActiveRecord

November 26, 2008
10 thanks

Types array shorthand

You can have respond_to blocks that look like this:

respond_to do |format|
  format.html
  format.xml
end

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 16, 2008 - (>= v2.1.0)
11 thanks

Application Helper for Fading Flash Messages

A simple helper method for showing the flash message. Includes optional fade in seconds (view needs javascript_include_tag defaults if you desire fade effect):

def show_flash_message(options={})
  html = content_tag(:div, flash.collect{ |key,msg| content_tag(:div, msg, :class => key) }, :id => 'flash-message')
  if options.key?(:fade)
    html << content_tag(:script, "setTimeout(\"new Effect.Fade('flash-message');\",#{options[:fade]*1000})", :type => 'text/javascript')
  end
  html
end

simply call in your views then using:

<%= show_flash_message(:fade => 4) %>
November 12, 2008
6 thanks

Another Example

Do not mistakenly pass class_name as a key/value pair (Hash form). You will get an error including the text ‘class or module needed’. It should look like this:

serialize :some_array, Array

Or, perhaps clearer would be:

serialize(:some_array, Array)

That may seem obvious, but it is common to be in the habit of passing things as a key/value pair.

November 11, 2008
4 thanks

:use_route to force named routes in url_for

If you are using a plugin or library that calls url_for internally, you can force it to use a particular named route with the :use_route key. For instance, calling:

url_for(:controller => 'posts', :action => 'view', :id => post, :use_route => :special_post)

will have the same effect as:

special_post_url(post)

Naturally, this is much more verbose if you’re calling it directly, but can be a lifesaver if url_for is being called inside another method (e.g. will_paginate).

November 7, 2008
3 thanks

Re: Using a Loading Graphic

You probably want to be using :complete, not :loaded, to execute Javascript when an Ajax request has finished. See: http://prototypejs.org/api/ajax/options

November 7, 2008
3 thanks

Common options

“Common options” mentioned here is default PrototypeHelper options documented in link_to_remote

This means you can use :loading, :loaded, :failure, :success, etc in observe_field.

November 7, 2008
3 thanks

Add spacer template

<%= render :partial => “product”, :collection => @products, :spacer_template => “product_ruler” %>

November 6, 2008
4 thanks

current_url

exact url from browser window:

def current_url
  url_for :only_path=>false,:overwrite_params=>{}
end
October 30, 2008
7 thanks

Can be extended but only with a module

Although not documented, belongs_to does support Association Extensions however it doesn’t accept a block like has_many does. So you can’t do this:

class Account < ActiveRecord::Base
  belongs_to :person do
    def do_something_funky
      # Some exciting code
    end
  end
end

but you can do this:

module FunkyExtension
  def do_something_funky
    # Some exciting code
  end
end

class Account < ActiveRecord::Base
  belongs_to :person, :extend => FunkyExtension
end

And then call it like this:

@account = Account.first
@account.person.do_something_funky
October 29, 2008
3 thanks

A work-around for adding confirmation to image_submit_tag

Sometimes you may want to add a confirmation to image submit tags but this function does not allow it. To get over this limitation use a normal submit tag and set the src and type properties (set type to “image”)

Code example

submit_tag “Delete”, :confirm => “Are you sure?”, :src => “/images/trash.png”, :type => “image” %>

October 25, 2008
3 thanks
October 24, 2008
11 thanks

Prompt vs. Select

According to the docs in form_options_helper.rb

:include_blank - set to true or a prompt string if the first option element of the select element is a blank. Useful if there is not a default value required for the select element.

:prompt - set to true or a prompt string. When the select element doesn’t have a value yet, this prepends an option with a generic prompt – “Please select” – or the given prompt string.

The main difference is that if the select already has a value, then :prompt will not show whereas the :include_blank always will.

October 24, 2008
9 thanks

Back it up with a unique index

As mentioned briefly above, as well as using this validation in your model you should ensure the underlying database table also has a unique index to avoid a race condition.

For example:

class User < ActiveRecord::Base
  validates_uniqueness_of :login_name
end

The index can be specified in the migration for the User model using add_index like this:

add_index :users, :login_name, :unique => true

You do a similar thing when using the :scope option:

class Person < ActiveRecord::Base
  validates_uniqueness_of :user_name, :scope => :account_id
end

Should have a migration like this:

add_index :people, [ :account_id, :user_name ], :unique => true

Note that both the attribute being validated (:user_name) and the attribute(s) used in the :scope (:account_id) must be part of the index.

For a clear and concise explanation of the potential for a race condition see Hongli Lai’s blog.

October 23, 2008
8 thanks

Customizing attribute names in error messages

By default, the error messages translate the names of the attributes through String#humanize. The way to to change that is to override the ActiveRecord::Base.human_attribute_name method.

For example, if you want to name a column in your database as :www_url and you want to say “Website” instead of “Www url” in the error message, you can put this into your model:

class Person < ActiveRecord::Base
  def self.human_attribute_name(attribute_key_name)
    if attribute_key_name.to_sym == :www_url
      "Website"
    else
      super
    end
  end
end

Currently this seems to be the cleanest and easiest way. Unfortunately, human_attribute_name is deprecated and may stop working in a future release of Rails.

October 22, 2008
10 thanks

Gotcha when defining :finder_sql or :counter_sql

When setting custom SQL statements in the :finder_sql or :counter_sql queries, if you need to inject attributes from the current object, such as the ID, make sure to disable string interpolation of the statement by using single quotes or %q().

Example:

has_many :relationships, :class_name => 'Relationship', :finder_sql => %q(
  SELECT DISTINCT relationships.*
  FROM relationships
  WHERE contact_id = #{id}
)

Surrounding this SQL with double-quotes or %Q() will expand #{id} too early, resulting in a warning about Object#id being deprecated and general brokenness.

October 21, 2008
5 thanks

Using a Loading Graphic

If you want to make a little loading graphic, typically you use an animated gif (like a little spinner or something). Both link_to_remote and remote_form_for allow you to easily do this by using the :loaded and :loading triggers to call javascript.

For example:

<% remote_form_for @survey, :loading => "$('loading').show();", :loaded => "$('loading').hide();" do |f| %>
  <%= submit_tag ' Save' %>
  <%= image_tag "indicator_circle.gif", :style => 'display: none;', :id => 'loading' %>
<% end %>

The ‘loading’ parameter used for the ‘$’ prototype selector is the id of the animated gif. It starts out hidden, and is toggled by the loading/loaded triggers.

October 20, 2008
3 thanks

number_to_euro

in small cells:

12-->
12def number_to_euro(amount)
  number_to_currency(amount,:unit=>'').gsub(' ',nbsp)
end
October 15, 2008
29 thanks

List of status codes and their symbols

Note that the :status option accepts not only an HTTP status code (such as 500), but also a symbol representing that code (such as :created), if that makes more sense to you. Here’s a list of which symbols map to which numbers (derived from ActionController::StatusCodes::SYMBOL_TO_STATUS_CODE):

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

Implemented in database adapters

These methods are not implemented in the abstract classes. Instead, all database adapters implement these separately, if the feature is supported.

October 9, 2008 - (v1.2.0 - v2.1.0)
12 thanks

Rendering nothing

If your controller action does not explicitly call render, Rails will, by default, attempt to locate and render the template corresponding to the action. It’s not uncommon, for example with Ajax calls, to want to render nothing. This will circumvent the default rendering and prevent errors on missing templates. To render nothing simply do the following:

render :nothing => true

Its important to note that this isn’t the same as returning no HTTP response. In fact, this results in an HTTP response with a status code of 200 OK being sent back with a blank content body. Why does it matter? Well, you can still test your controller by asserting that a :success response was returned.

October 8, 2008
3 thanks

Seriously! Do not forget the brackets

thank you source jamesandre.ws

the form_for([:admin, @user]) must have the [] brackets to avoid errors like “Only get requests are allowed”

<% form_for([:admin, @user]) do |f| %>
<%= render :partial => 'form' %>
<%= submit_tag "Create" %>
<% end %>