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?
If the column happens to be a 'status' type column, and your model lends itself to the use of state machines, consider using the aasm gem, after which you can simply do
It still doesn't initialize the value for unsaved records, but it's a bit cleaner than rolling your own with
init
or whatever, and you reap the other benefits of aasm such as scopes for all your statuses.use default_scope in rails 3
api doc
ActiveRecord obscures the difference between defaulting defined in the database (schema) and defaulting done in the application (model). During initialization, it parses the database schema and notes any default values specified there. Later, when creating objects, it assigns those schema-specified default values without touching the database.
discussion
From the api docs http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html Use the
before_validation
method in your model, it gives you the options of creating specific initialisation for create and update calls e.g. in this example (again code taken from the api docs example) the number field is initialised for a credit card. You can easily adapt this to set whatever values you wantSurprised that his has not been suggested here
There are several issues with each of the available methods, but I believe that defining an
after_initialize
callback is the way to go for the following reasons:default_scope
will 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.initialize
can work, but don't forget to callsuper
!after_initialize
is deprecated as of Rails 3. When I overrideafter_initialize
in rails 3.0.3 I get the following warning in the console:Therefore I'd say write an
after_initialize
callback, 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
select
in a query likePerson.select(:firstname, :lastname).all
) you will get aMissingAttributeError
if yourinit
method accesses a column that hasn't been included in theselect
clause. You can guard against this case like so:self.number ||= 0.0 if self.has_attribute? :number
and 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)
We put the default values in the database through migrations (by specifying the
:default
option on each column definition) and let Active Record use these values to set the default for each attribute.IMHO, this approach is aligned with the principles of AR : convention over configuration, DRY, the table definition drives the model, not the other way around.
Note that the defaults are still in the application (Ruby) code, though not in the model but in the migration(s).
Similar questions, but all have slightly different context: - How do I create a default value for attributes in Rails activerecord's model?
Best Answer: Depends on What You Want!
If you want every object to start with a value: use
after_initialize :init
You want the
new.html
form to have a default value upon opening the page? use https://stackoverflow.com/a/5127684/1536309If you want every object to have a value calculated from user input: use
before_save :default_values
You want user to enterX
and thenY = X+'foo'
? use: