如何在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 

因为它是一个布尔型字段,所以将10作为默认值将不起作用。 它必须是一个truefalse价值。

如果你只是设置数据库支持模型的某些属性的默认值,我会考虑使用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 

https://github.com/keithrowell/rails_default_value

您可以覆盖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