【问题标题】:In a Rails ActiveRecord model, is using after_initialize callbacks a very bad idea?在 Rails ActiveRecord 模型中,使用 after_initialize 回调是一个非常糟糕的主意吗?
【发布时间】:2014-02-15 03:27:26
【问题描述】:

假设我们有这个模型

class Account < ActiveRecord::Base
  after_initialize :set_name

  def set_name
    self.name = ‘My Account’
  end
end

现在我想运行一个查询,它只返回模型的一些属性而不是全部,特别是不返回它在 after_initialize 回调中使用的“名称”属性

Account.group(:name).select("count(*), id").first

然后此执行引发以下错误,因为 set_name 回调使用的属性尚未“加载”或未选择到查询返回的记录中。

ActiveModel::MissingAttributeError: missing attribute: name

幸运的是,对于某些特定情况,我可以执行相同的 sql 查询,而完全不使用 Account 模型来获得所需的结果

sql = Account.group(:name).select("count(*), id").to_sql
ActiveRecord::Base.connection.execute(sql).first
=> #<Mysql2::Result:0x00000106eddbc0>

但重点是,如果我想获取 Account 对象而不是 Mysql2::Result 对象怎么办? .select 方法是否应该返回具有所有属性的“完整”对象(例如,用 Nil 填充缺失的列)?或者对我们的 ActiveRecord 模型使用 after_initialize 回调是一个非常糟糕的主意?当然,我们也可以在回调中添加一些代码来检查属性是否存在,但在我看来,这在 OO 语言中是不自然的或听起来很奇怪。

【问题讨论】:

  • 请仔细阅读这个问题,因为它不是那么简单,我相信答案不是那么简单。让我知道你的想法。

标签: sql ruby-on-rails ruby-on-rails-3 activerecord callback


【解决方案1】:

after_initialize 的大多数用法可以(并且应该)替换为相应数据库列上的默认值。如果您将该属性设置为一个常量值,您可能希望将其作为替代方案。

编辑:如果值不是常量,则调用 has_attribute?(:name) 将防止出现此错误 - ActiveModel::MissingAttributeError occurs after deploying and then goes away after a while

【讨论】:

  • 想象一下,回调方法根据名称字段检查条件,而不是放置默认名称。我们仍然有同样的问题if self.name == .... 会引发和异常。
【解决方案2】:

不,这不是一个坏主意,事实上我在工作中经常使用它。有效的用例是当您希望代码在您尝试对对象执行任何操作之前运行。以下是提供的一些过滤器的细分。

# Before you intend to do anything with the object
after_initialize

# Before you intend to save the object
before_save

# After you've saved the object
after_save

# Before you save a new record
before_create

# After you create a new object
after_create

【讨论】:

  • 因为“在你打算对对象做任何事情之前”,如果你像我展示的那样运行一个查询,它会引发错误。
猜你喜欢
  • 2018-08-17
  • 2010-09-10
  • 2011-08-16
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-08
  • 2013-07-15
相关资源
最近更新 更多