如何在Rails中设置默认值?
我试图find最好的方法来设置Rails中的对象的默认值。
我能想到的最好的方法是在控制器中的new
方法中设置默认值。
有没有人有任何意见,如果这是可以接受的,或者有更好的方法来做到这一点?
“正确”在Ruby中是一个危险的词。 通常有不止一种方法来做任何事情。 如果您知道您始终需要该表的该列的默认值,则将其设置在数据库迁移文件中是最简单的方法:
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
因为ActiveRecord自动发现你的表和列的属性,这将导致在任何标准的Rails应用程序中使用它的任何模型中设置相同的默认值。
但是,如果您只想在特定情况下设置默认值(例如,它是与其他人共享表的inheritance模型),那么在创build模型对象时,另一个优雅的方法是直接在Rails代码中执行:
class GenericPerson < Person def initialize(attributes=nil) attr_with_defaults = {:last_name => "Doe"}.merge(attributes) super(attr_with_defaults) end end
然后,当你做一个GenericPerson.new()
,它总是将“Doe”属性Person.new()
除非你用别的东西覆盖它。
基于SFEley的回答,这里是更新的/固定的更新的Rails版本:
class SetDefault < ActiveRecord::Migration def change change_column :table_name, :column_name, :type, default: "Your value" end end
首先你不能重载initialize(*args)
因为在所有情况下都不会调用它。
你最好的select是把你的默认值进入你的迁移:
add_column :accounts, :max_users, :integer, :default => 10
其次,将默认设置放入模型中,但这只适用于最初为零的属性。 你可能有麻烦,因为我用boolean
列做:
def after_initialize if new_record? max_users ||= 10 end end
你需要new_record?
所以默认值不会覆盖从数据库加载的值。
您需要||=
来阻止Rails覆盖传递给initialize方法的参数。
您也可以在您的迁移中尝试change_column_default
(在Rails 3.2.8中testing):
class SetDefault < ActiveRecord::Migration def up # Set default value change_column_default :people, :last_name, "Smith" end def down # Remove default change_column_default :people, :last_name, nil end end
change_column_default Rails API文档
如果你指的是ActiveRecord对象,你可以有两种方法来做到这一点:
1.在DB中使用:default参数
例如
class AddSsl < ActiveRecord::Migration def self.up add_column :accounts, :ssl_enabled, :boolean, :default => true end def self.down remove_column :accounts, :ssl_enabled end end
更多信息在这里: http : //api.rubyonrails.org/classes/ActiveRecord/Migration.html
2.使用callback
EG before_validation_on_create
更多信息: http : //api.rubyonrails.org/classes/ActiveRecord/Callbacks.html#M002147
在Ruby on Rails v3.2.8中,使用after_initialize
ActiveRecordcallbackafter_initialize
,您可以调用模型中的一个方法,为新对象分配默认值。
after_initializecallback触发每个查找器find并实例化的对象,after_initialize触发新对象实例化( 请参阅ActiveRecordcallback )。
所以,IMO应该看起来像这样:
class Foo < ActiveRecord::Base after_initialize :assign_defaults_on_new_Foo ... attr_accessible :bar ... private def assign_defaults_on_new_Foo # required to check an attribute for existence to weed out existing records self.bar = default_value unless self.attribute_whose_presence_has_been_validated end end
Foo.bar = default_value
,除非实例在保存/更新时包含之前的attribute_whose_presence_has_been_validated
。 然后, default_value
将与您的视图一起使用,以使用bar
属性的default_value
来呈现表单。
充其量这是hacky …
编辑 – 使用“new_record?” 检查是否从一个新的调用实例化
而不是检查一个属性值,使用new_record?
带导轨的内置方法。 所以,上面的例子应该是这样的:
class Foo < ActiveRecord::Base after_initialize :assign_defaults_on_new_Foo, if: 'new_record?' ... attr_accessible :bar ... private def assign_defaults_on_new_Foo self.bar = default_value end end
这更清洁。 啊,Rails的魔力 – 比我聪明。
至less在Rails 3.2.6中的布尔字段,这将在你的迁移工作。
def change add_column :users, :eula_accepted, :boolean, default: false end
因为它是一个布尔型字段,所以将1
或0
作为默认值将不起作用。 它必须是一个true
或false
价值。
如果你只是设置数据库支持模型的某些属性的默认值,我会考虑使用sql默认列值 – 你能澄清你正在使用什么types的默认值?
有很多方法来处理它,这个插件看起来像一个有趣的选项。
重写新/初始化的build议可能不完整。 Rails将(经常)调用分配给ActiveRecord对象,调用allocate不会导致调用初始化。
如果你正在谈论ActiveRecord对象,看看重写after_initialize。
这些博客文章(不是我的)是有用的:
默认值 未调用的默认构造函数
[编辑:SFEley指出,Rails实际上在数据库中实例化一个新的对象时会查看数据库中的默认值 – 我没有意识到这一点。]
我需要设置一个默认值,就像在DB中指定为默认列值一样。 所以它的行为就像这样
a = Item.new a.published_at # => my default value a = Item.new(:published_at => nil) a.published_at # => nil
由于after_initializecallback是在从参数中设置属性之后调用的,因此无法知道该属性是否为零,因为它从未设置过,或者因为它被故意设置为nil。 所以我不得不在里面捅一下这个简单的解决scheme。
class Item < ActiveRecord::Base def self.column_defaults super.merge('published_at' => Time.now) end end
对我很好。 (Rails 3.2.x)
比提出的答案更可能的更清洁的方式是覆盖访问器,如下所示:
def status self['name_of_var'] || 'desired_default_value' end
请参阅ActiveRecord :: Base文档中的 “覆盖默认访问器”,以及使用self自StackOverflow获取更多内容 。
我在这里回答了一个类似的问题..干净的方法是使用Rails attr_accessor_with_default
class SOF attr_accessor_with_default :is_awesome,true end sof = SOF.new sof.is_awesome => true
UPDATE
在Rails 3.2中已经废弃了attr_accessor_with_default ..你可以用纯Ruby来代替它
class SOF attr_writer :is_awesome def is_awesome @is_awesome ||= true end end sof = SOF.new sof.is_awesome #=> true
如果你在谈论ActiveRecord对象,我使用'属性 – 默认'gem。
文档和下载: https : //github.com/bsm/attribute-defaults
你可以使用rails_default_value gem。 例如:
class Foo < ActiveRecord::Base # ... default :bar => 'some default value' # ... end
您可以覆盖ActiveRecord模型的构造函数。
喜欢这个:
def initialize(*args) super(*args) self.attribute_that_needs_default_value ||= default_value self.attribute_that_needs_another_default_value ||= another_default_value #ad nauseum end