Is it better to set default value in migration or in callback? It's difficult to delete (or set another) default value in migration, but in model it one more piece of code
4 Answers
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
5 Comments
before_create? then you don't need to check :persisted?before_create will override existing value and we do not want to set default value if the object already has values. This is why we are setting default value only when the object is new and not persisted.before_create will fire up only once in the lifetime of the model in DB row. before_update will fire up every time you alter the model in DB.Model.newIn Rails 5, the attributes API allows specification of default values. The syntax is simple and allows you to change a default without a migration.
# db/schema.rb
create_table :store_listings, force: true do |t|
t.string :my_string, default: "original default"
end
# app/models/store_listing.rb
class StoreListing < ActiveRecord::Base
attribute :my_string, :string, default: "new default"
end
2 Comments
"", an empty string, with this the model as is.Piggy-backing on @w-hile answer — which is a great one, unless you have a bunch of things you want to make "settings" —
I grew sick and tired of polluting my models with a bunch of columns devoted to settings, so I wrote Setsy.
class User < ApplicationRecord
include ::Setsy::DSL
# each setting can be a hash, like posts_limit, or just a value
DEFAULT_SETTINGS = {
posts_limit: { value: 10 },
favorite_color: 'blue'
}.freeze
setsy :settings, column: :settings_data, defaults: DEFAULT_SETTINGS do |conf|
conf.reader :posts_limit_and_color do
"posts limit is #{posts_limit} and color is #{favorite_color}"
end
end
end
And you can,
user = User.first
user.settings # {posts_limit: 10, favorite_color: 'blue'}
user.settings.posts_limit # 10
user.settings.posts_limit.default? # true
user.assign_attributes(settings_data: { posts_limit: 15, favorite_color: 'blue' })
user.settings.posts_limit.default? # false
user.settings.posts_limit.default # 10
Comments
As a general rule, on the backend, enforce constraints in models and in the DB. It's like validation JS and not validating in the backend side (PHP, ROR, etc). Someone can modify your JS to pass the validation and since you didn't validate on the backend, your site may be compromised. Thus, validate always in both sides, at least if your app server gets compromise, the DB server may put up some defense.