开发者

How can I override a Ruby on Rails module method via metaprogramming?

As much I would like to I still don't know how to implement metaprogramming.

For views rendered from my Admin::Base controller I would like override the Rails compute_publ开发者_如何学Goic_path located under ActionView::Helpers::AssetTagHelper, so that all my admin's layout files will be under public/admin.

There is probably a better way to this, but at this point I want to learn how to do it this way.

I put this in Admin::Base controller:

module ActionView::Helpers::AssetTagHelper
  def compute_public_path(source, dir, ext = nil, include_host = true)
    super(source, "admin/#{dir}", ext = nil, include_host = true)
  end
end

but it gives me:

super: no superclass method `compute_public_path' for #<ActionView::Base:0x1032240a8>

Which doesn't surprise me.


If I try this in my admin helper:

def compute_public_path_with_admin(source, dir, ext = nil, include_host = true)
  compute_public_path_without_admin(source, "admin/#{dir}", ext, include_host)
end

alias_method_chain :compute_public_path, :admin

I get "undefined method 'compute_public_path' for module 'AdminHelper'", which I am guessing happens because compute_public_path is a private method.

I found this works:

ActionView::Helpers::AssetTagHelper.class_eval do
  def compute_public_path_with_admin(source, dir, ext = nil, include_host = true)
    compute_public_path_without_admin(source, "admin/#{dir}", ext, include_host)
  end

  alias_method_chain :compute_public_path, :admin
end

as long as I set config.cache_classes to false, otherwise I get a stack level too deep error.

Thanks to Squeegy for pointing me in the right direction.

How can I make this work with disabling class caching?


def compute_public_path_with_admin(source, dir, ext = nil, include_host = true)
  compute_public_path_without_admin(source, "admin/#{dir}", ext, include_host)
end

alias_method_chain :compute_public_path, :admin

compute_public_path will now call your implementation, which then calls the original implementation.

See: Is alias_method_chain synonymous with alias_method?


Please don't do this.

The accepted answer will get what you wanted, but what you want might have dangerous security implications.

Why would you want your admin layouts under public? There's a reason why Rails by default puts them under app/views/layouts: No one will be able to read their source there.

If you put them in public, they are basically readable for any visitor.

If you put them where they belong, you're not exposing your layout code. And on top of that, you can structure app/views/layouts any way you want without any metaprogramming, i.e. without having to hack framework internals.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜