Rails: How do I create a default value for attributes in Rails activerecord's model?

Viewed 225728

I want to create a default value for an attribute by defining it in ActiveRecord. By default everytime the record is created, I want to have a default value for attribute :status. I tried to do this:

class Task < ActiveRecord::Base
  def status=(status)
    status = 'P'
    write_attribute(:status, status)
  end
end

But upon creation I still retrieve this error from the database:

ActiveRecord::StatementInvalid: Mysql::Error: Column 'status' cannot be null

Therefore I presume the value was not applied to the attribute.

What would be the elegant way to do this in Rails?

Many thanks.

10 Answers

Because I encountered this issue just a little while ago, and the options for Rails 3.0 are a bit different, I'll provide another answer to this question.

In Rails 3.0 you want to do something like this:

class MyModel < ActiveRecord::Base
  after_initialize :default_values

  private
    def default_values
      self.name ||= "default value"
    end
end

When I need default values its usually for new records before the new action's view is rendered. The following method will set the default values for only new records so that they are available when rendering forms. before_save and before_create are too late and will not work if you want default values to show up in input fields.

after_initialize do
  if self.new_record?
    # values will be available for new record forms.
    self.status = 'P'
    self.featured = true
  end
end

As I see it, there are two problems that need addressing when needing a default value.

  1. You need the value present when a new object is initialized. Using after_initialize is not suitable because, as stated, it will be called during calls to #find which will lead to a performance hit.
  2. You need to persist the default value when saved

Here is my solution:

# the reader providers a default if nil
# but this wont work when saved
def status
  read_attribute(:status) || "P"
end

# so, define a before_validation callback
before_validation :set_defaults
protected
def set_defaults
  # if a non-default status has been assigned, it will remain
  # if no value has been assigned, the reader will return the default and assign it
  # this keeps the default logic DRY
  status = status
end

I'd love to know why people think of this approach.

Related