仅当Rails中的属性已更改时才运行回调


93

我的应用程序具有以下关联:

# Page 
belongs_to :status

我想运行一个回调任何时候status_idpage改变。

因此,如果page.status_id从4变到5,我希望能够抓住这一点。

怎么做?

Answers:


197

Rails 5.1+

class Page < ActiveRecord::Base
  before_save :do_something, if: :will_save_change_to_status_id?

  private

  def do_something
    # ...
  end
end

更改了ActiveRecord :: Dirty的提交在这里:https : //github.com/rails/rails/commit/16ae3db5a5c6a08383b974ae6c96faac5b4a3c81

这是有关这些更改的博客文章:https : //www.ombulabs.com/blog/rails/upgrades/active-record-5-1-api-changes.html

这是我为自己对ActiveRecord :: Dirty in Rails 5.1+所做的更改的摘要:

ActiveRecord ::脏

https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html

保存之前(可选更改)

修改对象之后,然后保存到数据库中或在before_save过滤器中:

  • changes 现在应该是 changes_to_save
  • changed? 现在应该是 has_changes_to_save?
  • changed 现在应该是 changed_attribute_names_to_save
  • <attribute>_change 现在应该是 <attribute>_change_to_be_saved
  • <attribute>_changed? 现在应该是 will_save_change_to_<attribute>?
  • <attribute>_was 现在应该是 <attribute>_in_database

保存后(BREAKCHANGE CHANGE)

修改对象并保存到数据库后,或在after_save过滤器中:

  • saved_changes(代替previous_changes
  • saved_changes?
  • saved_change_to_<attribute>
  • saved_change_to_<attribute>?
  • <attribute>_before_last_save

导轨<= 5.0

class Page < ActiveRecord::Base
  before_save :do_something, if: :status_id_changed?

  private

  def do_something
    # ...
  end
end

这利用了以下事实:before_save回调可以基于方法调用的返回值有条件地执行。该status_id_changed?方法来自ActiveModel :: Dirty,它允许我们通过简单地附加_changed?到属性名称来检查特定属性是否已更改。

何时do_something应调用该方法取决于您的需要。它可以是before_saveafter_save任何已定义的ActiveRecord :: Callbacks


4
在较新的版本中不建议使用此解决方案。
Mateus Luiz

6
更新了Rails 5.1+信息。
pdobb


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.