2009-10-03 28 views
17

私はActiveRecord :: Dirtyとそれに関連するメソッドを認識していますが、属性が変更されたイベントを購読する手段はありません。何かが好きです:変更されたActiveRecord属性のコールバック?

class Person < ActiveRecord::Base 
    def attribute_changed(attribute_name, old_value, new_value) 
    end 

    #or 

    attribute_changed do |attribute_name, old_value, new_value| 
    end 
end 

このための標準またはプラグインはありますか?私はそれがどこかに存在しなければならないと感じ、私はただそれを逃しています。

答えて

18

cwninjaの答えは、トリックを行う必要がありますが、少しそれがあります。

まず、基本属性の処理はwrite_attributeメソッドで行われるため、これをタップする必要があります。

また、Railsにはコールバック構造が組み込まれていますが、邪魔にならない引数を渡すことはできませんが、タップするのがいいかもしれません。あなたはこのようにそれを行うことができますカスタムコールバックを使用して

:あなたは(あなたが複数のコールバックおよび/またはサブクラスを持っている可能性がある場合に特に便利)Railsのコールバックを使用しようと思った場合は

class Person < ActiveRecord::Base 

    def write_attribute(attr_name, value) 
    attribute_changed(attr_name, read_attribute(attr_name), value) 
    super 
    end 

    private 

    def attribute_changed(attr, old_val, new_val) 
     logger.info "Attribute Changed: #{attr} from #{old_val} to #{new_val}" 
    end 

end 

をあなたはこのような何かを行うことができます:

class Person < ActiveRecord::Base 
    define_callbacks :attribute_changed 

    attribute_changed :notify_of_attribute_change 

    def write_attribute(attr_name, value) 
    returning(super) do 
     @last_changed_attr = attr_name 
     run_callbacks(:attribute_changed) 
    end 
    end 

    private 

    def notify_of_attribute_change 
     attr = @last_changed_attr 
     old_val, new_val = send("#{attr}_change") 
     logger.info "Attribute Changed: #{attr} from #{old_val} to #{new_val}" 
    end 

end 
+0

ピーター、それは美しいです、私は "write_attribute"のトンを節約しようとしている私はすべてのコードを散らしている。ありがとう! – BushyMark

+0

これはRails 2専用です。 – lulalala

+0

日付を確認せずにgoogle経由でこれに来ました。この最近のウォークスルーは、私が必要としていたことを行いました。[after_callbacksでモデルの変更を追跡する方法](http://ruby-journal.com/how-to-track-changes-with-after-callbacks-in- rails-3-or-newer /) – Jay

5

試してみてください。

def attribute_changed(attribute_name, old_value, new_value) 
end 

def attribute=(attribute_name, value) 
    returning(super) do 
    attribute_changed(attribute_name, attribute_was(attribute_name), attribute(attribute_name)) 
    end 
end 

はちょうど今、これを発明し、それが動作するはずです。

+0

私に正しい道を教えてくれてありがとう。 – Mario

3

あなたは常にプライベートメソッドchanged_attributesにアクセスし、before_saveを使用してそこにキーをチェックして、何がするそれを行うことができます。 Railsの3のために

14

:にコメント

class MyModel < ActiveRecord::Base 
    after_update :my_listener, :if => :my_attribute_changed? 

    def my_listener 
    puts "Attribute 'my_attribute' has changed" 
    end 
end 

https://stackoverflow.com/a/1709956/316700

私はこのことについて公式ドキュメントを見つけることができません。

+2

私は、属性がメモリ内で変更されるとすぐにメソッドが呼び出されることを望んでいると思います。つまり、保存が呼び出される前です。つまり、 'my_object.some_attr =" foo "'はコールバックを生成します。 – MikeJ

+0

'after_update'はレール2.3(http://apidock.com/rails/ActiveRecord/Callbacks/after_update)以来非推奨です – schmijos

2

私が見つけた最も簡単な方法:Railsの4

def attribute=(value) 
    super(value) 
    your_callback(self.attribute) 
end 

については

after_save :my_method, :if => Proc.new{ self.my_attribute_changed? } 

def my_method 
    ... do stuff... 
end 
+1

after_save:my_method、if if>>:my_attribute_changed? –

+0

nice!それはさらに良い:) – pesta

8

あなたは属性の値を上書きしたい場合は、write_attribute(:attribute, your_callback(self.attribute))なくattribute=かを使用する必要がありますループは終わりましたよあまりにも深い例外をスタックするまで。

関連する問題