How can I set default value in ActiveRecord?
I see a post from Pratik that describes an ugly, complicated chunk of code: http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model
class Item < ActiveRecord::Base
def initialize_with_defaults(attrs = nil, &block)
initialize_without_defaults(attrs) do
setter = lambda { |key, value| self.send("#{key.to_s}=", value) unless
!attrs.nil? && attrs.keys.map(&:to_s).include?(key.to_s) }
setter.call('scheduler_type', 'hotseat')
yield self if block_given?
end
end
alias_method_chain :initialize, :defaults
end
I have seen the following examples googling around:
def initialize
super
self.status = ACTIVE unless self.status
end
and
def after_initialize
return unless new_record?
self.status = ACTIVE
end
I’ve also seen people put it in their migration, but I’d rather see it defined in the model code.
Is there a canonical way to set default value for fields in ActiveRecord model?
There are several issues with each of the available methods, but I believe that defining an
after_initializecallback is the way to go for the following reasons:default_scopewill initialize values for new models, but then that will become the scope on which you find the model. If you just want to initialize some numbers to 0 then this is not what you want.Model.new).initializecan work, but don’t forget to callsuper!after_initializeis deprecated as of Rails 3. When I overrideafter_initializein rails 3.0.3 I get the following warning in the console:Therefore I’d say write an
after_initializecallback, which lets you default attributes in addition to letting you set defaults on associations like so:Now you have just one place to look for initialization of your models. I’m using this method until someone comes up with a better one.
Caveats:
For boolean fields do:
self.bool_field = true if self.bool_field.nil?See Paul Russell’s comment on this answer for more details
If you’re only selecting a subset of columns for a model (ie; using
selectin a query likePerson.select(:firstname, :lastname).all) you will get aMissingAttributeErrorif yourinitmethod accesses a column that hasn’t been included in theselectclause. You can guard against this case like so:self.number ||= 0.0 if self.has_attribute? :numberand for a boolean column…
self.bool_field = true if (self.has_attribute? :bool_value) && self.bool_field.nil?Also note that the syntax is different prior to Rails 3.2 (see Cliff Darling’s comment below)