Как найти имя пространства имен или модуля Foo в фильтре ниже?
class ApplicationController < ActionController::Base
def get_module_name
@module_name = ???
end
end
class Foo::BarController < ApplicationController
before_filter :get_module_name
end





Это должно сделать это:
def get_module_name
@module_name = self.class.to_s.split("::").first
end
нет, вы не можете, на самом деле demodulize возвращает имя класса без пространств имен
Как отметил Джейсон Харрельсон, при этом не учитываются несколько родительских модулей.
Я не думаю, что есть способ очиститель, и я видел это где-то еще
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
@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
Вы можете определить, есть ли у класса имя модуля или нет, и вернуть что-то еще, кроме имени класса, которое вы можете проверить.
Я знаю, что это старый поток, но я только что столкнулся с необходимостью иметь отдельную навигацию в зависимости от пространства имен контроллера. Решение, которое я придумал, заключалось в следующем в моем макете приложения:
<%= render "#{controller.class.name[/^(\w*)::\w*$/, 1].try(:downcase)}/nav" %>
Это выглядит немного сложным, но в основном делает следующее - он принимает имя класса контроллера, которое может быть, например, «People» для контроллера без пространства имен и «Admin :: Users» для контроллера с пространством имен. Использование строкового метода [] с регулярным выражением, которое возвращает что-либо до двух двоеточий или nil, если ничего нет. Затем он меняет его на нижний регистр («попытка» присутствует в случае отсутствия пространства имен и возвращается nil). Это оставляет нам либо пространство имен, либо ноль. Затем он просто отображает партиал с пространством имен или без него, например без пространства имен:
app/views/_nav.html.erb
или в пространстве имен администратора:
app/views/admin/_nav.html.erb
Конечно, эти частичные данные должны существовать для каждого пространства имен, иначе произойдет ошибка. Теперь навигация для каждого пространства имен будет отображаться для каждого контроллера без необходимости изменять какой-либо контроллер или представление.
Ни одно из этих решений не рассматривает константу с несколькими родительскими модулями. Например:
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]
Этот вопрос был написан до Rails 3, и модули на самом деле не поддерживались. Обновлен принятый ответ, чтобы отразить более актуальные версии!
демодуляция была ключевым ответом
Я рекомендую gsub вместо split. Это более эффективно, чем split, учитывая, что вам не нужно другое имя модуля.
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.to_s.gsub(/::.*/, '')
end
end
my_class.name.underscore.split('/').slice(0..-2)
или же
my_class.name.split('::').slice(0..-2)
В простом случае вы можете использовать:
self.class.parent
Это доступно только в последних версиях Rubies? Не могу поверить, что существует так много ответов о «темной магии», и никто не ссылался на этот метод до 2015 года.
Не могу найти в документе ... Я даже не могу воспроизвести :) Я предпочитаю этот ответ сейчас: stackoverflow.com/questions/14778816/…: class C; end; C.new.class.superclass -> Объект
Думаю, мое решение сработало из-за рельсов: rubydoc.info/docs/rails/4.1.7/Module#parent-instance_method
Со многими подмодулями:
module ApplicationHelper
def namespace
controller.class.name.gsub(/(::)?\w+Controller$/, '')
end
end
Пример: Foo::Bar::BazController => Foo::Bar
Никто не упомянул использование 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
self.class.module_parent
Ответ Hettomei отлично работает до Rails 6.0
DEPRECATION WARNING:
Module#parenthas been renamed tomodule_parent.parentis deprecated and will be removed in Rails 6.1.
module_parent существует с Rails 6.0
или вы также можете использовать self.class.name.demodulize для этой цели.