Rails 3检查属性是否已更改


153

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

street1,street2,城市,州,邮政编码

我知道我可以使用类似

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

但是那段代码真的很长。有没有更清洁的方法?

Answers:


282

ActiveModel :: Dirty(默认情况下在所有模型上都可用)。该文档确实很好,但是它可以让您执行以下操作:

@user.street1_changed? # => true/false

如果您尝试查看属性是否以某种形式更改(这似乎是OP所做的事情),这将无济于事。
Mark Fraser 2013年

8
当然可以。如果使用params哈希分配值,则这些值来自表单。
彼得·布朗

如果我想做这样的事情怎么办:model.collection.changed_size_by?或类似的东西
Mauro Dias

@MauroDias,您必须编写自己的逻辑来跟踪类似的集合属性。
彼得·布朗

我将尝试为此使用一些测试库。可能是一个解决办法,反正TY
毛罗·迪亚斯

54

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

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

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

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

两个@user.changedattrs是数组因此可以得到的交叉点(参见ary & other ary方法)。相交的结果是一个数组。通过调用any?数组,我知道是否存在至少一个交集。

changed_attributes方法也非常有用,它返回属性的哈希值及其原始值,并changes返回属性的哈希值及其原始值和新值(在数组中)。

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

http://apidock.com/rails/ActiveModel/肮脏


1
这是一个很好的方法。从历史上看,我已经完成了if attrs.any?{|attr| @user.send("#{attr}_changed?")}当我想检查几个不同属性中的一个是否已更改时-当然,我只使用自己定义的attrs进行此操作,因为我不喜欢将用户参数放入send方法中。;)
nzifnab 2013年

14

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

如果您尝试检测许多属性更改,则可能会变得混乱。可能不应该在控制器中执行此操作,但是。


9
对于它的价值,您可以执行此操作,previous_changes默认情况下也可用。
杰森·加卢滕

2
#update_attributes不会隐藏更改。它保存了记录,因此模型已更新且没有更改。您需要更改模型中的字段并changed?在保存之前进行检查。即。@ model.field ='foo'或@model.attributes = @model.attributes.merge(params[:model])
Grzegorz

9

对于Rails 5.1+回调

从Ruby on Rails 5.1开始,attribute_changed?attribute_wasActiveRecord方法将被弃用

使用saved_change_to_attribute?代替attribute_changed?

@user.saved_change_to_street1? # => true/false

这里有更多例子


2

上面的答案更好,但就我们所知,我们还有另一种方法,让对象的“ catagory”列值更改(@design),

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

.changes将返回一个哈希,其键为列名,值作为一个数组,每列具有两个值[old_value,new_value]。例如,上述类别从@design的“ ABC”更改为“ XYZ”,

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

供参考,以更改ROR

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.