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

Переопределение рельсовых помощников с доступом к оригинальным

Я хочу использовать знакомых помощников рельсов, но с немного измененными функциями. То, как я это вижу, хочу, чтобы я мог сделать что-то вроде:

module AwesomeHelper
  #... create alias of stylesheet_link_tag to old_stylesheet_link_tag
  def stylesheet_link_tag(*args)
    if @be_awesome
      awesome_stylesheet_link_tag *args
    else
      old_stylesheet_link_tag *args
    end
  end
end

Как я вижу это, у меня есть три варианта:

  • Патч обезьяны:. Повторное открытие вспомогательного модуля рельсов. Если команда rails когда-либо изменяет имя своего вспомогательного модуля, мой код становится источником хрупкости. Не непреодолимый, но не идеальный.
  • Использовать разные имена методов: Попытка придерживаться общего интерфейса rails может быть моим падением. Мои изменения могут стать источником путаницы для других разработчиков.
  • Способы отсоединения (новые): Не уверен, будет ли это работать, или будет ли он иметь те же недостатки, что и 1. Будет ли это исследовать, но это может быть хорошей отправной точкой.

Итак, вопрос здесь в том, что я придерживаюсь одного из этих субоптимальных решений или есть другой способ, который я не рассматривал? Если я перейду на вариант 3, есть ли способ сделать это, не обращаясь напрямую к вспомогательному модулю rails?

(Примечание: я удалил контекст, так как он ничего не добавляет к вопросу.)

4b9b3361

Ответ 1

Там лучший способ, чем любой из перечисленных вами вариантов. Просто используйте super:

module AwesomeHelper
  def stylesheet_link_tag(*sources)
    if @be_awesome
      awesome_stylesheet_link_tag *sources
    else
      super
    end
  end
end

Переопределение stylesheet_link_tag в AwesomeHelper гарантирует, что при вызове stylesheet_link_tag Ruby встретит его в пути поиска метода до того, как он достигнет ActionView::Helpers::AssetTagHelper. Если @be_awesome - true, вы можете взять на себя ответственность и остановить все там, а если нет, вызов super без круглых скобок будет прозрачно проходить через все аргументы до реализации Rails. Таким образом, вам не нужно беспокоиться о том, что основная команда Rails перемещает вас на вас!

Ответ 2

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

Предположим, вы хотите записывать вызовы на link_to helper (да, надуманный пример, но показывает идею). В API-интерфейсе вы понимаете, что link_to находится внутри модуля ActionView::Helpers::UrlHelper. Таким образом, вы создаете файл в каталоге, скажем, config/initializers со следующим содержимым:

# like in config/initializers/link_to_log.rb
module ActionView::Helpers::UrlHelper

    def link_to_with_log(*args, &block)
        logger.info '**** LINK_TO CALL ***'
        link_to_without_log(*args, &block) # calling the original helper
    end

    alias_method_chain :link_to, :log
end

Ядро этой функциональности - alias_method_chain (доступно для кликов). Используйте его ПОСЛЕ определения метода xxx_with_feature.

Ответ 3

Попробуйте использовать alias_method:

module AwesomeHelper
  alias_method :original_stylesheet_link_tag, :stylesheet_link_tag

  def stylesheet_link_tag(*sources)
    if @be_awesome
      awesome_stylesheet_link_tag *sources
    else
      original_stylesheet_link_tag *sources
    end
  end
end

Ответ 4

Я бы очень хотел, чтобы вы рассмотрели свой вариант № 2, переопределив поведение методов рельсов так, как это очевидно для вызывающего.

Ваш новый метод должен быть вызван awesome_stylesheet_link_tag, чтобы другие разработчики Rails могли прочитать ваш код и задать вопрос "Что такого удивительного в теге ссылки?".

В качестве меньшего изменения вы можете сделать переопределение, но передать в :awesome => true в качестве аргумента, чтобы они, по крайней мере, имели представление о том, что что-то происходит.

Изменение поведения широко используемого метода, такого как stylesheet_link_tag, создает потенциальное будущее недоразумение, когда нет необходимости.