5 Rails Tips April 25th, 2008

Ryan Bates at railscasts.com has written out a contest where he asks to publish your own Ruby on Rails tips, 5 of them, and let him know about it. I’m keen on the idea of sharing some Rails wisdom with the world, so here are my humble 5 Rails Tips.

using alias_method_chain to improve your models

In Ruby on Rails projects I like to use the Fat Models, Skinny Controllers principle. Sometimes I have models with associations that are quite evident, and where I want it to be very transparent how to set them. For example, I have a Post, which belongs to a category, but I want to be able to create a post like this:

Post.new :title => "Lorem Ipsum", :content => "Lorem Ipsum dolor...", :category => 'Lorem'

And this should create the Lorem category, or use the one which exists. To reach that goal, I use alias_method_chain

class Post < ActiveRecord::Base
  belongs_to :category

  def category_with_name_recognition=(name)
    if name.is_a? Category
      self.category_without_name_recognition = name
    else
      self.category_without_name_recognition = Category.find_or_initialize_by_name(name)
    end
  end

  alias_method_chain :category=, :name_recognition
end

The alias_method_chain function magically aliases category= to category_without_name_recognition, and then replaces category= to link to category_with_name_recognition. That way I can do a call to the old function. For more info on aliasmethodchain, take a look at your local active_support/core_ext/module/aliasing.rb file.

This comes in very handy when category is an autocomplete_field!

everything you always wanted to know about rake tasks, but were too afraid to ask

Everybody knows the default rake tasks (rake db:migrate, rake test), but do you know the next ones:

  • rake db:create:all –> This will create databases for all defined environments in your database.yml file.
  • rake routes –> This will print out all routes your application knows
  • rake db:fixtures:load –> This will load your test fixtures in your current environments database, I use this all the time

To see all rake tasks, you can just run rake --tasks for a list of all tasks with a short description. For a full description of all tasks, run rake --describe

use read_attribute and write_attribute

If you’re overriding an attribute setter or getter in your models, it’s not possible setting or getting these attributes like you normally would, because that would cause an infinite loop. Luckily, there are methods you can use to get and set the attribute. Lets take a User object for example:

class User < ActiveRecord::Base
  ...

  def password=(pass)
    write_attribute(:password, Security.encode(pass))
  end

  def password
    Security.decode(read_attribute(:password))
  end
end

using your own date and time formats

I personally don’t want to be bothered with time formatting, I can read about any format the internet throws at me. Sadly, some of my clients have different, strong opinions on the way time should be formatted on their website. You really don’t want to be bothered with using strftime everywhere. Luckily, Rails has a solution to this problem.

In your environment.rb, you can define your own time formats:

ActiveSupport::CoreExtensions::Time::Conversions::DATE_FORMATS.merge!(
  :client_readable => "%A %B %d at %H:%M", # => Friday April 25 at 11:10
  :client_reports => "%d/%m/%Y at %H:%M"   # => 25/04/2008 at 11:10
)

And then you can use this formatting in your views really easy:

Last updated on <%= @post.updated_at.to_s(:client_readable) %>
# => "Last updated on Friday April 25 at 11:20"

you need plugins!!!

Rails is a great framework, but it doesn’t implement every need of every project. Most of the time however, you’re not the first person to need feature A, or something B, most of the time the feature you want is already in a plugin. These are 5 plugins I can’t live without:

cool Rails 2.1 features

I couldn’t constrain myself to 5 rails tips. Today, and today only, you get a free 6th tip!

If you’re running on Rails Edge (which I do for most projects), or you’re reading this when Rails 2.1 is already out, there are a bunch of cool new features that aren’t documented yet.

render :partial => form
# Before Rails 2.1
<% form_for @client do |form| %>
  <%= render :partial => 'form', :object => form %>
  <%= form.submit "Save" %>
<% end %>

# Now, with sparkly new Rails
<% form_for @client do |form| %>
  <%= render :partial => form %> # Automaticly renders _form.erb 
  <%= form.submit "Save %>
find(:last)
# Before Rails 2.1
@last_post = Post.find(:first, :order => 'created_at DESC')

# with Rails 2.1
@last_post = Post.find(:last, :order => 'created_at')
Easy finding
# Before Rails 2.1
Post.find :all
Post.find :first

# with Rails 2.1, thanks to scoping
Post.all
Post.first
Post.last

These are all small changes that I find particularly handy in my day-to-day work. For the “big” changes, you should read Ryan’s Scraps, he keeps track of all big changes in Rails.

And with that, I’m all out of tips, at least for now. Comments are always appreciated!

tags: , , , , l

2 Responses to “5 Rails Tips”

  • 4 months ago Marcus said

    Thanks for the tips. I found them on the Railscast list… definitely better than the first and second place winners :)

  • 3 months ago rose said

    Dates and time ‘always’ give trouble :) , great tip !

Leave a Reply