Object.const_get和Rails - 切断父模块名称

时间:2015-04-24 14:00:13

标签: ruby-on-rails ruby

我有以下代码来拉出并实例化Rails控制器:

def get_controller(route)
  name = route.requirements[:controller]
  return if name.nil?


  if name.match(/\//)
    controller_name = name.split('/').map(&:camelize).join('::')
  else
    controller_name = name.camelize
  end

  p controller_name: controller_name

  controller = Object.const_get("#{controller_name}Controller")

  p controller: controller
  controller.new
end

有些路线是单一名称 - &#34;用户&#34;,&#34;朋友&#34;,&#34;邻居&#34;,&#34;政客&#34;等... < / p>

其他路线是嵌套的,例如&#34; admin / pets&#34;,&#34; admin / shopping_lists&#34;,&#34; admin / users&#34;等...

在上面提到的大多数情况下,上面的代码都有效(因为它可以正确地构建和实例化控制器),除了一个 - 在这个例子中,&#34; admin / users&#34;

来自puts语句,我得到以下内容:

{:controller_name=>"Admin::Users"}
{:controller => UsersController}

您会注意到名称空间Admin正在被切断。我的猜测是,因为这只是在多个名称空间(usersadmin/users)中共享名称的控制器的情况,所以它与Rails自动加载(?)有关。有什么原因造成的?

根据lx00st的评论,我还应该指出,我已经尝试了各种形式的获取这些常量,另一种尝试如下:

sections = name.split('/')
sections.map(&:camelize).inject(Object) do |obj, const|
  const += "Controller" if const == sections.last
  obj.const_get(const)
end

这种方法遇到了同样的问题。

2 个答案:

答案 0 :(得分:3)

这是通过用户apneadiving的答案解决的,可以找到here

  

请注意Rails开发模式中存在恶意案例。为了获得速度,加载严格的最小值。然后Rails在需要时查找类定义。

     

但是,当您说::User已经加载,然后查找::Admin::User时,这有时会失败。 Rails不会寻找它,它会认为::User可以解决问题。

     

这可以使用代码中的require_dependency语句来解决。

我个人认为这是一个错误,不是一个功能,但是......所以它就是这样。它解决了这个问题。

答案 1 :(得分:1)

首先,这段代码是多余的:

if name.match(/\//)
  controller_name = name.split('/').map(&:camelize).join('::')
else
  controller_name = name.camelize
end

唯一的字符串可以完美地处理两种情况:

controller_name = name.split('/').map(&:camelize).join('::')

然后,您可能希望正确处理命名空间:

n_k = controller_name.split('::')
klazz = n_k.last

namespace_object = if n_k.length == 1
                     Object
                   else
                     Kernel.const_get(n_k[0..-2].join('::'))
                   end

controller = namespace_object.const_get("#{klazz}Controller")

希望有所帮助。