回答:
ActiveModel :: Dirtyをチェックしてください(デフォルトですべてのモデルで利用可能)。ドキュメントは本当に良いですが、次のようなことができます:
@user.street1_changed? # => true/false
これが、複数の属性の変更をチェックする問題を解決した方法です。
attrs = ["street1", "street2", "city", "state", "zipcode"]
if (@user.changed & attrs).any?
then do something....
end
このchanged
メソッドは、そのオブジェクトに対して変更された属性の配列を返します。
@user.changed
とattrs
は両方とも配列なので、交差点を取得できます(ary & other ary
メソッドを参照)。交差の結果は配列です。any?
配列を呼び出すことにより、交差が少なくとも1つある場合はtrueになります。
また、このchanged_attributes
メソッドは非常に便利です。メソッドは、属性のハッシュを元の値とともにchanges
返し、は元の値と新しい値を含む属性のハッシュを(配列で)返します。
APIDockで、これらのメソッドをサポートしているバージョンを確認できます。
if attrs.any?{|attr| @user.send("#{attr}_changed?")}
はいくつかの異なる属性の1つが変更されたかどうかを確認したいときに行いました-もちろん、これは自分で定義したattrsでのみ実行しますsend
。ユーザーパラメータをメソッドにスローするのは好きではないからです。;)
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
ただし、属性の変更をたくさん検出しようとすると、面倒になる可能性があります。おそらくコントローラーでこれを行うべきではありませんが、まあ。
previous_changes
これはデフォルトでも利用可能です。
#update_attributes
変更は非表示になりません。レコードが保存されるため、モデルが更新され、変更はありません。changed?
保存する前に、モデルのフィールドを変更して確認する必要があります。すなわち。@ model.field = 'foo'または@model.attributes = @model.attributes.merge(params[:model])
Rails 5.1以降のコールバックの場合
Ruby on Rails 5.1以降、attribute_changed?
およびattribute_was
ActiveRecordメソッドは廃止されます
のsaved_change_to_attribute?
代わりに使用attribute_changed?
@user.saved_change_to_street1? # => true/false
その他の例はこちら
上記の回答の方が優れていますが、知識を得るために別のアプローチもあります。オブジェクト(@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'] }