如何在ActiveRecord中设置默认值?

我看到Pratik的一篇帖子,描述了一段丑陋而复杂的代码:http://m.onkey.org/2007/7/24/how-to-set-default-values-in-your-model

class Item < ActiveRecord::Base  
  def initialize_with_defaults(attrs = nil, &block)
    initialize_without_defaults(attrs) do
      setter = lambda { |key, value| self.send("#{key.to_s}=", value) unless
        !attrs.nil? && attrs.keys.map(&:to_s).include?(key.to_s) }
      setter.call('scheduler_type', 'hotseat')
      yield self if block_given?
    end
  end
  alias_method_chain :initialize, :defaults
end

我在谷歌上看到了以下例子:

  def initialize 
    super
    self.status = ACTIVE unless self.status
  end

  def after_initialize 
    return unless new_record?
    self.status = ACTIVE
  end

我也见过人们在迁移中使用它,但我更希望看到它在模型代码中定义.

是否有一种规范的方法来设置ActiveRecord模型中字段的默认值?

推荐答案

每种可用方法都有几个问题,但我认为定义after_initialize回调是一种可行的方法,原因如下:

  1. default_scope将初始化新模型的值,但这将成为您找到模型的范围.如果你只想将一些数字初始化为0,那么这就是你想要的.
  2. 在迁移中定义默认值有时也会起作用...正如已经提到的,当你调用Model时,这将起到not个作用.刚出现的
  3. 覆盖initialize可以工作,但别忘了拨打super
  4. 使用像phusion这样的插件有点荒谬.这是ruby,我们真的需要一个插件来初始化一些默认值吗?
  5. 从Rails 3开始覆盖after_initialize is deprecated.当我在rails 3.0.3中覆盖after_initialize时,控制台中会出现以下警告:

弃用警告:Base#在_initialize被弃用后,请使用Base.在初始化之后:改为方法.(从/Users/me/myapp/app/models/my_model:15调用)

因此,我建议编写一个after_initialize回调函数,它允许您设置默认属性in addition to,允许您设置如下关联的默认值:

  class Person < ActiveRecord::Base
    has_one :address
    after_initialize :init

    def init
      self.number  ||= 0.0           #will set the default value only if it's nil
      self.address ||= build_address #let's you set a default association
    end
  end    

现在,您有just one个位置可以查找模型的初始化.我一直在用这个方法,直到有人想出更好的方法.

注意事项:

  1. 对于布尔字段,请执行以下操作:

    self.bool_field = true if self.bool_field.nil?

    更多细节请参见保罗·拉塞尔对这个答案的 comments

  2. 如果只为模型 Select 列的子集(例如,在像Person.select(:firstname, :lastname).all这样的查询中使用select),如果init方法访问未包含在select子句中的列,则会得到MissingAttributeError.你可以这样预防这种情况:

    self.number ||= 0.0 if self.has_attribute? :number

    对于布尔列...

    self.bool_field = true if (self.has_attribute? :bool_value) && self.bool_field.nil?

    还要注意的是,在Rails 3.2之前,语法是不同的(参见下面Cliff Darling的 comments )

Ruby-on-rails相关问答推荐

使用Hotwire/Turbo的Rails在链接悬停时获取请求

无法安装Ruby错误运行';__rvm_make-J4';,

使用嵌套属性时如何自动将父 ID 分配为外键?

Rails 3.1 assets资源 - 奇怪的开发服务

如何将实例变量传递给 RSpec 共享示例

在允许用户使用设计(rails)登录之前判断用户是否处于活动状态

耙路由错误缺少:路由定义上的操作键

activerecord 查找所有未包含在数组中的内容

Rails 成语避免在 has_many 中重复:通过

如何解决弃用警告方法 to_hash 已弃用并将在 Rails 5.1 中删除

如何显示 RSpec 测试生成的 SQL 查询日志(log)?

关于在不适合任何地方的 Rails 应用程序中放置类的指南

Rails 3.0 中的 f.error_messages

Rails 5:重命名表迁移

counter_cache 实现的问题

扩展 Devise SessionsController 以使用 JSON 进行身份验证

在 Rails 3 中设置会话超时

如何使用 url 连接到 postgresql

Rails 在 id 字段上重置种子的方法

没有UTC的Rails 3默认日期时间格式