¿Cómo encuentra el nombre del espacio de nombres / módulo mediante programación en Ruby on Rails?
-
02-07-2019 - |
Pregunta
¿Cómo puedo encontrar el nombre del espacio de nombres o el módulo 'Foo' en el filtro a continuación?
class ApplicationController < ActionController::Base
def get_module_name
@module_name = ???
end
end
class Foo::BarController < ApplicationController
before_filter :get_module_name
end
Solución
Ninguna de estas soluciones considera una constante con múltiples módulos principales. Por ejemplo:
A::B::C
A partir de Rails 3.2.x puede simplemente:
"A::B::C".deconstantize #=> "A::B"
A partir de Rails 3.1.x puede:
constant_name = "A::B::C"
constant_name.gsub( "::#{constant_name.demodulize}", '' )
Esto se debe a que #demodulize es lo opuesto a #deconstantize:
"A::B::C".demodulize #=> "C"
Si realmente necesitas hacer esto manualmente, prueba esto:
constant_name = "A::B::C"
constant_name.split( '::' )[0,constant_name.split( '::' ).length-1]
Otros consejos
Esto debería hacerlo:
def get_module_name
@module_name = self.class.to_s.split("::").first
end
Para el caso simple, puede usar:
self.class.parent
Esto funcionaría si el controlador tuviera un nombre de módulo, pero devolvería el nombre del controlador si no lo tuviera.
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.name.split("::").first
end
end
Sin embargo, si cambiamos esto un poco 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
Puede determinar si la clase tiene un nombre de módulo o no y devolver algo más que el nombre de la clase que puede probar.
Sé que este es un subproceso antiguo, pero acabo de encontrar la necesidad de tener una navegación separada dependiendo del espacio de nombres del controlador. La solución que se me ocurrió fue esta en el diseño de mi aplicación:
<%= render "#{controller.class.name[/^(\w*)::\w*$/, 1].try(:downcase)}/nav" %>
Lo que parece un poco complicado pero básicamente hace lo siguiente: toma el nombre de la clase del controlador, que sería, por ejemplo, " Gente " para un controlador sin espacio de nombres, y "Admin :: Usuarios" para un espacio de nombre. Usando el método de cadena [] con una expresión regular que devuelve cualquier cosa antes de dos puntos, o nil si no hay nada. Luego lo cambia a minúsculas (el " intentar " está ahí en caso de que no haya espacio de nombres y se devuelva nil). Esto nos deja con el espacio de nombres o nulo. Luego simplemente procesa el parcial con o sin el espacio de nombres, por ejemplo, sin espacio de nombres:
app/views/_nav.html.erb
o en el espacio de nombres de administrador:
app/views/admin/_nav.html.erb
Por supuesto, estos parciales tienen que existir para cada espacio de nombres; de lo contrario, se produce un error. Ahora la navegación para cada espacio de nombre aparecerá para cada controlador sin tener que cambiar ningún controlador o vista.
my_class.name.underscore.split('/').slice(0..-2)
o
my_class.name.split('::').slice(0..-2)
No creo que haya una manera más limpia , y he visto esto en otro lugar
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.name.split("::").first
end
end
Recomiendo gsub
en lugar de split
. Es más efectivo que split
dado que no necesita ningún otro nombre de módulo.
class ApplicationController < ActionController::Base
def get_module_name
@module_name = self.class.to_s.gsub(/::.*/, '')
end
end
Con muchos submódulos:
module ApplicationHelper
def namespace
controller.class.name.gsub(/(::)?\w+Controller$/, '')
end
end
Ejemplo: Foo :: Bar :: BazController
= > Foo::Bar