如何在ActiveRecord中设置默认值?
我看到Pratik的一篇文章描述了一段丑陋而复杂的代码: 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
我已经看到以下示例谷歌搜索:
def initialize
super
self.status = ACTIVE unless self.status
end
和
def after_initialize
return unless new_record?
self.status = ACTIVE
end
我也看到人们把它放在他们的迁移中,但我宁愿看到它在模型代码中定义。
是否有规范方法为ActiveRecord模型中的字段设置默认值?
#1楼
来自api文档http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html在模型中使用before_validation
方法,它为您提供了为创建和更新调用创建特定初始化的选项,例如在此示例中(同样代码)取自api docs示例)数字字段初始化为信用卡。 您可以轻松地调整它以设置您想要的任何值
class CreditCard < ActiveRecord::Base
# Strip everything but digits, so the user can specify "555 234 34" or
# "5552-3434" or both will mean "55523434"
before_validation(:on => :create) do
self.number = number.gsub(%r[^0-9]/, "") if attribute_present?("number")
end
end
class Subscription < ActiveRecord::Base
before_create :record_signup
private
def record_signup
self.signed_up_on = Date.today
end
end
class Firm < ActiveRecord::Base
# Destroys the associated clients and people when the firm is destroyed
before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
end
感到惊讶的是他没有在这里被建议
#2楼
一些简单的情况可以通过在数据库模式中定义默认值来处理,但是不能处理许多棘手的情况,包括计算值和其他模型的键。 对于这些情况,我这样做:
after_initialize :defaults
def defaults
unless persisted?
self.extras||={}
self.other_stuff||="This stuff"
self.assoc = [OtherModel.find_by_name('special')]
end
end
我决定使用after_initialize,但我不希望它应用于只找到新的或创建的对象。 我认为对于这个明显的用例没有提供after_new回调几乎令人震惊,但我已经通过确认该对象是否已经持久化表明它不是新的来做到了。
看过Brad Murray的回答,如果条件转移到回调请求,这甚至更清晰:
after_initialize :defaults, unless: :persisted?
# ":if => :new_record?" is equivalent in this context
def defaults
self.extras||={}
self.other_stuff||="This stuff"
self.assoc = [OtherModel.find_by_name('special')]
end
#3楼
after_initialize解决方案的问题在于,无论是否访问此属性,都必须向从数据库中查找的每个对象添加after_initialize。 我建议采用一种懒惰的方法。
属性方法(getters)当然是方法本身,因此您可以覆盖它们并提供默认值。 就像是:
Class Foo < ActiveRecord::Base
# has a DB column/field atttribute called 'status'
def status
(val = read_attribute(:status)).nil? ? 'ACTIVE' : val
end
end
除非像某人指出的那样,否则你需要做Foo.find_by_status('ACTIVE')。 在这种情况下,如果数据库支持,我认为您确实需要在数据库约束中设置默认值。
#4楼
只需执行以下操作即可改进after_initialize回调模式
after_initialize :some_method_goes_here, :if => :new_record?
如果您的初始化代码需要处理关联,这会产生非常重要的好处,因为如果您在不包含关联的情况下读取初始记录,则以下代码会触发一个微妙的n + 1。
class Account
has_one :config
after_initialize :init_config
def init_config
self.config ||= build_config
end
end
#5楼
从文档中:运行sudo gem install attribute-defaults
并将require 'attribute_defaults'
添加到您的应用程序。
class Foo < ActiveRecord::Base
attr_default :age, 18
attr_default :last_seen do
Time.now
end
end
Foo.new() # => age: 18, last_seen => "2014-10-17 09:44:27"
Foo.new(:age => 25) # => age: 25, last_seen => "2014-10-17 09:44:28"
来源:oschina
链接:https://my.oschina.net/stackoom/blog/3163501