Ruby-on-rails 如何为 Rails activerecord 模型中的属性创建默认值?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1550688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How do I create a default value for attributes in Rails activerecord's model?
提问by Joshua Partogi
I want to create a default value for an attribute by defining it in ActiveRecord. By default everytime the record is created, I want to have a default value for attribute :status. I tried to do this:
我想通过在 ActiveRecord 中定义一个属性来创建它的默认值。默认情况下,每次创建记录时,我都希望属性有一个默认值:status。我试图这样做:
class Task < ActiveRecord::Base
def status=(status)
status = 'P'
write_attribute(:status, status)
end
end
But upon creation I still retrieve this error from the database:
但是在创建时我仍然从数据库中检索到这个错误:
ActiveRecord::StatementInvalid: Mysql::Error: Column 'status' cannot be null
Therefore I presume the value was not applied to the attribute.
因此,我认为该值未应用于该属性。
What would be the elegant way to do this in Rails?
在 Rails 中这样做的优雅方式是什么?
Many thanks.
非常感谢。
回答by Jim
You can set a default option for the column in the migration
您可以为迁移中的列设置默认选项
....
add_column :status, :string, :default => "P"
....
OR
或者
You can use a callback, before_save
您可以使用回调, before_save
class Task < ActiveRecord::Base
before_save :default_values
def default_values
self.status ||= 'P' # note self.status = 'P' if self.status.nil? might be safer (per @frontendbeauty)
end
end
回答by BeepDog
Because I encountered this issue just a little while ago, and the options for Rails 3.0 are a bit different, I'll provide another answer to this question.
因为我前段时间也遇到过这个问题,而且Rails 3.0的选项有点不同,所以我再提供一个这个问题的答案。
In Rails 3.0 you want to do something like this:
在 Rails 3.0 中,你想做这样的事情:
class MyModel < ActiveRecord::Base
after_initialize :default_values
private
def default_values
self.name ||= "default value"
end
end
回答by Tim Santeford
When I need default values its usually for new records before the new action's view is rendered. The following method will set the default values for only new records so that they are available when rendering forms. before_saveand before_createare too lateand will not work if you want default values to show up in input fields.
当我需要默认值时,通常在呈现新操作的视图之前用于新记录。下面的方法将只为新记录设置默认值,以便在呈现表单时它们可用。before_save并且before_create都来不及了,不行的,如果你想默认值输入字段中显示出来。
after_initialize do
if self.new_record?
# values will be available for new record forms.
self.status = 'P'
self.featured = true
end
end
回答by Daniel Kristensen
You can do it without writing any code at all :) You just need to set the default value for the column in the database. You can do this in your migrations. For example:
您可以在不编写任何代码的情况下完成此操作:) 您只需要为数据库中的列设置默认值。您可以在迁移中执行此操作。例如:
create_table :projects do |t|
t.string :status, :null => false, :default => 'P'
...
t.timestamps
end
Hope that helps.
希望有帮助。
回答by EmFi
The solution depends on a few things.
解决方案取决于几件事。
Is the default value dependent on other information available at creation time? Can you wipe the database with minimal consequences?
默认值是否取决于创建时可用的其他信息?你能以最小的后果擦除数据库吗?
If you answered the first question yes, then you want to use Jim's solution
如果您回答第一个问题是肯定的,那么您想使用 Jim 的解决方案
If you answered the second question yes, then you want to use Daniel's solution
如果你回答第二个问题是,那么你想使用丹尼尔的解决方案
If you answered no to both questions, you're probably better off adding and running a new migration.
如果您对这两个问题的回答均为否,则最好添加并运行新的迁移。
class AddDefaultMigration < ActiveRecord::Migration
def self.up
change_column :tasks, :status, :string, :default => default_value, :null => false
end
end
:string can be replaced with any type that ActiveRecord::Migration recognizes.
:string 可以替换为 ActiveRecord::Migration 识别的任何类型。
CPU is cheap so the redefinition of Task in Jim's solution isn't going to cause many problems. Especially in a production environment. This migration is proper way of doing it as it is loaded it and called much less often.
CPU 很便宜,因此在 Jim 的解决方案中重新定义 Task 不会引起很多问题。尤其是在生产环境中。这种迁移是正确的方法,因为它被加载并且调用的频率要低得多。
回答by PeppyHeppy
回答by swapab
Just strengthening Jim's answer
只是加强吉姆的回答
Using presenceone can do
使用存在可以做
class Task < ActiveRecord::Base
before_save :default_values
def default_values
self.status = status.presence || 'P'
end
end
回答by aec
For column types Rails supports out of the box - like the string in this question - the best approach is to set the column default in the database itself as Daniel Kristensen indicates. Rails will introspect on the DB and initialize the object accordingly. Plus, that makes your DB safe from somebody adding a row outside of your Rails app and forgetting to initialize that column.
对于列类型 Rails 支持开箱即用 - 就像这个问题中的字符串 - 最好的方法是在数据库本身中设置列默认值,如 Daniel Kristensen 指出的那样。Rails 将内省数据库并相应地初始化对象。另外,这使您的数据库免受有人在您的 Rails 应用程序之外添加一行并忘记初始化该列的影响。
For column types Rails doesn't support out of the box - e.g. ENUM columns - Rails won't be able to introspect the column default. For these cases you do notwant to use after_initialize (it is called every time an object is loaded from the DB as well as every time an object is created using .new), before_create (because it occurs after validation), or before_save (because it occurs upon update too, which is usually not what you want).
对于列类型 Rails 不支持开箱即用 - 例如 ENUM 列 - Rails 将无法内省列默认值。对于这些情况下,你不希望使用after_initialize(它被称为每一个对象从数据库加载以及对象使用。新创建的每个时间的时间),before_create(因为它验证后出现),或before_save(因为它也会在更新时发生,这通常不是您想要的)。
Rather, you want to set the attribute in a before_validation on: create, like so:
相反,您希望在 before_validation on: create 中设置属性,如下所示:
before_validation :set_status_because_rails_cannot, on: :create
def set_status_because_rails_cannot
self.status ||= 'P'
end
回答by Peter P.
As I see it, there are two problems that need addressing when needing a default value.
在我看来,当需要一个默认值时,有两个问题需要解决。
- You need the value present when a new object is initialized. Using after_initialize is not suitable because, as stated, it will be called during calls to #find which will lead to a performance hit.
- You need to persist the default value when saved
- 您需要在初始化新对象时存在的值。使用 after_initialize 是不合适的,因为如前所述,它将在调用 #find 期间调用,这将导致性能下降。
- 保存时需要保持默认值
Here is my solution:
这是我的解决方案:
# 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
I'd love to know why people think of this approach.
我很想知道为什么人们会想到这种方法。
回答by Joshua Partogi
I found a better way to do it now:
我现在找到了一个更好的方法:
def status=(value)
self[:status] = 'P'
end
In Ruby a method call is allowed to have no parentheses, therefore I should name the local variable into something else, otherwise Ruby will recognize it as a method call.
在 Ruby 中,方法调用允许没有括号,因此我应该将局部变量命名为其他名称,否则 Ruby 会将其识别为方法调用。

