Rails: How can I set default values in ActiveRecord?
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.- Defining defaults in your migration also works part of the time... As has already been mentioned this will not work when you just call Model.new.
- Overriding
initialize
can work, but don't forget to callsuper
! - Using a plugin like phusion's is getting a bit ridiculous. This is ruby, do we really need a plugin just to initialize some default values?
- Overriding
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:
DEPRECATION WARNING: Base#after_initialize has been deprecated, please use Base.after_initialize :method instead. (called from /Users/me/myapp/app/models/my_model:15)
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:
class Person < ActiveRecord::Base
has_one :address
after_initialize :init
def init
self.number ||= 0.0 #will set the default value only if it's nil
self.address ||= build_address #let's you set a default association
end
end
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)
How can I set some default values to a column in rails?
You have to use model to do it, following is example fo doing. in your migration add following
t.integer "status", default: 1, null: false
Now in your modle app/models/checks.rb
put following codes
STATUS = {
pending: 0,
scheduled: 1,
runnin: 2
}.freeze
enum status: STATUS
Now you can also access like following
check = Check.first
puts check.status
So you are actually saving enum in integer, whose values you define in module. This is one way of doing it.
How can i set the default values of controller parameters?
If you need the last_updated_by
param to go within the customer_params (customer hash key for ActionController::Parameters
), then:
before_action :set_last_updated_by_param, only: :create
private
def set_last_updated_by_param
params[:customer][:last_updated_by] = params.dig(:customer, :name)
end
The before_action callback adds the new key last_updated_by
on the customer
params only before the create action is executed.
Notice, no need to modify the customer_params to permit it.
As showed by @JohanWentholt, with_defaults
seems to be the best way. Go for it.
Waiting the OP chooses the correct answer.
Set a default value conditionally
From the API docs
after_find and after_initialize callback is triggered for each object that is found and instantiated by a finder, with after_initialize being triggered after new objects are instantiated as well.
You could do something along the lines of:
class Room < ApplicationRecord
after_initialize :set_room_defaults
def set_room_defaults
if people_in_room.size == 1
set room_type = "Single"
elsif people_in_room.size == 2
set room_type = "Double"
elsif people_in_room.size == 3
set room_type = "Triple"
end
end
end
Or you could store the mappings in an Array
:
class Room < ApplicationRecord
ROOM_TYPES = %w(Single Double Triple).freeze
after_initialize :set_room_defaults
def set_room_defaults
set room_type = ROOM_TYPES[people_in_room.size - 1]
end
end
set default value of attribute in rails
If you need the value set immediately before the record is created, a before_create
event seems more appropriate for your use case.
how to set default value to column in rails while creating migration
You can't do this from the command line - you'll have to edit the migration file and change the corresponding line to something like
add_column :users, :notification_email, :boolean, :default => true
Default values for models in rails
Defining defaults in your migration has some disadvantages as well. This will not work when you just call Model.new
.
I prefer to write an after_initialize
callback, which lets me set default attributes:
class Model < ActiveRecord::Base
after_initialize :set_defaults, unless: :persisted?
# The set_defaults will only work if the object is new
def set_defaults
self.attribute ||= 'some value'
self.bool_field = true if self.bool_field.nil?
end
end
How to set default values in Rails?
"Correct" is a dangerous word in Ruby. There's usually more than one way to do anything. If you know you'll always want that default value for that column on that table, setting them in a DB migration file is the easiest way:
class SetDefault < ActiveRecord::Migration
def self.up
change_column :people, :last_name, :type, :default => "Doe"
end
def self.down
# You can't currently remove default values in Rails
raise ActiveRecord::IrreversibleMigration, "Can't remove the default"
end
end
Because ActiveRecord autodiscovers your table and column properties, this will cause the same default to be set in any model using it in any standard Rails app.
However, if you only want default values set in specific cases -- say, it's an inherited model that shares a table with some others -- then another elegant way is do it directly in your Rails code when the model object is created:
class GenericPerson < Person
def initialize(attributes=nil)
attr_with_defaults = {:last_name => "Doe"}.merge(attributes)
super(attr_with_defaults)
end
end
Then, when you do a GenericPerson.new()
, it'll always trickle the "Doe" attribute up to Person.new()
unless you override it with something else.
Related Topics
Regular Expressions With Validations in Ror 4
Ruby - Print the Variable Name and Then Its Value
Naked Asterisk as Parameter in Method Definition: Def F(*)
Method to Parse HTML Document in Ruby
How to Find the Local Port a Rails Instance Is Running On
Adding a Directory to $Load_Path (Ruby)
Rails 4: Before_Filter Vs. Before_Action
Is There a Performance Gain in Using Single Quotes VS Double Quotes in Ruby
How to Uninstall Ruby on Ubuntu
Difference Between '..' (Double-Dot) and '...' (Triple-Dot) in Range Generation
What Are the Restrictions For Method Names in Ruby
Strange \N in Base64 Encoded String in Ruby
Backslashes in Single Quoted Strings Vs. Double Quoted Strings