У меня есть следующие классы:Рубин Метапрограммирование Q: Вызов метода внешнего класса на after_save
class AwardBase
class AwardOne < AwardBase
class Post < ActiveRecord::Base
Пост является ActiveRecord и награда имеет can_award? класса, который принимает объект post и проверяет, соответствует ли он некоторым критериям. Если да, он обновляет post.owner.awards.
Я знаю, что могу сделать это с использованием шаблона Observer (я тестировал его, и код отлично работает). Однако для этого требуется добавить дополнительный код модели. Я бы не хотел прикоснуться к модели вообще, если это возможно. То, что я хотел бы сделать, это запустить проверку премии, как это (триггер будет вызываться при загрузке класса):
class AwardOne < AwardBase
trigger :post, :after_save
def self.can_award?(post)
...
end
end
Намерение с указанным кодом является то, что она должна автоматически добавить AwardOne.can_award? методу after_save Поста
Поэтому в основном то, что я пытаюсь сделать, это получить trigger
вызов эквивалентен:
class Post < ActiveRecord::Base
after_save AwardOne.can_award?(self)
...
end
который в основном:
class Post < ActiveRecord::Base
after_save :check_award
def check_award
AwardOne.can_award?(self)
end
end
Как может Я делаю это без изменения класса Post?
Вот что я сделал (который, кажется, не работает):
class AwardBase
def self.trigger (klass, active_record_event)
model_class = klass.to_class
this = self
model_class.instance_eval do
def award_callback
this.can_award?(self)
end
end
model_class.class_eval do
self.send(active_record_event, :award_callback)
end
end
def self.can_award? (model)
raise NotImplementedError
end
end
Приведенный выше код завершается с ошибкой:
NameError (undefined local variable or method `award_callback' for #<Post:0x002b57c04d52e0>):
Просьба предоставить стек для этой ошибки. –
Вы можете использовать ActiveSupport :: Concerns, похожие на принятый ответ здесь: http://stackoverflow.com/questions/12084234/how-do-i-use-ruby-metaprogramming-to-add-callbacks-to-a- rails-model? rq = 1 – Anand
, но все равно вы должны включить его в свою модель! Я не уверен, хотя – argentum47