简体   繁体   English

如何通过元编程覆盖Ruby on Rails模块方法?

[英]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_public_path located under ActionView::Helpers::AssetTagHelper, so that all my admin's layout files will be under public/admin. 从我的联系:: Base的控制器渲染视图我想重写Rails的compute_public_path位于下::的ActionView ::助手AssetTagHelper,让我所有的管理员的布局文件将在公共/管理。

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: 我把它放在Admin :: Base控制器中:

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. 我得到“模块'AdminHelper'的未定义方法'compute_public_path'”,我猜这是发生了,因为compute_public_path是私有方法。

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. 只要将config.cache_classes设置为false ,否则我会得到一个堆栈级别太深的错误。

Thanks to Squeegy for pointing me in the right direction. 感谢Squeegy为我指出正确的方向。

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. 现在, compute_public_path将调用您的实现,然后调用原始实现。

See: Is alias_method_chain synonymous with alias_method? 请参阅: alias_method_chain是否与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 ? 您为什么要在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. Rails默认将它们放在app/views/layouts下是有原因的:没有人可以在那里阅读它们的源代码。

If you put them in public , they are basically readable for any visitor. 如果将它们public ,则基本上所有访客都可以阅读。

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 , ie without having to hack framework internals. 最重要的是, 您可以根据需要构建app/views/layouts而无需任何元编程 ,即,无需破解框架内部结构。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM