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