Recent good notes
RSS feedCalling 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.
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.
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 memo end hash # => {'A' => 'a', 'B' => 'b', 'C' => 'c'}
Method doesn't exists
Don’t confuse it with new_record? in ActiveRecord
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 end 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 end longest #=> 5
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)
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
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”
Pop for last, Shift for first
If you want to pop the first element instead of the last one, use shift .
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) %>
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.
: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).
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
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.
Add spacer template
<%= render :partial => “product”, :collection => @products, :spacer_template => “product_ruler” %>
current_url
exact url from browser window:
def current_url url_for :only_path=>false,:overwrite_params=>{} end
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
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” %>
Also for numeric
1.humanize == “1″ 1000000.humanize == “1.000.000″ 1000.12345.humanize == “1.000,12″
http://pragmatig.wordpress.com/2008/10/25/numbers-for-humans-humanize-for-numeric/
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.
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.
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.
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.
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.
Opening a link in a new window
Use “_blank”, not “_new” to open a link in a new window.
link_to "External link", "http://foo.bar", :target => "_blank" # => <a href="http://foo.bar" target="_blank">External link</a>
number_to_euro
in small cells:
12 € --> 12 € def number_to_euro(amount) number_to_currency(amount,:unit=>'€').gsub(' ',nbsp) end
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
Ruby's exception hierarchy
Ruby’s exception hierarchy, according to http://blog.nicksieger.com/articles/2006/09/06/rubys-exception-hierarchy:
NoMemoryError ScriptError LoadError NotImplementedError SyntaxError SignalException Interrupt StandardError ArgumentError IOError EOFError IndexError LocalJumpError NameError NoMethodError RangeError FloatDomainError RegexpError RuntimeError SecurityError SystemCallError SystemStackError ThreadError TypeError ZeroDivisionError SystemExit fatal
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.
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.