Ruby on Rails
RailsBestPractices

Seasoned Developers Post Best Practices Here
———————————————————————

Set Default Values in Methods:

In methods that accept variables, you can set a default value with a simple assignment:
<pre> def self.custom_find( id_to_find = 1 ) ... end </pre>


Simple Hash as Default Method Parameter:

This form allows you to add functionality to methods without breaking existing calls, as the order of arguments is irrelevant. Anything the method depends on should be defined in required_params

<pre> def foo(params = {}) required_params = { :bar => 'quux', :baz => 'buuz' } params = required_params.merge params #... [params[:bar], params[:baz]].join(', ') end

>> foo(:bar => ‘hello’, :baz => ‘world’, :quux => ‘!’)
hello, world


Suppress the new line when closing your ERb phrases:
<pre><% @time = Time.now -%></pre>Notice the minus-sign before the close? That suppresses the new line.

You can also set this behavior for all ERb phrases by adding the following to your environment.rb:
<pre> ActionView::Base.erb_trim_mode = '>' </pre>
WARNING! If you put this in environment.rb then you won’t get clear stack traces even in your development environment. Hence, I suggest you put it in the production.rb


Use a left join with a has_many/belongs_to:

Instead of the standard rails way of one query per foreign key record. Say you have an author who has_many :books, and a book belongs_to :author (assume only 1 author per book for this example). Then you can do the following to preload all the books the author has written, when querying for the author

<pre> @author = Author.find(params[:id], :include => :books)


Properly substitute variables in an SQL Query

<pre> @records = Record.find(:all, :conditions => ["author_id = ?", params[:author]])

@records = Record.find(:all, :conditions => “author_id = :author”, params])

Note — Some of what is here are simply good Ruby idioms, irrespective of Rails. Rather than duplicate such information (nicely collected for us on the RubyGarden wiki ) it may be better to focus on Rails-specific practices, or situations when a general good Ruby practice may not be the best option in a Rails app.

I agree with this and will update the page accordingly to keep it useful

%{color:red}Unfortunately RubyGarden isn’t updated often, nor has it been online in the past few days. %
——

Check your data:

MySQL (by default) is lax in what it accepts as a valid date, and what your app will be presented with. For example, “1953-00-00” is a valid date to MySQL, and that value will be presented to ActiveRecord without a problem. However, when asked for this attribute, AR will give back nil, because Ruby’s date format won’t accept zero days and months. In my opinion, this ought to raise an exception, but that’s not the current behaviour. Always assume that someone will have command-line access to your data, and code defensively.
——

Migrations

You should be using migrations. More than that, always assume that someone is going to have to rebuild your database up from bare metal with only your migrations to help them. The slight subtlety to that is that it’s a bad idea to use any complex methods on ActiveRecord::Base in your migrations, because while the migration might work when it’s written, your model code might change in the future to stop it from working. Limit yourself to using the model[:colname] idiom in the migrations if you can.

Put a transaction around your migrations. That way, you know that you won’t be dumped out half-way through a migration, and have to disentangle whatever half-finished mess you end up with to try to run it again. The slight crimp to this is that MySQL doesn’t allow data definition commands (like CREATE TABLE, for instance) inside a transaction, and they cause an implicit commit. It’s still a good idea for data-only migrations, though.

An example of this looks as follows

<pre> class SomeMigration < ActiveRecord::Migration def self.up ActiveRecord::Base.transaction do say "Creating table 'foos'" create_table :foos do |t| t.column :created_at, :timestamp, :null => false t.column :updated_at, :timestamp, :null => false t.column :foo, :string, :null => false t.column :bar, :string, :null => false end

say “Adding indexes on ‘foos’” add_index :foos, :foo, :unique => true add_index :foos, :bar end end def self.down ActiveRecord::Base.transaction do drop_table :foos end end

end

——

Referring to attributes in models

Always prepend references to attributes with self in your model methods. That way, when your schema changes, you’ll get useful error messages if you forget to change the method code. If you try to change the value of a attribute of your model without referencing it with self, you will be creating a new local variable.
——

Refer to your parameters properly

The method call form:

params[:thing]

is prefered to the instance variable form:

@params[:thing]

Similarly, you should use session[:user] instead of @session[:user]. Directly accessing the instance variables is deprecated and will generate warnings with rails 1.2.

The reasoning behind this is straigtforward. Accessing the instance variables directly, using the @ form, does not allow the implementation of the value to change. When accessed without the @, it calls a method that returns the instance variable. If it becomes necessary to change the way the value is determined (building it dynamically, for example), this allows it to be abstracted nicely.
——

When to use "value", @’value@’, and :value

I am never quite sure when to use each of these methods of representing a value. I know that :value is a symbol, but how do "value" and 'value' differ? And when should each one be used?

Double quoted strings are interpolated:

<pre> >> name = 'John the Baptist' >> puts 'Hello, #{name}!' Hello, #{name}! >> puts "Hello, #{name}!" Hello, John the Baptist! >> #Same as: >> puts 'Hello, '+name+'!' Hello, John the Baptist! </pre>

name here could have been any valid expression. Interpolation usually looks “cleaner” than concatenating with +, and has been shown to actually be a bit faster too.

In short: Use symbols only as keys. For strings, use single quotes unless you need to interpolate other values into it.

——

External web sites related to this topic

——