Rails3 Перегрузка вспомогательного двигателя - PullRequest
2 голосов
/ 17 июня 2011

Итак, у меня есть Rails 3.0 Engine (гем).

Он предоставляет контроллер в app / controllers / advanced_controller.rb и соответствующий помощник в app / helpers / advanced_helper.rb.(И некоторые взгляды конечно).

Пока все хорошо, контроллер / помощник / представления просто автоматически доступны в приложении, использующем гем, отлично.

Но я хочу разрешить локальному приложению выборочные вспомогательные методы переопределения из AdvancedHelper в движке (и в идеале иметь возможность вызывать 'super').Это довольно разумная вещь, чтобы хотеть разрешить, верно, совершенно разумный (и я думаю, обычный) дизайн?

Проблема в том, что я не могу найти какой-либо способ заставить его работать.Если приложение определяет свое собственное app / helpers / advanced_helper.rb (AdvancedHelper), то приложение из движка вообще никогда не загружается - так что это сработало бы, если бы вы захотели заменить ВСЕ вспомогательные методы там (без вызова super), но не если вы просто хотите переехать один.

Так что на самом деле это имеет смысл, поэтому я выбрал другое имя.Давайте назовем мой локальный ./app/helpers/local_advanced_helper.rb (LocalAdvancedHelper).Этот помощник загружается, если я добавлю туда метод, которого нет в AdvancedHelper исходного движка, он будет доступен для просмотра.

Но если я добавлю туда метод с тем же именем, что и в AdvancedHelper движка ... мой локальный НИКОГДА не будет вызван.Как будто AdvancedHelper (из движка) находится раньше в цепочке вызовов, чем LocalAdvancedHelper (из приложения).Действительно, если я включу отладчик и посмотрю на helpers.ancestors, это именно то, что происходит, они в обратном порядке, который я бы хотел в цепочке предков.Таким образом, AdvancedHelper (из движка) теоретически может вызвать 'super' для вызова LocalAdvancedHelper (из приложения) - но это, конечно, не имеет большого смысла, вы никогда не захотите этого делать.

Но то, что я хотел бы сделать ... Я не могу сделать.

У кого-нибудь есть какие-нибудь идеи, есть ли способ предоставить этот дизайн, который кажется мне совершенно разумным, когда приложение может выборочно переопределить вспомогательный метод из Engine?

Кто-нибудь может объяснить, почему он работает так, как есть?Я попытался взглянуть на реальный исходный код Rails, но довольно быстро заблудился, код вокруг этого материала ужасно абстрактно разделен на множество мест.

Это довольно эзотерический вопрос, я пессимистичен, у кого-нибудь будут какие-то идеи, надеюсь, вы меня удивите!

== Обновление

Хорошо, чтобы понять, чточасть кода на Rails вызывается где, я помещаю «def self.included; отладчик; конец» на каждого из моих помощников, затем в отладчике я могу вызвать исключение, чтобы увидеть трассировку стека.

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

Но ясно, что помощник со «стандартным» именем (т. Е. WidgetHelper для WidgetController) вызывается другим кодом rails для включения в вспомогательный модуль представления «master» для данного контроллера, чем другие помощники.,Мне интересно, если я дам помощнику другое имя, затем вручную включу его в мой контроллер с помощью ("helper OtherNamedAdvancedHelper"), если это изменит порядок загрузки.

Ответы [ 3 ]

1 голос
/ 02 января 2013

Мы можем использовать Module # class_eval для переопределения.

В основном приложении

MountedEngineHelper.class_eval do
  def advanced_helper
    ...
  end
end

Таким образом, все еще доступны другие методы, определенные в помощнике движка.

0 голосов
/ 20 июня 2013

Эти заметки о выпуске из Rails4 кажутся заманчиво связанными с этой проблемой, и потенциально заметьте, что она исправлена:

http://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#helpers-loading-order

0 голосов
/ 26 мая 2012

Спасибо за вашу разработку. Я думаю, что это действительно проблема. И он все еще присутствует в Rails 3.2.3, поэтому я подал вопрос .

Обходное решение с наименьшим запахом, которое я придумал, это сделать «цепочку методов с половинным псевдонимом»:

module MountedEngineHelper
  def advanced_helper
    ...
  end
end

module MyHelper
  def advanced_helper_with_extra_behavior
    advanced_helper
    extra_behavior
  end
end

Очевидным недостатком является то, что вы должны изменить свои шаблоны так, чтобы ваш помощник вызывался. По крайней мере, вы явно указываете существование дополнительного поведения.

...