确定Rails after_savecallback中哪些属性发生了变化?

我在模型观察者中设置after_savecallback,只有当模型的发布属性从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 

有没有人有任何build议,以最好的方式来处理,最好使用模型观察callback(以免污染我的控制器代码)?

在模型的after_updatefilter中,您可以使用_changed? accessor(至less在Rails 3中,不知道Rails 2)。 举个例子:

 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 

它只是工作。

对于那些想知道保存后的变化,你应该使用

 model.previous_changes 

这工作像model.change但它仍然工作model.save等。我觉得这个信息很有用,所以也许你也会。

在Rails 5.1+中已经弃用了。 saved_changesafter_savecallback中使用saved_changes

如果你可以在before_save而不是after_save上做到这一点,你可以使用这个:

 self.changed 

它将返回此logging中所有已更改列的数组。

你也可以使用:

 self.changes 

它返回一个散列的变化,并在结果之前和之后作为数组

对任何人来说,今天(2017年8月)tops谷歌:值得一提的是,这种行为将被改变在Rails 5.2 ,并有Rails 5.1的弃用警告,因为ActiveModel ::脏改变了一点。

我该怎么改变?

如果你使用的是attribute_changed? 方法在after_* ,你会看到一个警告,如:

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

正如它提到的,你可以通过用saved_change_to_attribute?replace函数来修复这个saved_change_to_attribute? 。 那么例如, name_changed? 变成saved_change_to_name?

同样,如果您使用attribute_change来获取之前的值,这也会改变,并引发以下内容:

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

同样,它提到,方法改名为saved_change_to_attribute返回["old", "new"] 。 或者使用saved_changes ,它将返回所有的变化,这些变化可以作为saved_changes['attribute']被访问。

“选定”的答案不适合我。 我使用CouchRest :: Model(基于Active Model)的rails 3.1。 _changed? 方法不会在after_update挂钩中对已更改的属性返回true,而只会在before_update挂钩中返回true。 我能够得到它使用(新?) 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 

我正在使用这个来提取一个新的属性值的哈希值,这对我来说更新其他模型是有用的

 attributes_changed = self.changes.inject(Hash.new){|hash,attr| ((hash[attr[0].to_sym] = attr[1].last) || attr[1].last == false) && hash} 

 attr[1].last == false 

当新值为false ,需要返回false并且不返回“hash”。

我想有一个更简单的方法,我是新来的铁轨

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

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

send_notification方法本身不需要添加条件。

您只需添加一个定义您所做更改的访问者

 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