Rails:如何在 ActiveRecord 中设置默认值? [英] Rails: How can I set default values in ActiveRecord?
问题描述
如何在 ActiveRecord 中设置默认值?
我看到 Pratik 的一篇文章描述了一段丑陋而复杂的代码:http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model
class Item
我在谷歌上看到了以下示例:
def 初始化极好的self.status = ACTIVE 除非 self.status结尾
和
def after_initialize除非 new_record 返回?self.status = ACTIVE结尾
我也看到人们将其放入迁移中,但我更愿意在模型代码中定义它.
是否有一种规范的方法可以为 ActiveRecord 模型中的字段设置默认值?
每种可用方法都有几个问题,但我相信定义 after_initialize
回调是解决问题的方法以下原因:
default_scope
将初始化新模型的值,但这将成为您找到模型的范围.如果您只想将一些数字初始化为 0,那么这不是您想要的.- 在您的迁移中定义默认值在某些时候也有效...正如已经提到的那样,当您只调用 Model.new 时,这将起作用.
- 覆盖
initialize
可以工作,但不要忘记调用super
! - 使用像 phusion 这样的插件有点荒谬.这是 ruby,我们真的需要一个插件来初始化一些默认值吗?
- 覆盖
after_initialize
从 Rails 3 开始被弃用.当我在 Rails 3.0.3 中覆盖after_initialize
时,我在控制台中收到以下警告:
<块引用>
弃用警告:Base#after_initialize 已弃用,请改用 Base.after_initialize :method.(从/Users/me/myapp/app/models/my_model:15 调用)
因此我想说写一个 after_initialize
回调,它允许你默认属性除了让你像这样设置关联的默认值:
class Person
现在您只有一个地方可以查找模型的初始化.我一直在使用这种方法,直到有人想出更好的方法.
注意事项:
对于布尔字段:
self.bool_field = true if self.bool_field.nil?
有关详细信息,请参阅 Paul Russell 对此答案的评论
如果您只是为模型选择列的子集(即;在像
Person.select(:firstname, :lastname).all 这样的查询中使用
select
) 如果您的init
方法访问未包含在select
子句中的列,您将得到MissingAttributeError
.您可以像这样防范这种情况:self.number ||= 0.0 如果 self.has_attribute?:number
对于布尔列...
self.bool_field = true if (self.has_attribute? :bool_value) &&self.bool_field.nil?
另请注意,Rails 3.2 之前的语法有所不同(请参阅下面的 Cliff Darling 评论)
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?
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)
这篇关于Rails:如何在 ActiveRecord 中设置默认值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!