Rails 3は属性が変更されたかどうかを確認します


153

Rails 3で更新する前に、属性のブロックが変更されたかどうかを確認する必要があります。

street1、street2、city、state、zipcode

私は次のようなものを使用できることを知っています

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

しかし、そのコードは本当に長くなります。よりクリーンな方法はありますか?

回答:


282

ActiveModel :: Dirtyをチェックしてください(デフォルトですべてのモデルで利用可能)。ドキュメントは本当に良いですが、次のようなことができます:

@user.street1_changed? # => true/false

属性がフォームで変更されたかどうかを確認しようとしている場合、これは役に立ちません(OPが実行しているように見えます)。
Mark Fraser

8
もちろんです。paramsハッシュを使用して値を割り当てる場合、これらはフォームから取得されています。
Peter Brown

私がこのようなことをしたい場合:model.collection.changed_size_by?または何か
マウロディアス2013年

@MauroDiasは、そのようなコレクションプロパティを追跡するために独自のロジックを記述する必要があります。
Peter Brown

私はこれのためにいくつかのテストlibを使用するつもりです。とにかくTY
Mauro Dias '17年

54

これが、複数の属性の変更をチェックする問題を解決した方法です。

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

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

このchangedメソッドは、そのオブジェクトに対して変更された属性の配列を返します。

@user.changedattrsは両方とも配列なので、交差点を取得できます(ary & other aryメソッドを参照)。交差の結果は配列です。any?配列を呼び出すことにより、交差が少なくとも1つある場合はtrueになります。

また、このchanged_attributesメソッドは非常に便利です。メソッドは、属性のハッシュを元の値とともにchanges返し、は元の値と新しい値を含む属性のハッシュを(配列で)返します。

APIDockで、これらのメソッドをサポートしているバージョンを確認できます。

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


1
これは良い方法です。歴史的に私if attrs.any?{|attr| @user.send("#{attr}_changed?")}はいくつかの異なる属性の1つが変更されたかどうかを確認したいときに行いました-もちろん、これは自分で定義した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これはデフォルトでも利用可能です。
Jason Galuten、2015年

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

上記の回答の方が優れていますが、知識を得るために別のアプローチもあります。オブジェクト(@design)の列の値を変更してみましょう。

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

.changesは、キーを列の名前として、値を配列として、各列に2つの値[old_value、new_value]を含むハッシュを返します。たとえば、上記のカテゴリは、@ designの「ABC」から「XYZ」に変更されます。

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

RORでの参照の変更

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.