Переопределение method_missing не работает - PullRequest
4 голосов
/ 02 августа 2010

Я написал удобное расширение ActiveRecord для делегирования методов базовому объекту (на основе многостолового наследования )

class ActiveRecord::Base
  def self.acts_as(base)
    class_eval %Q{
      def method_missing(method, *args, &blk)
        #{base}.send(method, *args, &blk)
      rescue NoMethodError
        super
      end
    }
  end
end

У меня есть состояние класси base class

# state class
class MyState < ActiveRecord::Base
  belongs_to :my_object
  acts_as :my_object
end

# base class
class MyObject < ActiveRecord::Base
  has_one :head, :class_name => 'MyState'
  has_one :tail, :class_name => 'MyState'
end

Когда я попробовал это, я обнаружил, что в некоторых случаях это не работает.В частности,

> MyState.first.some_method_in_base
nil
> MyObject.first.tail.some_method_in_base
NoMethodError: undefined method `some_method_in_base' for #<ActiveRecord::Associations::HasOneAssociation:0xABCDEFG>

Может ли кто-нибудь просветить меня, почему одно работает, а другое нет?

1 Ответ

5 голосов
/ 02 августа 2010

Когда вы запускаете MyObject.first.tail, объект, который фактически отвечает, является AssociationProxy классом, который

удаляет большинство основных методов экземпляра и делегатов # неизвестные методы для @target через method_missing

Вы можете получить более подробную информацию о работе прокси:

MyObject.first.proxy_owner
MyObject.first.proxy_reflection
MyObject.first.proxy_target

Если вы заглянете в код, то увидите, что AssociationProxy передает метод some_method_in_base вашему классу MyState только в том случае, если MyState отвечает на some_method_in_base как вы можно увидеть в коде ниже.

  private
    # Forwards any missing method call to the \target.
    def method_missing(method, *args, &block)
      if load_target
        if @target.respond_to?(method)
          @target.send(method, *args, &block)
        else
          super
        end
      end
    end

Следовательно, method_missing , который вы определили в целевой класс , никогда не вызывается.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...