Подтвердить что ты не робот

Rails 3: alias_method_chain все еще используется?

Я просто читал о разработке Gems/Plugin для Rails 3 и перебегал через этот пост, в котором говорится, что alias_method_chain больше не используется. Я вижу, что метод все еще присутствует в activesupport-3.0.0/lib/active_support/core_ext/module/aliasing.rb.

Должен ли я использовать alias_method_chain в Rails 3?

Является этим, по-прежнему отражающим лучшие практики для gems/plugins в Rails 3, которые хотят изменить ActiveRecord?

4b9b3361

Ответ 1

Нет, он был заменен умным использованием переопределения метода в модулях и ключевым словом super.

В принципе, вы определяете исходную функцию в включенном модуле и переопределяете ее в другом включенном модуле. Когда вы вызываете super в функции переопределения, он вызывает исходную функцию. Но есть один улов. Вы должны включить расширяемые модули после, включая базовый модуль, и в том порядке, в котором вы хотите, чтобы цепочка произошла.

class Something
  module Base  
    def my_method
      # (A) original functionality
    end
  end

  module PreExtension
    def my_method
      # (B) before the original
      super # calls whatever was my_method before this definition was made
    end
  end

  module PostExtension
    def my_method
      super # calls whatever was my_method before this definition was made
      # (C) after the original
    end
  end

  include Base # this is needed to place the base methods in the inheritance stack
  include PreExtension # this will override the original my_method
  include PostExtension # this will override my_method defined in PreExtension
end

s = Something.new
s.my_method 
#=> this is a twice extended method call that will execute code in this order:
#=> (B) before the original
#=> (A) the original
#=> (C) after the original

Райан Бэйтс Railscasts рассказывает о как это используется в Rails Routing code. Я бы рекомендовал посмотреть его и другие его скринкасты. Они имеют право превращать вязальную бабушку в гуру Rails.

PS: Кредит отправляется Peeja для исправления фундаментальной ошибки в моем первоначальном ответе. Спасибо.

Ответ 2

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

Когда модуль включен в класс, модуль вставлен сразу после класса в классе предков. призвание super из класса вызовет реализацию модуля.

class Something
  module PreExtension; end
  module PostExtension; end

  include PreExtension
  include PostExtension
end

Something.ancestors # => [Something, Something::PostExtension, Something::PreExtension, Object, Kernel]

Всякий раз, когда метод вызывается на Something, Ruby просматривает этот список по порядку и вызывает первую найденную им реализацию. Если реализация вызывает super, она продолжает искать и находить следующий.

Это означает, что модули, включенные позже, имеют приоритет над модули, включенные ранее, и могут вызвать super, чтобы получить ранее модулей. Это связано с тем, что включенные модули вставляется в цепочку предков непосредственно после класса. Эта упомянутый выше упоминаемый код маршрутизации edgerunner. Этот код помещает все в модули, например:

class SomethingNew
  module Base
    def my_method
      puts "(A)"
    end
  end

  module Extension
    def my_method
      puts "(B)"
      super
    end
  end

  include Base
  include Extension
end

SomethingNew.new.my_method
# Output:
# >> (B)
# >> (A)

SomethingNew.ancestors # => [SomethingNew, SomethingNew::Extension, SomethingNew::Base, Object, Kernel]

Вот почему alias_method_chain существовал в первую очередь. Если размещение базового кода в модуле не является вариантом, я не уверен, как выполнить эквивалент alias_method_chain.

Ответ 3

Я вижу, что alias_method_chain больше не присутствует в Rails 3.0.0. http://api.rubyonrails.org/ не сообщает об этом, а rails console сообщает, что это undefined local variable or method.

См. также - https://rails.lighthouseapp.com/projects/8994/tickets/285-alias_method_chain-limits-extensibility#ticket-285-20

ОБНОВЛЕНИЕ: Как отмечено @ecoologic в комментариях, alias_method_chain все еще присутствует в Rails 3.1.1.