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つの注意点は、すべてのモデルで公開されるすべてのイベントの名前は一意でなければならないということです。