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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/133357/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 20:41:29  来源:igfitidea点击:

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

ruby-on-railsrubynamespaces

提问by Steropes

How do I find the name of the namespace or module 'Foo' in the filter below?

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

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


class Foo::BarController < ApplicationController
  before_filter :get_module_name
end

回答by Jason Harrelson

None of these solutions consider a constant with multiple parent modules. For instance:

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

A::B::C

As of Rails 3.2.x you can simply:

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

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

As of Rails 3.1.x you can:

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

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

This is because #demodulize is the opposite of #deconstantize:

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

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

If you really need to do this manually, try this:

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

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

回答by Hettomei

For the simple case, You can use :

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

self.class.parent

回答by Daniel Lucraft

This should do it:

这应该这样做:

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

回答by Steropes

This would work if the controller did have a module name, but would return the controller name if it did not.

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

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

However, if we change this up a bit to:

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

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

You can determine if the class has a module name or not and return something else other than the class name that you can test for.

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

回答by Dave Hollingworth

I know this is an old thread, but I just came across the need to have separate navigation depending on the namespace of the controller. The solution I came up with was this in my application layout:

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

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

Which looks a bit complicated but basically does the following - it takes the controller class name, which would be for example "People" for a non-namespaced controller, and "Admin::Users" for a namespaced one. Using the [] string method with a regular expression that returns anything before two colons, or nil if there's nothing. It then changes that to lower case (the "try" is there in case there is no namespace and nil is returned). This then leaves us with either the namespace or nil. Then it simply renders the partial with or without the namespace, for example no namespace:

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

app/views/_nav.html.erb

or in the admin namespace:

或在 admin 命名空间中:

app/views/admin/_nav.html.erb

Of course these partials have to exist for each namespace otherwise an error occurs. Now the navigation for each namespace will appear for every controller without having to change any controller or view.

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

回答by sandstrom

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

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

or

或者

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

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

回答by Horacio

For Rails 6.1

对于 Rails 6.1

self.class.module_parent

self.class.module_parent



Hettomei answer works fine up to Rails 6.0

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

DEPRECATION WARNING: Module#parenthas been renamed to module_parent. parentis deprecated and will be removed in Rails 6.1.

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

回答by Horacio

I don't think there is a cleanerway, and I've seen this somewhere else

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

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

回答by Pablo Cantero

I recommend gsubinstead of split. It's more effective that splitgiven that you don't need any other module name.

我推荐gsub而不是split. split鉴于您不需要任何其他模块名称,它更有效。

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

回答by Cyril

With many sub-modules:

有许多子模块:

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

Example: Foo::Bar::BazController=> Foo::Bar

例子:Foo::Bar::BazController=>Foo::Bar