我想通过在ActiveRecord中定义属性来创建一个默认值。默认情况下,每次创建记录时,我都希望attribute:status有一个默认值。我试着这样做:
class Task < ActiveRecord::Base
def status=(status)
status = 'P'
write_attribute(:status, status)
end
end
但是在创建时,我仍然从数据库中检索这个错误:
ActiveRecord::StatementInvalid: Mysql::Error: Column 'status' cannot be null
因此,我假定该值没有应用于属性。
在Rails中做这件事的优雅方式是什么?
多谢。
在我看来,在需要默认值时需要解决两个问题。
在初始化新对象时,需要该值。使用after_initialize并不合适,因为如前所述,它将在调用#find期间被调用,这将导致性能下降。
保存时需要保留默认值
以下是我的解决方案:
# the reader providers a default if nil
# but this wont work when saved
def status
read_attribute(:status) || "P"
end
# so, define a before_validation callback
before_validation :set_defaults
protected
def set_defaults
# if a non-default status has been assigned, it will remain
# if no value has been assigned, the reader will return the default and assign it
# this keeps the default logic DRY
status = status
end
我很想知道为什么人们会想到这种方法。
解决方案取决于几件事。
默认值是否依赖于创建时可用的其他信息?
你能以最小的代价清除数据库吗?
如果你对第一个问题的回答是肯定的,那么你就想使用吉姆的解决方案
如果你对第二个问题的回答是肯定的,那么你就想用丹尼尔的答案
如果两个问题的答案都是否定的,那么您最好添加并运行一个新的迁移。
class AddDefaultMigration < ActiveRecord::Migration
def self.up
change_column :tasks, :status, :string, :default => default_value, :null => false
end
end
:string可以替换为ActiveRecord::Migration识别的任何类型。
CPU很便宜,所以在Jim的解决方案中重新定义Task不会引起太多问题。特别是在生产环境中。这种迁移是正确的方式,因为它被加载并且调用得更少。
在我看来,在需要默认值时需要解决两个问题。
在初始化新对象时,需要该值。使用after_initialize并不合适,因为如前所述,它将在调用#find期间被调用,这将导致性能下降。
保存时需要保留默认值
以下是我的解决方案:
# the reader providers a default if nil
# but this wont work when saved
def status
read_attribute(:status) || "P"
end
# so, define a before_validation callback
before_validation :set_defaults
protected
def set_defaults
# if a non-default status has been assigned, it will remain
# if no value has been assigned, the reader will return the default and assign it
# this keeps the default logic DRY
status = status
end
我很想知道为什么人们会想到这种方法。