Как исправить модуль ActionView с помощью prepend?

Если вы включаете модуль Foo в класс SomeClass, а затем добавляете к этому модулю другой модуль Bar, любая перезапись метода внутри Bar не повлияет на SomeClass. Пример:

module Foo
  def some_method
    puts 'In Foo'
  end
end

class SomeClass
  include Foo
end

SomeClass.new.some_method # => 'In Foo'

module Bar
  def some_method
    puts 'In Bar'
    super
  end
end

Foo.prepend Bar

Foo.ancestors # => [Bar, Foo]

SomeClass.new.some_method # => 'In Foo'

class AnotherClass
  include Foo
end

AnotherClass.new.some_method # => 
# 'In Bar'
# 'In Foo'

Я пытаюсь исправить вспомогательный метод ActionView следующим образом:

In lib/core_extensions/action_view/helpers/url_helper/secure_link_to:

module CoreExtensions
  module ActionView
    module Helpers
      module UrlHelper
        module SecureLinkTo
          def link_to(name = nil, options = nil, html_options = nil, &block)
            html_options ||= {}
            if html_options[:target].present?
              html_options[:rel] = 'noopener noreferrer'
            end

            super(name, options, html_options, &block)
          end
        end
      end
    end
  end
end

а затем в инициализаторе:

ActionView::Helpers::UrlHelper.prepend CoreExtensions::ActionView::Helpers::UrlHelper::SecureLinkTo

Однако, похоже, это не работает. Мое предположение - к моменту выполнения инициализатора ActionView::Helpers::UrlHelper уже было включено (там, где оно должно быть включено), и поэтому добавление, похоже, не вступает в силу. Кто-нибудь знает решение этого?


person Alexander    schedule 01.11.2016    source источник
comment
почему бы просто не открыть снова ActionView::Helpers::UrlHelper и не определить там метод? (кроме того, ваш подход кажется несколько более чистым)   -  person Andrey Deineko    schedule 01.11.2016
comment
Ну, именно так, как вы говорите - хотелось бы сделать по-чистому. Я следую этому: nofail.de/2014/06/monkey-patching-rails и эта статья рекомендует prepend как лучшее решение.   -  person Alexander    schedule 01.11.2016


Ответы (1)


Не отвечая на ваш конкретный вопрос о добавлении модуля, здесь был бы другой способ:

Поскольку хелперы в Rails являются глобальными, вы можете просто создать свой собственный хелпер с переопределенным методом link_to.

module LinkHelper
  def link_to(name = nil, options = nil, html_options = nil, &block)
    html_options ||= {}
    if html_options[:target].present?
      html_options[:rel] = 'noopener noreferrer'
    end

    super(name, options, html_options, &block)
  end
end

Почему-то это кажется менее hacky, чем создание инициализатора, потому что мне не нужно жестко кодировать цепочку наследования во вспомогательном модуле.

person Magnuss    schedule 01.11.2016
comment
Спасибо за ответ, Магнус. Куда мне положить этот файл? - person Alexander; 01.11.2016
comment
@AlexPopov Это старый добрый вспомогательный модуль. Вы положили его в app/helpers. - person Magnuss; 01.11.2016
comment
Для справки: stackoverflow.com/ вопросы/10471535/ - person Alexander; 01.11.2016