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?
The after_initialize callback pattern can be improved by simply doing the following
This has a non-trivial benefit if your init code needs to deal with associations, as the following code triggers a subtle n+1 if you read the initial record without including the associated.
This has been answered for a long time, but I need default values frequently and prefer not to put them in the database. I create a
DefaultValues
concern:And then use it in my models like so:
I strongly suggest using the "default_value_for" gem: https://github.com/FooBarWidget/default_value_for
There are some tricky scenarios that pretty much require overriding the initialize method, which that gem does.
Examples:
Your db default is NULL, your model/ruby-defined default is "some string", but you actually want to set the value to nil for whatever reason:
MyModel.new(my_attr: nil)
Most solutions here will fail to set the value to nil, and will instead set it to the default.
OK, so instead of taking the
||=
approach, you switch tomy_attr_changed?
...BUT now imagine your db default is "some string", your model/ruby-defined default is "some other string", but under a certain scenario, you want to set the value to "some string" (the db default):
MyModel.new(my_attr: 'some_string')
This will result in
my_attr_changed?
being false because the value matches the db default, which in turn will fire your ruby-defined default code and set the value to "some other string" -- again, not what you desired.For those reasons I don't think this can properly be accomplished with just an after_initialize hook.
Again, I think the "default_value_for" gem is taking the right approach: https://github.com/FooBarWidget/default_value_for
In Rails 5+, you can use the attribute method within your models, eg.:
The Phusion guys have some nice plugin for this.
An even better/cleaner potential way than the answers proposed is to overwrite the accessor, like this:
See "Overwriting default accessors" in the ActiveRecord::Base documentation and more from StackOverflow on using self.