Rails 3: alias_method_chain все еще используется? - PullRequest
34 голосов
/ 11 сентября 2010

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

Должен ли я по-прежнему использовать alias_method_chain в Rails 3? это по-прежнему отражает лучшие практики для гемов / плагинов в Rails 3, которые хотят изменить ActiveRecord?

Ответы [ 3 ]

57 голосов
/ 22 сентября 2010

Нет, он был заменен умным использованием переопределения методов в модулях и ключевым словом 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 .Я бы порекомендовал посмотреть его и другие его скринкасты.Они могут превратить вязаную бабушку в гуру из Rails.

PS: Авторы благодарны Peeja за исправление фундаментальной ошибки в моем первоначальном ответе.Благодаря.

19 голосов
/ 05 ноября 2010

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

Когда модуль включен в класс, модуль вставляется сразу после класса в цепочке предков класса.Вызов 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, чтобы получить более ранние реализации модулей.Это связано с тем, что включенные модули вставляются в цепочку предков непосредственно после класса.Так работает упомянутый код маршрутизации.Этот код помещает все в модули, например:

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.

0 голосов
/ 17 сентября 2010

Я вижу, что 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.

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