如何从模型中检测属性更改?

时间:2009-10-19 01:10:08

标签: ruby-on-rails

我想在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

我的问题是如何在模型中更改之前检查以前的值?

6 个答案:

答案 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。

)会更好