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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 21:52:25  来源:igfitidea点击:

How to detect attribute changes from model?

ruby-on-rails

提问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 of saved_change_to_attribute?("name"). Behaves similarly to attribute_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.

我在很多地方都看到了这个问题,所以我为它写了一个小小的 ruby​​gem,使代码更好一点(并避免到处都有一百万个 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)会好得多