How to extend a helper using plugin?

Hello,

I'm facing this problem while trying to extend the parse_redmine_links
helper method in Redmine-1.1.0 (Rails-2.3.5) from my plugin.

My idea is to use alias_method_chain so the extended version could
call the original version and adjust the result to it's liking.

Anything I've tried so far exposes this behavior: the first render of
a page uses the extended version, while every later renders use the
original unmodified helper.

I've tried to include my patch module in the plugin's init.rb like
this:

require_dependency 'application_helper'
ApplicationHelper.send(:include,
RedminePastebin::ApplicationHelperPatch)

Also I've tried to define my ApplicationHelper in myplugin/app/helper/
application_helper.rb with the same effect. Both approaches used
self.included hook to call alias_method_chain, like this:

  def self.included(base)
    base.module_eval do
      alias_method_chain :parse_redmine_links, :pastes
    end
  end

Any ideas on how to accomplish the task are welcome!

Hello,

I'm facing this problem while trying to extend the parse_redmine_links
helper method in Redmine-1.1.0 (Rails-2.3.5) from my plugin.

My idea is to use alias_method_chain so the extended version could
call the original version and adjust the result to it's liking.

Anything I've tried so far exposes this behavior: the first render of
a page uses the extended version, while every later renders use the
original unmodified helper.

Because you're in development mode, the app's code, including
application_helper is reloaded for each request, but your plugin's
init.rb is only called once and never gets to do your monkey patching
on the reloaded copies of application helper

You might be able to use a to_prepare callback (these get called
before each request in development mode) if you're going to use this a
lot in development mode - take a peek inside action_dispatch/
middleware/callbacks

Fred

Yes, but I *was* using a to_prepare block (w/o actually understanding
what it does, though.)

So what I now actually have in init.rb is this:

Dispatcher.to_prepare :redmine_model_dependencies do
  puts "!!! to_prepare block !!!"

  require_dependency 'application_helper'

  unless ApplicationHelper.included_modules.include?
RedminePastebin::ApplicationHelperPatch
    ApplicationHelper.send(:include,
RedminePastebin::ApplicationHelperPatch)
  end
end

If I put some logging lines into redmine's application_helper.rb, I
can get this:

module ApplicationHelper
  def self.included(base)
    puts "ApplicationHelper: INCLUDED: #{self.method_defined?
(:parse_redmine_links_with_pastes)}"
  end
  ...
  def parse_redmine_links(text, project, obj, attr, only_path,
options)
    logger.info "parse_redmine_links"
  ...

And in my patch-module I have this log line:

    def parse_redmine_links_with_pastes(text, project, obj, attr,
only_path,
                                        options)
      logger.info "parse_redmine_links_with_pastes"
     ...

Now for the first page load I get these:

ApplicationHelper: INCLUDED: false
ApplicationHelper: INCLUDED: false
!!! to_prepare block !!!
=> Call with -d to detach
=> Ctrl-C to shutdown server
!!! to_prepare block !!!
ApplicationHelper: INCLUDED: true
...
parse_redmine_links_with_pastes
...

and for the second load, these:

!!! to_prepare block !!!
ApplicationHelper: INCLUDED: true
ApplicationHelper: INCLUDED: true
ApplicationHelper: INCLUDED: true
...
parse_redmine_links

So original unmodified method is called regardless of the fact that
the new one is defined...

I guess I need to move that alias_method_chain call somewhere else so
it's called on every page load. How do I do so?

Now, that's interesting. The above method supposed to work, and it
does work with, e.g. users_helper (see
http://www.redmine.org/projects/redmine/wiki/Plugin_Internals#Wrapping-an-existing-method
for the supported way of overriding helper methods.)

But this does not work with application_helper. I come to think it is
special in some way.

If I put this into my init.rb:

Dispatcher.to_prepare :redmine_model_dependencies do
  require_dependency 'users_helper'
  require_dependency 'application_helper'

  unless UsersHelper.included_modules.include?(LockUsersHelperPatch)
    puts "!!! UsersHelper !!!"
    UsersHelper.send(:include, LockUsersHelperPatch)
  end

  unless ApplicationHelper.included_modules.include?
ApplicationHelperPatch
    puts "!!! ApplicationHelper !!!"
    ApplicationHelper.send(:include, ApplicationHelperPatch)
  end
end

I can clearly see that UserHelperPatch is included on every page load,
while ApplicationHelperPatch is only included for the first time. So
it somehow thinks it is included, but calls the wrong (unaliased)
method.

Any help on this is greatly appreciated!

I wonder if I might have better luck asking this on the -core list...

Is the problem solved?
I found that the following codes works as expected.

redmine/vendor/plugins/redmine_x/init.rb:

require 'redmine'
require 'dispatcher'

module XPatch
  def self.included(base) # :nodoc:
    if !base.method_defined?(:parse_redmine_links_without_patch)
      base.send(:include, InstanceMethods)
      base.class_eval do
        alias_method_chain :parse_redmine_links, :patch
      end
    else
      base.class_eval do

alias_method :parse_redmine_links, :parse_redmine_links_with_patch
      end
    end
  end

  module InstanceMethods
    def parse_redmine_links_with_patch(text, project, obj, attr,
only_path, options)
      parse_redmine_links_without_patch(text, project, obj, attr,
only_path, options)
      text.gsub!(/./, 'x')
    end
  end
end

Dispatcher.to_prepare :x do
  require_dependency 'application_helper'
  ApplicationHelper.send(:include, XPatch)
end

Redmine::Plugin.register :redmine_magic_links_to_notes do
  name 'Redmine X plugin'
  author 'ganaware'
  description 'X notes'
  version '0.0.1'
end