179

我在我的模型观察者中设置了一个 after_save 回调,以仅在模型的发布属性从 false 更改为 true 时发送通知。既然方法等变了?仅在保存模型之前有用,我目前(但未成功)尝试这样做的方式如下:

def before_save(blog)
  @og_published = blog.published?
end

def after_save(blog)
  if @og_published == false and blog.published? == true
    Notification.send(...)
  end
end

是否有人对处理此问题的最佳方法有任何建议,最好使用模型观察者回调(以免污染我的控制器代码)?

4

7 回答 7

233

导轨 5.1+

使用saved_change_to_published?

class SomeModel < ActiveRecord::Base
  after_update :send_notification_after_change

  def send_notification_after_change
    Notification.send(…) if (saved_change_to_published? && self.published == true)
  end

end

或者,如果您愿意,saved_change_to_attribute?(:published).

导轨 3–5.1

警告

这种方法适用于 Rails 5.1(但在 5.1 中已弃用,并且在 5.2 中有重大更改)。您可以阅读有关此拉取请求中的更改。

after_update模型上的过滤器中,您可以使用_changed?访问器。例如:

class SomeModel < ActiveRecord::Base
  after_update :send_notification_after_change

  def send_notification_after_change
    Notification.send(...) if (self.published_changed? && self.published == true)
  end

end

它只是工作。

于 2010-10-05T08:09:06.977 回答
204

对于那些想知道刚刚在after_save回调中所做的更改的人:

Rails 5.1 及更高版本

model.saved_changes

导轨 < 5.1

model.previous_changes

另请参阅:http ://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-previous_changes

于 2013-12-18T12:08:35.480 回答
78

对于以后看到这一点的任何人,因为它目前(2017 年 8 月)在谷歌上名列前茅:值得一提的是,这种行为将在Rails 5.2中改变,并且从 Rails 5.1 开始有弃用警告,因为ActiveModel::Dirty发生了一些变化.

我要改变什么?

如果您attribute_changed?在 -callbacks 中使用方法after_*,您将看到如下警告:

弃用警告:attribute_changed?inside of after 回调的行为将在下一版本的 Rails 中改变。新的返回值将反映返回后调用方法的行为save(例如,与现在返回的相反)。要保持当前行为,请saved_change_to_attribute?改用。(从 /PATH_TO/app/models/user.rb:15 的 some_callback 调用)

正如它所提到的,您可以通过将函数替换为saved_change_to_attribute?. 例如,name_changed?变成saved_change_to_name?.

同样,如果您使用attribute_change来获取前后值,这也会发生变化并抛出以下内容:

弃用警告:attribute_changeinside of after 回调的行为将在下一版本的 Rails 中改变。新的返回值将反映返回后调用方法的行为save(例如,与现在返回的相反)。要保持当前行为,请saved_change_to_attribute改用。(从 /PATH_TO/app/models/user.rb:20 的 some_callback 调用)

同样,正如它所提到的,该方法将名称更改为saved_change_to_attribute返回["old", "new"]。或 use saved_changes,它返回所有更改,这些更改可以作为saved_changes['attribute'].

于 2017-08-03T19:45:24.010 回答
49

如果您可以在before_save而不是 上执行此操作after_save,您将可以使用它:

self.changed

它返回此记录中所有已更改列的数组。

您还可以使用:

self.changes

它返回作为数组更改的列的哈希值以及结果之前和之后

于 2012-05-27T11:42:08.213 回答
8

“选定”的答案对我不起作用。我正在使用带有 CouchRest::Model 的 rails 3.1(基于 Active Model)。对于钩子中的更改属性,这些_changed?方法不会返回 true after_update,仅在before_update钩子中。around_update我能够使用(新?)钩子让它工作:

class SomeModel < ActiveRecord::Base
  around_update :send_notification_after_change

  def send_notification_after_change
    should_send_it = self.published_changed? && self.published == true

    yield

    Notification.send(...) if should_send_it
  end

end
于 2012-02-10T19:53:32.263 回答
6

你可以after_update像这样添加一个条件:

class SomeModel < ActiveRecord::Base
  after_update :send_notification, if: :published_changed?

  ...
end

无需在send_notification方法本身中添加条件。

于 2017-08-15T18:18:23.900 回答
-20

您只需添加一个访问者来定义您更改的内容

class Post < AR::Base
  attr_reader :what_changed

  before_filter :what_changed?

  def what_changed?
    @what_changed = changes || []
  end

  after_filter :action_on_changes

  def action_on_changes
    @what_changed.each do |change|
      p change
    end
  end
end
于 2010-10-05T08:08:29.110 回答