Rails 3检查属性是否更改

在 Rails 3中更新之前,需要检查属性块是否已更改。

1号街2号街,城市,州,邮编

我知道我可以用

if @user.street1 != params[:user][:street1]
then do something....
end

但是那段代码会很长,有没有更干净的方法?

127060 次浏览

查看 ActiveModel: : Dirty(默认情况下所有型号都可用)。文档非常好,但是它允许您执行以下操作:

@user.street1_changed? # => true/false

这就是我如何解决检查多个属性的更改的问题。

attrs = ["street1", "street2", "city", "state", "zipcode"]


if (@user.changed & attrs).any?
then do something....
end

changed方法返回为该对象更改的属性的数组。

@user.changedattrs都是数组,所以我可以得到交集(参见 ary & other ary方法)。交集的结果是一个数组。通过对数组调用 any?,如果至少有一个交集,则返回 true。

同样非常有用的是,changed_attributes方法返回具有原始值的属性的哈希值,而 changes返回具有原始值和新值的属性的哈希值(在数组中)。

您可以检查 APIDock 中哪些版本支持这些方法。

Http://apidock.com/rails/activemodel/dirty

ActiveModel::Dirty对我不起作用,因为 @model.update_attributes()隐藏了变化。这就是我如何在控制器的 update方法中检测到它的变化:

def update
@model = Model.find(params[:id])
detect_changes


if @model.update_attributes(params[:model])
do_stuff if attr_changed?
end
end


private


def detect_changes
@changed = []
@changed << :attr if @model.attr != params[:model][:attr]
end


def attr_changed?
@changed.include :attr
end

如果您试图检测大量属性更改,那么可能会出现混乱。也许不应该在控制器里这么做,但是。

以上的答案更好,但是对于知识我们还有另外一种方法, 允许更改对象的“分类”列值(@design) ,

@design.changes.has_key?('catagory')

那个。Change 将返回一个散列,其中键作为列名,值作为数组,每个列有两个值[ old _ value,new _ value ]。例如,上面的类别从“ ABC”改为@design 的“ XYZ”,

@design.changes   # => {}
@design.catagory = 'XYZ'
@design.changes # => { 'catagory' => ['ABC', 'XYZ'] }

参考资料 认可职业退休计划的修订

对于 Rails5.1 + 回调

从 Ruby on Rails 5.1开始,将不推荐使用 attribute_changed?attribute_was ActiveRecord 方法

使用 saved_change_to_attribute?代替 attribute_changed?

@user.saved_change_to_street1? # => true/false

更多例子 给你