Ruby-on-rails 如何检测模型的属性变化?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1586536/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to detect attribute changes from model?
提问by David C
I'd like to create a callback function in rails that executes after a model is saved.
我想在保存模型后执行的 rails 中创建一个回调函数。
I have this model, Claim that has a attribute 'status' which changes depending on the state of the claim, possible values are pending, endorsed, approved, rejected
我有这个模型,Claim 有一个属性“status”,它根据索赔的状态而变化,可能的值是待定的、认可的、批准的、拒绝的
The database has 'state' with the default value of 'pending'.
数据库有'state',默认值为'pending'。
I'd like to perform certain tasks after the model is created on the first time or updated from one state to another, depending on which state it changes from.
我想在第一次创建模型或从一个状态更新到另一个状态后执行某些任务,具体取决于它从哪个状态更改。
My idea is to have a function in the model:
我的想法是在模型中有一个函数:
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
My question is how do I check for the previous value before the change within the model?
我的问题是如何在模型内更改之前检查先前的值?
回答by Harish Shetty
You should look at ActiveModel::Dirtymodule: You should be able to perform following actions on your Claim model:
您应该查看ActiveModel::Dirty模块:您应该能够对您的 Claim 模型执行以下操作:
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"]}
Oh! the joys of Rails!
哦!Rails 的乐趣!
回答by zeacuss
you can use this
你可以用这个
self.changed
it return an array of all columns that changed in this record
它返回此记录中更改的所有列的数组
you can also use
你也可以使用
self.changes
which returns a hash of columns that changed and before and after results as arrays
它以数组形式返回更改前后的列的哈希值
回答by Toby Hede
I recommend you have a look at one of the available state machine plugins:
我建议您查看可用的状态机插件之一:
Either one will let you setup states and transitions between states. Very useful and easy way of handling your requirements.
任何一种都可以让您设置状态和状态之间的转换。处理您的要求非常有用和简单的方法。
回答by Rajkaran Mishra
For Rails 5.1+, you should use active record attribute method: saved_change_to_attribute?
对于 Rails 5.1+,您应该使用活动记录属性方法:saved_change_to_attribute?
saved_change_to_attribute?(attr_name, **options)`
Did this attribute change when we last saved? This method can be invoked as
saved_change_to_name?instead ofsaved_change_to_attribute?("name"). Behaves similarly toattribute_changed?. This method is useful in after callbacks to determine if the call to save changed a certain attribute.Options
fromWhen passed, this method will return false unless the original value is equal to the given option
toWhen passed, this method will return false unless the value was changed to the given value
saved_change_to_attribute?(属性名称,**选项)`
我们上次保存时这个属性有变化吗?可以调用此方法
saved_change_to_name?而不是saved_change_to_attribute?("name")。行为类似于attribute_changed?。此方法在回调之后确定保存调用是否更改了某个属性时很有用。选项
from传递时,除非原始值等于给定选项,否则此方法将返回 false
to传递时,除非将值更改为给定值,否则此方法将返回 false
So your model will look like this, if you want to call some method based on the change in attribute value:
所以你的模型看起来像这样,如果你想根据属性值的变化调用一些方法:
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
And if you don't want to check for value change in callback, you can do the following::
如果您不想检查回调中的值更改,您可以执行以下操作:
class Claim < ApplicationRecord
after_save: :do_this, if: saved_change_to_status?
def do_this
..
..
end
end
回答by Ronna
I've seen the question rise in many places, so I wrote a tiny rubygem for it, to make the code a little nicer (and avoid a million if/else statements everywhere): https://github.com/ronna-s/on_change. I hope that helps.
我在很多地方都看到了这个问题,所以我为它写了一个小小的 rubygem,使代码更好一点(并避免到处都有一百万个 if/else 语句):https: //github.com/ronna-s /on_change。我希望这有帮助。
回答by Paz Aricha
You will be much better off using a well tested solution such as the state_machinegem.
使用经过充分测试的解决方案(例如state_machinegem)会好得多。

