繁体   English   中英

你如何在 Ruby on Rails 中以编程方式找到命名空间/模块名称?

[英]How do you find the namespace/module name programmatically in Ruby on Rails?

如何在下面的过滤器中找到命名空间或模块“Foo”的名称?

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = ???
  end
end


class Foo::BarController < ApplicationController
  before_filter :get_module_name
end

这些解决方案都没有考虑具有多个父模块的常量。 例如:

A::B::C

从 Rails 3.2.x 开始,您可以简单地:

"A::B::C".deconstantize #=> "A::B"

从 Rails 3.1.x 开始,您可以:

constant_name = "A::B::C"
constant_name.gsub( "::#{constant_name.demodulize}", '' )

这是因为#demodulize 与#deconstantize 相反:

"A::B::C".demodulize #=> "C"

如果您确实需要手动执行此操作,请尝试以下操作:

constant_name = "A::B::C"
constant_name.split( '::' )[0,constant_name.split( '::' ).length-1]

对于简单的情况,您可以使用:

self.class.parent

这应该这样做:

  def get_module_name
    @module_name = self.class.to_s.split("::").first
  end

如果控制器确实有模块名称,这将起作用,但如果没有,则会返回控制器名称。

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.name.split("::").first
  end
end

但是,如果我们将其更改为:

class ApplicatioNController < ActionController::Base
  def get_module_name
    my_class_name = self.class.name
    if my_class_name.index("::").nil? then
      @module_name = nil
    else
      @module_name = my_class_name.split("::").first
    end
  end
end

您可以确定该类是否具有模块名称,并返回您可以测试的类名称以外的其他内容。

对于 Rails 6.1

self.class.module_parent


Hettomei 的答案在 Rails 6.0 之前都可以正常工作

弃用警告: Module#parent已重命名为module_parent parent已弃用,将在 Rails 6.1 中删除。

my_class.name.underscore.split('/').slice(0..-2)

或者

my_class.name.split('::').slice(0..-2)

我知道这是一个旧线程,但我刚遇到需要根据控制器的命名空间进行单独导航。 我想出的解决方案是在我的应用程序布局中:

<%= render "#{controller.class.name[/^(\w*)::\w*$/, 1].try(:downcase)}/nav" %>

这看起来有点复杂,但基本上执行以下操作 - 它采用控制器类名称,例如,对于非命名空间控制器,它是“People”,对于命名空间控制器,它是“Admin::Users”。 使用带有正则表达式的 [] 字符串方法,返回两个冒号之前的任何内容,如果没有,则返回 nil。 然后将其更改为小写(如果没有命名空间并返回 nil,则存在“try”)。 这给我们留下了命名空间或 nil。 然后它简单地呈现带有或不带有名称空间的部分,例如没有名称空间:

app/views/_nav.html.erb

或在 admin 命名空间中:

app/views/admin/_nav.html.erb

当然,每个命名空间都必须存在这些部分,否则会发生错误。 现在,每个命名空间的导航将出现在每个控制器上,而无需更改任何控制器或视图。

没有人提到使用rpartition吗?

const_name = 'A::B::C'
namespace, _sep, module_name = const_name.rpartition('::')
# or if you just need the namespace
namespace = const_name.rpartition('::').first

我不认为有更干净的方法,我在其他地方看到过

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.name.split("::").first
  end
end

我推荐gsub而不是split 考虑到您不需要任何其他模块名称, split更有效。

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.to_s.gsub(/::.*/, '')
  end
end

有许多子模块:

module ApplicationHelper
  def namespace
    controller.class.name.gsub(/(::)?\w+Controller$/, '')
  end
end

示例: Foo::Bar::BazController => Foo::Bar

暂无
暂无

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

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