我想在rails中创建一个回调函数,该函数在保存模型后执行。
我有这个模型,声明具有属性'status',该属性根据声明的状态而变化,可能的值是待定,已批准,已批准,已拒绝
数据库具有'state',其默认值为'pending'。
我想在第一次创建模型或从一个状态更新到另一个状态后执行某些任务,具体取决于它从哪个状态更改。
我的想法是在模型中有一个功能:
after_save :check_state
def check_state
# if status changed from nil to pending (created)
do this
# if status changed from pending to approved
performthistask
end
我的问题是如何在模型中更改之前检查以前的值?
答案 0 :(得分:166)
您应该查看ActiveModel::Dirty模块: 您应该能够对您的声明模型执行以下操作:
claim.status_changed? # returns true if 'status' attribute has changed
claim.status_was # returns the previous value of 'status' attribute
claim.status_change # => ['old value', 'new value'] returns the old and
# new value for 'status' attribute
claim.name = 'Bob'
claim.changed # => ["name"]
claim.changes # => {"name" => ["Bill", "Bob"]}
哦! Rails的乐趣!
答案 1 :(得分:36)
你可以用这个
self.changed
它返回在此记录中更改的所有列的数组
您也可以使用
self.changes
返回已更改的列的哈希值以及结果之前和之后的列数
答案 2 :(得分:3)
答案 3 :(得分:1)
对于Rails 5.1+,您应该使用活动记录属性方法。
saved_change_to_attribute?(attr_name,** options)`
上次保存时此属性是否更改?这种方法可以 以
saved_change_to_name?
而不是saved_change_to_attribute?("name")
。行为类似于attribute_changed?
。此方法在回调到 确定保存调用是否更改了某个属性。选项
from
传递时,此方法将返回false,除非原始 值等于给定的选项
to
传递时,除非该值是 更改为给定值
如果您要基于属性值的更改来调用某些方法,那么您的模型将如下所示:
class Claim < ApplicationRecord
after_save: :do_this, if: Proc.new { saved_change_to_status?(from: nil, to: 'pending') }
after_save: :do_that, if: Proc.new { saved_change_to_status?(from: 'pending', to: 'approved') }
def do_this
..
..
end
def do_that
..
..
end
end
如果不想在回调中检查值的变化,可以执行以下操作:
class Claim < ApplicationRecord
after_save: :do_this, if: saved_change_to_status?
def do_this
..
..
end
end
答案 4 :(得分:0)
我已经看到很多地方出现了这个问题,所以我为它编写了一个小小的rubygem,使代码更好一些(并避免在所有地方使用百万if / else语句):https://github.com/ronna-s/on_change。 我希望有所帮助。
答案 5 :(得分:0)
使用经过良好测试的解决方案(例如state_machine gem。
)会更好