Rails 3 Observers に代わる私の方法は、モデル内で定義されたコールバックを利用する手動実装ですが、(agmin が上記の回答で述べているように)「依存関係を反転させます...カップリング」を管理します。
私のオブジェクトは、オブザーバーの登録を提供する基本クラスから継承します。
class Party411BaseModel
self.abstract_class = true
class_attribute :observers
def self.add_observer(observer)
observers << observer
logger.debug("Observer #{observer.name} added to #{self.name}")
end
def notify_observers(obj, event_name, *args)
observers && observers.each do |observer|
if observer.respond_to?(event_name)
begin
observer.public_send(event_name, obj, *args)
rescue Exception => e
logger.error("Error notifying observer #{observer.name}")
logger.error e.message
logger.error e.backtrace.join("\n")
end
end
end
end
(確かに、継承より合成の精神で、上記のコードをモジュールに配置し、各モデルに混在させることができます。)
初期化子はオブザーバーを登録します。
User.add_observer(NotificationSender)
User.add_observer(ProfilePictureCreator)
その後、各モデルは、基本的な ActiveRecord コールバックを超えて、独自の監視可能なイベントを定義できます。たとえば、私の User モデルは 2 つのイベントを公開します。
class User < Party411BaseModel
self.observers ||= []
after_commit :notify_observers, :on => :create
def signed_up_via_lunchwalla
self.account_source == ACCOUNT_SOURCES['LunchWalla']
end
def notify_observers
notify_observers(self, :new_user_created)
notify_observers(self, :new_lunchwalla_user_created) if self.signed_up_via_lunchwalla
end
end
これらのイベントの通知を受け取りたいオブザーバーは、(1) イベントを公開するモデルに登録し、(2) イベントに一致する名前のメソッドを持つ必要があるだけです。予想どおり、複数のオブザーバーが同じイベントに登録でき、(元の質問の 2 番目の段落を参照して) オブザーバーは複数のモデルにわたってイベントを監視できます。
以下の NotificationSender および ProfilePictureCreator オブザーバー クラスは、さまざまなモデルによって公開されるイベントのメソッドを定義します。
NotificationSender
def new_user_created(user_id)
...
end
def new_invitation_created(invitation_id)
...
end
def new_event_created(event_id)
...
end
end
class ProfilePictureCreator
def new_lunchwalla_user_created(user_id)
...
end
def new_twitter_user_created(user_id)
...
end
end
1 つの注意点は、すべてのモデルで公開されるすべてのイベントの名前が一意でなければならないことです。