Как вы программно находите пространство имен / имя модуля в Ruby on Rails?
-
02-07-2019 - |
Вопрос
Как мне найти имя пространства имен или модуля '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]
Другие советы
Это должно сработать:
def get_module_name
@module_name = self.class.to_s.split("::").first
end
Для простого случая Вы можете использовать :
self.class.parent
Это сработало бы, если бы у контроллера действительно было имя модуля, но вернуло бы имя контроллера, если бы этого не было.
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" для контроллера с пространством имен.Использование метода [] string с регулярным выражением, которое возвращает все, что находится до двух двоеточий, или nil, если ничего нет.Затем он изменяет это на нижний регистр ("try" присутствует на случай, если пространства имен нет и возвращается nil).Тогда у нас остается либо пространство имен, либо nil.Затем он просто отображает частичное с пространством имен или без него, например no namespace:
app/views/_nav.html.erb
или в пространстве имен admin:
app/views/admin/_nav.html.erb
Конечно, эти частичные элементы должны существовать для каждого пространства имен, в противном случае возникает ошибка.Теперь навигация по каждому пространству имен будет отображаться для каждого контроллера без необходимости менять какой-либо контроллер или представление.
my_class.name.underscore.split('/').slice(0..-2)
или
my_class.name.split('::').slice(0..-2)
Я не думаю, что существует очиститель кстати, и я видел это где-то еще
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