Alex Popov Alex Popov - 1 month ago 8
Ruby Question

How to monkey-patch an ActionView module via prepend?

If you include a module

Foo
in a class
SomeClass
, then prepend that module with another module
Bar
, any method-overwriting inside
Bar
will not take effect in
SomeClass
. Example:

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'


I am trying to monkey-patch an ActionView helper method the following way:

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


and then in an initializer:

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


However, this doesn't seem to work. My assumption - by the time the initializer executes,
ActionView::Helpers::UrlHelper
has already been included (in wherever it is supposed to be included) and thus the prepending doesn't seem to take effect. Does anybody know a solution to this?

Answer

Without answering your specific question about module prepend, here would be another way:

Since helpers in Rails are global, you can simply create your own helper with the link_to method overridden.

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

Somehow this seems less hacky than creating an initializer, because I don't need to hardcode the inheritence chain in the helper module.

Comments