【问题标题】:ActiveRecord callback on when object has updated virtual attribute NOT in database当对象更新虚拟属性不在数据库中时,ActiveRecord 回调
【发布时间】:2016-04-22 15:59:14
【问题描述】:

代码

# Item Model
class Item < ActiveRecord::Base
  attr_accessor :paid_amount
  after_save :amount_processed?

  def amount_processed?
    if self.try(:paid_amount)
      return true
    else
      return false
    end
  end
end

# Controller snippet
...
# params = {"paid_amount" => 10}
@item.assign_attributes(params)
if @item.valid?
  @item.save
end
...

当前回调未运行,即代码从不检查amount_processed?。发生这种情况的原因是因为paid_amount 不是Item 的数据库属性。但这是设计使然。问题是假设这个设计会保留,我是否有办法运行回调来检查amount_processed? 仅基于属性已传递的事实? (即,如果你运行@item.paid_amount,你会在@item.assign_attributes之后得到"10")。

请注意,以下回调将不起作用:

  • after_saveafter_touch 因为如上所述,paid_amount 永远不会保存,所以 @item 永远不会更新
  • after_find 因为根据定义,它在属性分配之前运行。所以通过这个验证,即使amount_processed?被选中,当它被选中时,@item.paid_amount = nil

希望将两者结合起来......

由于问题询问如何根据当前设计进行此操作,因此完全可以接受的答案是说在当前设计中,这是不可能的。只有当属性实际更新时,回调才会起作用。在这种情况下,我已经有两种策略来解决这个问题,其中最简单的是将amount_processed? 移动到控制器级别,这样我就可以在assign_attributes 之后检查paid_amount。另一种策略是有一个子项,但这取决于有关代码的其他信息,为简单起见,我保留了这些信息。

谢谢!

【问题讨论】:

  • 为什么不直接使用validate :amount_processed?。见custom validations
  • 很确定您的代码应该可以正常工作。您确定 (a) params 包含您认为它所做的并且 (b) 该实体实际上是有效的吗?如果您直接从表格或其他形式获得params,我认为您需要从params[:item] 获取值afterSave 仅仅是一个回调,它独立于任何变量。您可以抓住对象并立即调用save,然后将调用afterSave
  • @GoGoCarl after_save 不起作用的原因是paid_amount 不是Item 的数据库属性,它只是我可以访问的东西(因为attr_accessor 用户通过通过参数)。所以换句话说,如果我这样做@item.update_attributes({"paid_amount"=&gt; "10"}),回调不会运行,因为实际上没有任何更新
  • 你上面的代码是assign_attributes,这有很大的不同。
  • 呃,我收回了。应该还能工作。 update_attributes 的核心实际上只是一条捷径。检查valid?的结果

标签: ruby-on-rails activerecord callback


【解决方案1】:

好的,我想我在这里有了答案,感谢 cmets。 Willem 是对的,在当前的设计中,我可以通过使用自定义验证来确保运行 amount_processed?,将回调更改为:

validate :amount_processed?

但是,这样做会使代码有点笨拙,因为我选择了验证来完成回调的工作。换句话说,我必须确保 amount_processed? 始终返回 true(在 if 语句的末尾;显然其他工作将使用 paid_amount 完成)。还有其他一些考虑因素,以及从整体上查看我的代码。

鉴于此,可能会改变设计...但这仍然是一个非常有用的练习

【讨论】:

    猜你喜欢
    • 2016-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多