Rails: Setting Default Attributes on an ActiveRecord Model

Update 28 June 2009: Rollo Tomazzi noted in the comments that the method described below will not work for hash-value attributes. He has written a review of the various methods for setting default attribute values on his blog.

Whilst working with Rails' ActiveRecord, I was looking for a clean way to insert default data into a model object before it was presented to the controller. In a lot of Rails tutorials I've seen, such default data is written in the controller, e.g.:

class PostsController < ActionController  
  def new
    @post = Post.new(:category_id => 5)

However, this isn't very DRY, as I would need to duplicate the initialisation code if I were to create an instance of Post in another controller method. It would make more sense to put such default data into the model itself, so that wherever I create the new Post, it is always initialised with the same default data.

I initially thought the answer would be ActiveRecord's after_initialize callback method, but this overwrote any attribute values set from the database after a record was loaded.

Instead, thanks to this post, I learned that you simply override the attribute accessor with a value. You can directly access the dynamic attributes set by ActiveRecord using the read_attribute and write_attribute methods:

class Post < ActiveRecord::Base  
  # Default category ID stored in the Settings hash.
  def category_id
    read_attribute(:category_id) or Settings.defaults[:category_id]

  # Hard-coded default
  def title
    read_attribute(:title) or "New Post"