Recent notes
RSS feed
Overriding the default div class="fieldWithErrors"
By default fields that are invalid are wrapped in:
<div class="fieldWithErrors"> <input type="text" name="blah"> </div>
To override and wrap in spans instead of divs place the following in your environment.rb:
ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| "<span class=\"fieldWithErrors\">#{html_tag}</span>" }
or to not use wrapping at all:
ActionView::Base.field_error_proc = Proc.new { |html_tag, instance| "#{html_tag}" }

RE: Using validates_format_of to validate URIs
Further to Olly’s note below, you can also specify the protocol to further limit the valid uri’s, else things like ‘ftp ://someurl.com’ (there’s only a space in there to get it to display on here) would be valid.
validates_format_of :uri, :with => URI.regexp(['http'])

Validations
update_attribute will not perform validations checks when the Validation module is included.
If you want to perform validations when updating, use update_attributes instead.

Examples
@articles = cache(‘articles’) do
Articles.latest
end
Or:
@articles = cache([‘articles’, user.id], :expires_in => 15.minutes)
# Advanced Rails Recipies says: "expires_in option works only with memcached store" Articles.latest
end
Also if you’d like to have short ‘cache’ call in your model you can have it - add the following method to the model:
def cache(key, options = {})
ActionController::Base.cache_store.fetch(key, options) { yield }
end


New way of calling partials on collections
You can directly call a partial on a collection of objects like this:
<%= render :partial => @users %>
This will call the partial _user.html.erb and populate a local variable ‘user’ within the partial. Then you can display the user partial in this way:
_user.html.erb:
Name: <%= user.name %> <br /> Email: <%= user.email %> <br />
The above render statement is equivalent to this code:
<% for user in @users %> <%= render :partial => 'user', :locals => { :user => user } %> <% end %>

finder_sql
If you are using the finder_sql option, it is important to use single quotes if need to interpolate variables, such as the id of the record. Otherwise you will get the object_id of the class.

Using validates_format_of to validate URIs
You can use the validates_format_of with the regular expression in the URI library ensure valid URIs.
Example
require 'uri' class Feed < ActiveRecord::Base validates_format_of :uri, :with => URI.regexp end

X-Sendfile equivalent for Nginx
Nginx supports a similar http header to X-Sendfile called X-Accel-Redirect.
Set the X_SENDFILE_HEADER constant somewhere (eg in your environment.rb) file:
ActionController::Streaming::X_SENDFILE_HEADER = 'X-Accel-Redirect'
Then you can use x_sendfile => true as usual.
More here: http://wiki.codemongers.com/NginxXSendfile

Avoiding duplicate results when you do a join
When you use the :joins option you can get multiple instances of the same item. For example, say you want every User who owns one or more Lists. With the code below, if a user owns 5 lists, the User will show up five times in the results:
users = User.find(:all, :conditions => ['users.id = lists.user_id'], :joins => [:lists], :order => 'users.username')
You can cause each found user to appear only once by using the :select option with “DISTINCT”:
users = User.find(:all, :conditions => ['users.id = lists.user_id'], :joins => [:lists], :select => 'DISTINCT users.*' :order => 'users.username')

Function to Determine Layout
Sometimes its nice to have different layouts choosen automagicly:
class ApplicationController < ActionController::Base layout :determine_layout def determine_layout if is_admin? "admin" else "application" end ... end

around_filter - working example
More detailed, working example of usage:
class HomeController < ApplicationController around_filter :action1, :action2 around_filter do |controller, action| logger.info "code block before action" action.call logger.info "code block after action" end def index logger.info "ACTION" end private # filters should not be available for external URL def action1 logger.info "ACTION1 before yield" yield "ACTION1" logger.info "ACTION1 after yield" end def action2 logger.info "ACTION2 before yield" yield "ACTION2" logger.info "ACTION2 after yield" end end
Results (in log file):
ACTION1 before yield ACTION2 before yield code block before action ACTION Rendering home/index code block after action ACTION2 after yield ACTION1 after yield

not loaded if any gems missing at startup
similar to http://rails-doc.org/rails/Rails/Initializer/load_application_initializers#95-initializers
observers and custom initializers aren’t loaded if any gems are missing -
current behaviour isn’t great - as it’s not intuitive - and you get no warning.
here’s a lighthouse ticket i created a while ago about this.

RE: Using counters with collections
Note that as of Rails 2.1, it’s currently not possible to override the internal counter variable you get when using collections via passing it in through :locals.
This is a useful feature when you have a collection of items rendered but then wish to add another one - most likely via an AJAX request.
I’ve been informed it’s back in Edge, so hopefully it’ll re-appear again in Rails 2.2.

RE: Cross browser issues
In response to subblue’s note below, you should bear in mind that there may be circumstances where you want an AJAX request to enter the format.html block and not format.js.
When you’re returning HTML content, for example.
By using jQuery’s .ajaxSetup method in such an indiscriminate way (applying it by default to all ajax requests), you make it harder to keep track of what’s returning what.
A better alternative is to use it as a stored function;
function set_content_type_to_javascript(xhr) { xhr.setRequestHeader("Accept", "text/javascript"); }
and call this from within your .ajax requests when required;
$.ajax({ type: "GET", url: "/some/url", dataType: "script", beforeSend: function(xhr) { set_content_type_to_javascript(xhr) }, …etc… });

Multipart form
Don’t forget to add :multipart => true if you have file upload in your form.
<% form_for "user", :html => { :multipart => true } do |f| %>

Example: find by associated table
Say you have tables “authors” and “books” and they have a one-to-many association.
You want authors who have written books with “cooking” in the title…
cookbook_authors = Author.find(:all, :conditions => ['books.title LIKE ?', '%cooking%'], :joins => [:books], :order => 'authors.last_name' )
For many-to-many associations, it’s a similar pattern. Say you have tables “people” and “organizations” with a many-to-many association through the join table “organization_memberships”.
Ski Club members whose first name starts with “a”…
ski_club_members = Person.find(:all, :conditions => ['first_name LIKE ? AND organizations.name = ?', 'a%', 'Ski Club'], :joins => [:organizations], :order => 'people.last_name' )

How to handle the MultiparameterAssignmentErrors exception
If you expect to get this error, do this in your controller:
def create @event = Event.new @event.attributes = params[:event] @event.save! rescue ActiveRecord::MultiparameterAssignmentErrors => e e.errors.each do |error| @event.errors.add(error.attribute, ActiveRecord::Errors.default_error_messages[:invalid]) end rescue ActiveRecord::RecordInvalid # event is invalid ensure if @event.errors.empty? and not @event.new_record? redirect_to event_path(@event) else render :action => :new end end
If attribute assignment gives the MultiparameterAssignmentErrors exception we handle it by adding ‘invalid’ errors to the attributes involved. We also rescue the RecordInvalid exception and handle all the redirecting/rendering in the ensure block.

Detailed messages for a nested model
Detailed messages for a nested model
<%@address = @order.address%> <%=error_messages_for :address%>

You can turn off dirty objects
If you expierence problems with dirty objects you can turn it off:
ActiveRecord::Base.partial_updates = false

Moved to plugin "auto_complete"
This helper was moved to plugin “auto_complete” - http://svn.rubyonrails.org/rails/plugins/auto_complete/

"created_at" instead "created_on"
In examples( at least for version 2.1) should be Person.find(:last, :order => “created_at DESC”, :offset => 5)
instead of: Person.find(:last, :order => “created_on DESC”, :offset => 5)
the same with 2nd auto-generated table: in my rails 2.1 it is updated_at not _on

Cross browser issues
We use jQuery as our Javascript library of choice, but have to use a work around for full cross-browser support.
In jQuery you need to set the AJAX request headers as:
$.ajaxSetup({
beforeSend: function(xhr) {xhr.setRequestHeader(“Accept”, “text/javascript”);}
});
But we found that IE and Safari sends headers like: HTTP_ACCEPT=>“text/html, /, text/javascript”, with the javascript header last so this mucks up the respond_to block as it will always enter the first block (usually format.html) and never reach your format.js block.
We have a before filter called on required actions that forces the request format to be javascript if it is an xml_http_request?
def fix_xml_http_request if request.xml_http_request? request.format = :js end end

initializers
initializers/* are not loaded if one of the required gems fails to load. So your inflections, mines, etc, will not be loaded.
The required gems are defined on environment.rb with config.gem

email_to('xxx@xxx','xxx@xxx',:encode=>'javascript') does NOT work
as i always want the email in the link text, email_to does not help me…
so here comes the rescue!
#http://unixmonkey.net/?p=20 # Takes in an email address and (optionally) anchor text, # its purpose is to obfuscate email addresses so spiders and # spammers can't harvest them. def js_antispam_email_link(email, linktext=email) user, domain = email.split('@') # if linktext wasn't specified, throw email address builder into js document.write statement linktext = "'+'#{user}'+'@'+'#{domain}'+'" if linktext == email out = "<noscript>#{linktext} #{user}(ät)#{domain}</noscript>\n" out += "<script language='javascript'>\n" out += " <!--\n" out += " string = '#{user}'+'@'+''+'#{domain}';\n" out += " document.write('<a href='+'m'+'a'+'il'+'to:'+ string +'>#{linktext}</a>'); \n" out += " //-->\n" out += "</script>\n" return out end

Multiple filter methods with :only, :except
Notice that this methods accepts *filters param, so you can pass array of methods with :only or :except too
Example
before_filter [:authorize, :set_locale], :except => :login

Value parameter
You can add a value to your hidden field by using the :value parameter.
Example
hidden_field(:object, :field, :value => params[:requestval])

Set time zone in before filter
To set your time zone you could create a before_filter in your application.rb controller
class ApplicationController < ActionController::Base before_filter :set_timezone def set_timezone Time.zone = 'GMT' end end

2.1 sets UTC time by default
Rails 2.1 sets hour select to UTC time value, not local server time by default. So if you’re not in UTC time zone don’t forget to specify timezone in your config/environment.rb: config.time_zone = 'Vilnius'

Using gmail SMTP server to send mail
First you would need to sign up with Google Apps, which is a very painless process:
http://www.google.com/a/cpanel/domain/new
Next you need to install a plugin that will allow ActionMailer to make a secure connection to google:
script/plugin install git://github.com/caritos/action_mailer_tls.git
We need this due to transport layer security used by google.
Lastly all you need to do is place this in your environment.rb file and modify it to your settings:
ActionMailer::Base.smtp_settings = { :address => "smtp.gmail.com", :port => 587, :domain => "your.domain_at_google.com", :authentication => :plain, :user_name => "google_username", :password => "password" }