Como você encontrar o nome do namespace / módulo de programação em Ruby on Rails?
-
02-07-2019 - |
Pergunta
Como faço para encontrar o nome do namespace ou módulo 'Foo' no filtro abaixo?
class ApplicationController < ActionController::Base
def get_module_name
@module_name = ???
end
end
class Foo::BarController < ApplicationController
before_filter :get_module_name
end
Solução
Nenhuma destas soluções considerar uma constante com vários módulos principais. Por exemplo:
A::B::C
A partir de Rails 3.2.x você pode simplesmente:
"A::B::C".deconstantize #=> "A::B"
A partir de Rails 3.1.x, você pode:
constant_name = "A::B::C"
constant_name.gsub( "::#{constant_name.demodulize}", '' )
Isto porque #demodulize é o oposto do #deconstantize:
"A::B::C".demodulize #=> "C"
Se você realmente precisa fazer isso manualmente, tente o seguinte:
constant_name = "A::B::C"
constant_name.split( '::' )[0,constant_name.split( '::' ).length-1]
Outras dicas
Isso deve fazê-lo:
def get_module_name
@module_name = self.class.to_s.split("::").first
end
Para o caso simples, você pode usar:
self.class.parent
Isso poderia funcionar se o controlador tinha um nome do módulo, mas gostaria de voltar o nome do controlador se ele não o fez.
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.name.split("::").first
end
end
No entanto, se alterar esta um pouco para:
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
Você pode determinar se a classe tem um nome de módulo ou não e retorno outra coisa que não seja o nome da classe que você pode testar para.
Eu sei que esta é uma discussão antiga, mas eu só vim através a necessidade de ter de navegação separado, dependendo do namespace do controlador. A solução que eu vim com foi isso no meu layout do aplicativo:
<%= render "#{controller.class.name[/^(\w*)::\w*$/, 1].try(:downcase)}/nav" %>
O que parece um pouco complicado, mas basicamente faz o seguinte - que leva o nome da classe do controlador, que seria, por exemplo, "Pessoas" para um controlador não-namespaced e "admin :: Users" para um namespace. Utilizando o método de string [] com uma expressão regular que retorna nada antes de dois dois pontos, ou nulo se não há nada. Em seguida, ele muda nesse caso, para diminuir (a "tentativa" é lá em caso de não haver espaço para nome e nil é retornado). Isso, então, deixa-nos tanto com o namespace ou nula. Em seguida, ele simplesmente torna a parcial com ou sem o namespace, por exemplo, não namespace:
app/views/_nav.html.erb
ou no namespace admin:
app/views/admin/_nav.html.erb
É claro que essas parciais têm de existir para cada namespace caso contrário ocorre um erro. Agora, a navegação para cada namespace aparecerá para cada controlador sem ter que mudar qualquer controlador ou exibição.
my_class.name.underscore.split('/').slice(0..-2)
ou
my_class.name.split('::').slice(0..-2)
Eu não acho que há um mais limpa maneira, e eu já vi isso em outro lugar
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.name.split("::").first
end
end
Eu recomendo gsub
vez de split
. É mais eficaz que split
dado que você não precisa de nenhum outro nome do módulo.
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.to_s.gsub(/::.*/, '')
end
end
Com muitos sub-módulos:
module ApplicationHelper
def namespace
controller.class.name.gsub(/(::)?\w+Controller$/, '')
end
end
Exemplo: Foo::Bar::BazController
=> Foo::Bar