Rails 3检查属性是否已更改

pca*_*asa 149 ruby-on-rails ruby-on-rails-3

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

street1,street2,city,state,zipcode

我知道我可以使用类似的东西

if @user.street1 != params[:user][:street1]
  then do something....
end
Run Code Online (Sandbox Code Playgroud)

但这段代码真的很长.有更干净的方式吗?

Pet*_*own 275

查看ActiveModel :: Dirty(默认情况下适用于所有型号).文档非常好,但它可以让您执行以下操作:

@user.street1_changed? # => true/false
Run Code Online (Sandbox Code Playgroud)

  • 当然可以.如果使用params散列分配值,则这些值来自表单. (7认同)
  • 如果您试图查看表单中的属性是否已更改(这似乎是OP正在做的事情),这并没有帮助。 (2认同)

cam*_*son 54

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

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

if (@user.changed & attrs).any?
  then do something....
end
Run Code Online (Sandbox Code Playgroud)

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

两个@user.changedattrs是数组因此可以得到的交叉点(参见ary & other ary方法).交集的结果是一个数组.通过调用any?数组,如果至少有一个交集,我就会得到.

同样非常有用的changed_attributes方法是,该方法返回属性的散列及其原始值,并changes返回属性的散列及其原始值和新值(在数组中).

您可以检查APIDock支持这些方法的版本.

http://apidock.com/rails/ActiveModel/Dirty


ham*_*tar 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
Run Code Online (Sandbox Code Playgroud)

如果你试图检测很多属性变化,它可能会变得混乱.可能不应该在控制器中这样做,但是meh.

  • 对于它的价值,您可以使用`previous_changes`来执行此操作,默认情况下也可以使用. (8认同)
  • `#update_attributes`不会隐藏更改.它会保存记录,因此模型会更新,并且不会发生任何更改.在保存之前,您需要更改模型中的字段并检查"已更改?".即.@ model.field ='foo'或`@model.attributes = @ model.attributes.merge(params [:model])` (2认同)

Luc*_*ade 6

对于Rails 5.1+回调

为了改善这篇文章并完成其他答案

对于下一个Rails版本(5.1之后)的回调,不建议使用第一个答案。
因此,检查属性是否已更改的新方法是使用save_change_to_attribute?

你可以做:

@user.saved_change_to_street1? # => true/false
Run Code Online (Sandbox Code Playgroud)

您可以在此博文中查看更多示例