我替代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回调之外,每个模型都可以定义自己的可观察事件。例如,我的用户模型公开了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)具有名称与事件匹配的方法。正如人们可能期望的那样,多个观察者可以注册同一事件,并且(参考原始问题的第二段)观察者可以监视多个模型中的事件。
下面的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
需要注意的是,所有模型中公开的所有事件的名称必须唯一。