Jos*_*ogi 190 activerecord ruby-on-rails
我想通过在ActiveRecord中定义属性来为属性创建默认值.默认情况下,每次创建记录时,我都想拥有属性的默认值:status
.我试着这样做:
class Task < ActiveRecord::Base
def status=(status)
status = 'P'
write_attribute(:status, status)
end
end
Run Code Online (Sandbox Code Playgroud)
但是在创建时我仍然从数据库中检索此错误:
ActiveRecord::StatementInvalid: Mysql::Error: Column 'status' cannot be null
Run Code Online (Sandbox Code Playgroud)
因此我假设该值未应用于该属性.
在Rails中这样做的优雅方法是什么?
非常感谢.
Jim*_*Jim 287
您可以在迁移中为列设置默认选项
....
add_column :status, :string, :default => "P"
....
Run Code Online (Sandbox Code Playgroud)
要么
你可以使用回调, 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
Run Code Online (Sandbox Code Playgroud)
Bee*_*Dog 192
因为我刚才遇到过这个问题,并且Rails 3.0的选项有点不同,我将为这个问题提供另一个答案.
在Rails 3.0中,你想做这样的事情:
class MyModel < ActiveRecord::Base
after_initialize :default_values
private
def default_values
self.name ||= "default value"
end
end
Run Code Online (Sandbox Code Playgroud)
Tim*_*ord 83
当我需要默认值时,它通常用于渲染新操作视图之前的新记录.以下方法将仅为新记录设置默认值,以便在呈现表单时可用.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
Run Code Online (Sandbox Code Playgroud)
小智 77
您可以在不编写任何代码的情况下执行此操作:)您只需在数据库中设置列的默认值即可.您可以在迁移中执行此操作.例如:
create_table :projects do |t|
t.string :status, :null => false, :default => 'P'
...
t.timestamps
end
Run Code Online (Sandbox Code Playgroud)
希望有所帮助.
EmF*_*mFi 22
解决方案取决于一些事情.
默认值是否依赖于创建时可用的其他信息?你可以用最小的后果擦除数据库吗?
如果您回答第一个问题,那么您想使用Jim的解决方案
如果您回答第二个问题,那么您想使用Daniel的解决方案
如果对这两个问题的回答都是"否",那么最好添加和运行新的迁移.
class AddDefaultMigration < ActiveRecord::Migration
def self.up
change_column :tasks, :status, :string, :default => default_value, :null => false
end
end
Run Code Online (Sandbox Code Playgroud)
:string可以替换为ActiveRecord :: Migration识别的任何类型.
CPU很便宜,所以在Jim的解决方案中重新定义Task不会导致很多问题.特别是在生产环境中.这种迁移是正确的方式,因为它加载它并且不常调用.
swa*_*pab 10
只是加强吉姆的答案
使用存在可以做到
class Task < ActiveRecord::Base
before_save :default_values
def default_values
self.status = status.presence || 'P'
end
end
Run Code Online (Sandbox Code Playgroud)
对于列类型 Rails 支持开箱即用 - 就像这个问题中的字符串 - 最好的方法是在数据库本身中设置列默认值,如 Daniel Kristensen 指出的那样。Rails 将内省数据库并相应地初始化对象。另外,这使您的数据库免受有人在您的 Rails 应用程序之外添加一行并忘记初始化该列的影响。
对于列类型 Rails 不支持开箱即用 - 例如 ENUM 列 - Rails 将无法自省列默认值。对于这些情况下,你不希望使用after_initialize(它被称为每一个对象从数据库加载以及对象使用。新创建的每个时间的时间),before_create(因为它验证后出现),或before_save(因为它也会在更新时发生,这通常不是您想要的)。
相反,您希望在 before_validation on: create 中设置属性,如下所示:
before_validation :set_status_because_rails_cannot, on: :create
def set_status_because_rails_cannot
self.status ||= 'P'
end
Run Code Online (Sandbox Code Playgroud)
在我看来,当需要默认值时,有两个问题需要解决。
这是我的解决方案:
# 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
Run Code Online (Sandbox Code Playgroud)
我很想知道为什么人们会想到这种方法。
归档时间: |
|
查看次数: |
190509 次 |
最近记录: |