Как найти имя пространства имен/модулей в 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

Ответ 1

Ни одно из этих решений не рассматривает константу с несколькими родительскими модулями. Например:

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]

Ответ 2

Это должно сделать это:

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

Ответ 3

Для простого случая вы можете использовать:

self.class.parent

Ответ 4

Это будет работать, если у контроллера было имя модуля, но оно вернет имя контроллера, если это не так.

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

Вы можете определить, имеет ли класс имя модуля или нет, и вернуть что-то другое, кроме имени класса, которое вы можете проверить.

Ответ 5

Я знаю, что это старый поток, но я просто столкнулся с необходимостью иметь отдельную навигацию в зависимости от пространства имен контроллера. Решение, которое я придумал, было в моем макете приложения:

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

Что выглядит несколько сложнее, но в основном делает следующее: для имени контроллера используется имя класса, которое будет, например, "Люди" для контроллера без имен, и "Admin:: Users" для пространства с именами. Используя метод [] string с регулярным выражением, которое возвращает что-либо перед двумя двоеточиями, или nil, если нет. Затем он меняет это на нижний регистр ( "try" есть там, где нет пространства имен и возвращается nil). Это оставляет нас либо с пространством имен, либо с nil. Затем он просто отображает частичное с пространством имен или без него, например без пространства имен:

app/views/_nav.html.erb

или в пространстве имен admin:

app/views/admin/_nav.html.erb

Конечно, эти частичные должны существовать для каждого пространства имен, иначе возникает ошибка. Теперь для каждого пространства имен будет отображаться навигация для каждого контроллера без необходимости изменения какого-либо контроллера или просмотра.

Ответ 6

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

или

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

Ответ 7

Я не думаю, что есть более чистый способ, и я видел это где-то еще.

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

Ответ 8

Я рекомендую gsub вместо split. Это более эффективно, чем split, учитывая, что вам не нужно другое имя модуля.

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

Ответ 9

Со многими подмодулями:

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

Пример: Foo::Bar::BazController = > Foo::Bar