开发者

Rails3 Engine helper over-ride

So I have a Rails 3.0 Engine (gem).

It provides a controller at app/controllers/advanced_controller.rb, and a corresonding helper at app/helpers/advanced_helper.rb. (And some views of course).

So far so good, the controller/helper/views are just automatically available in the application using the gem, great.

But I want to let the local application selective over-ride helper methods from AdvancedHelper in the engine (and ideally be able to call 'super'). That's a pretty reasonable thing to want to allow, right, a perfectly reasonable (and I'd think common) design?

Problem is, I can't seem to find any way to make it work. If the application defines it's own app/helpers/advanced_helper.rb (AdvancedHelper), then the one from the engine never gets loaded at all -- so that would work if you wanted to replace ALL the helper methods in there (without calling super), but not if you just want to over-ride one.

So that kind of makes 开发者_JAVA百科sense actually, so I pick a different name. Let's call my local one ./app/helpers/local_advanced_helper.rb (LocalAdvancedHelper). This helper DOES get loaded, if I put a method in there that wasn't in the original engine's AdvancedHelper, it is available to views.

But if I put a method in there with the same name as one in the engine's AdvancedHelper... my local one NEVER gets called. It's like the AdvancedHelper (from engine) is earlier in the call chain than the LocalAdvancedHelper (from app). Indeed, if I turn on the debugger, and look at helpers.ancestors, that's exactly what's going on, they're in the reverse order I'd want in the ancestor chain. So AdvancedHelper (from engine) could theoretically call 'super' to call up to LocalAdvancedHelper (from app) -- but that of course wouldn't make a lot of sense to do, you'd never want to do that.

But what I would want to do... I can't do.

Anyone have any ideas, is there any way to provide this design, which seems perfectly reasonable to me, where an app can selectively over-ride a helper method from an Engine?

Anyone have any explanation of why it's working the way it is? I tried looking at actual Rails source code, but got lost pretty quick, the code around this stuff is awfully abstract split amongst a bunch of places.

This is pretty esoteric question, I'm pessimistic anyone will have any ideas, I hope you surprise me!

== Update

Okay, in order to understand what part of Rails code is being called where, I put a "def self.included ; debugger ; end" on each of my helpers, then in the debugger I can raise an exception to see a stack trace.

That still isnt' really helping me get to the bottom of it, the Rails code jumps all over the place and is pretty confusing.

But it's clear that a helper with the 'standard' name (ie WidgetHelper for WidgetController) is called by different rails code, to include in the 'master' view helper module for a given controller, than other helpers are. I'm wondering if I give the helper a different name, then manually include it in my controller with ("helper OtherNamedAdvancedHelper"), if that will change the load order.


We can use Module#class_eval to override.

In main app,

MountedEngineHelper.class_eval do
  def advanced_helper
    ...
  end
end

In this way other methods defined in engine helper are still available.


Thanks for your elaboration. I think this really is a problem. And it is still present in Rails 3.2.3, so I filed an issue.

The least-smelling workaround I came up with is to do a "half alias method chain":

module MountedEngineHelper
  def advanced_helper
    ...
  end
end

module MyHelper
  def advanced_helper_with_extra_behavior
    advanced_helper
    extra_behavior
  end
end

The obvious drawback is that you have to change your templates so that your helper is called. At least, you make the existence of extra behavior explicit there.


These release notes from Rails4 seem enticingly related to this problem, and potentially note it's been fixed:

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

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜