2012-02-23 2 views
4

У меня есть несколько методов в модели Account: оплата, получение, возврат и т. Д., Которые я хочу, чтобы мой AccountObserver наблюдал. Но я хотел бы передать дополнительные объекты в свой AccountObserver.Передача дополнительных аргументов в Rails observer

Например, в моей модели счета, я хотел бы определить:

def pay 
    ... 
    notify_observers(:after_pay, payee, amount) 

end 

Как мне это сделать?

спасибо.

+0

Самая естественная вещь, на мой взгляд, будет иметь модель «Оплата» или «Транзакция», которую вы будете наблюдать вместо этого, поскольку наблюдаемый объект даст вам доступ к связанной учетной записи, Получателю и сумме, d имеют дополнительный бонус наличия бумажного следа для прошлых транзакций. –

+0

Спасибо, Иордания. Ваше предложение очень проницательно, но я не могу изменить это решение в этой ситуации по причинам, не связанным с логикой программирования :) – AdamNYC

ответ

2

Я боюсь, что это не очень хороший вариант для наблюдателей. Лучший способ я могу думать, не заходя другой маршрут целиком, является установка переменных экземпляра вашего объекта счета, который вы можете получить доступ в наблюдателя, например .:

class Account < ActiveRecord::Base 
    attr_reader :last_payment 

    def pay payee, amt 
    @last_payment = [ payee, amt ] 

    notify_observers :after_pay 
    end 
end 

class AccountObserver < ActiveRecord::Observer 
    def after_pay account 
    payee, amt = account.last_payment 

    Rails.logger.info "#{payee} paid #{amt}!" 
    end 
end 
+0

Спасибо, Иордания. Я посмотрел на исходный код и понял, что мне нужно переопределить notify_observers, чтобы делать то, что я хочу. – AdamNYC

7

Не перезаписывать notify_observers. Исправление основных классов - действительно плохая идея. Вместо того, что вы должны сделать, это:

Вместо вызова instance method на вашей модели, которая ограничено только имя метода, вызовите метод класса себя:

# Notify list of observers of a change. 
def notify_observers(*arg) 
    observer_instances.each { |observer| observer.update(*arg) } 
end 

Она проходит вдоль каких-либо аргументов, которые вы даете это метод #update вашего наблюдателя, который вы можете перезаписать внутри своего собственного класса наблюдателя.

по умолчанию не принимает каких-либо посторонних аргументы, но не слишком сложно:

def update(observed_method, object, &block) #:nodoc: 
    return unless respond_to?(observed_method) 
    return if disabled_for?(object) 
    send(observed_method, object, &block) 
end 

Так просто добавить это к вашему наблюдателю, например:

def update(observed_method, object, *args) 
    return unless respond_to?(observed_method) 
    return if disabled_for?(object) 
    send(observed_method, object, *args) 
end 

def after_pay(payee, amount) 
    ... 
end 

И позвони

Payee.notify_observers(:after_pay, payee, amount) 
+0

Это замечательно, fx! Большое спасибо. – AdamNYC

+0

Спасибо за это!Я понял, что мне нужно вызвать класс notify_observers на уровне класса, но я все еще не мог заставить его работать. Это помогло мне узнать, что мне нужно изменить метод экземпляра 'update' на самом наблюдателе. –

1

Поздний отклик, но я надеюсь, что кому-то это будет полезно.

Прежде всего, это, кажется, being fixed in Rails 4

Но в моем Rails 3 проекта я передаю хэш на уровне класса notify_observers вызова.

self.class.notify_observers :organisation_added_to_group, { group: self, organisation: organisation } 

И наблюдатель Я получаю этот хэш:

def organisation_added_to_group(args) 
    puts args[:group] 
    puts args[:organisation] 
end 

Мне нравится, что я не забочусь о update «s метод внутренностей, как в приведенном выше ответе.

Смежные вопросы