Reputation: 595
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_public_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?
Upvotes: 2
Views: 1702
Reputation: 13633
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.
Upvotes: 0
Reputation: 187004
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?
Upvotes: 1