web-dev-qa-db-fra.com

Comment trouvez-vous le nom de l'espace de noms / module par programme dans Ruby on Rails?

Comment trouver le nom de l'espace de noms ou du module 'Foo' dans le filtre ci-dessous?

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = ???
  end
end


class Foo::BarController < ApplicationController
  before_filter :get_module_name
end
54
Steropes

Aucune de ces solutions ne considère une constante avec plusieurs modules parents. Par exemple:

A::B::C

À partir de Rails 3.2.x, vous pouvez simplement:

"A::B::C".deconstantize #=> "A::B"

Depuis Rails 3.1.x vous pouvez:

constant_name = "A::B::C"
constant_name.gsub( "::#{constant_name.demodulize}", '' )

En effet, #demodulize est l'opposé de #deconstantize:

"A::B::C".demodulize #=> "C"

Si vous devez vraiment le faire manuellement, essayez ceci:

constant_name = "A::B::C"
constant_name.split( '::' )[0,constant_name.split( '::' ).length-1]
97
Jason Harrelson

Cela devrait le faire:

  def get_module_name
    @module_name = self.class.to_s.split("::").first
  end
22
Daniel Lucraft

Pour le cas simple, vous pouvez utiliser:

self.class.parent
22
Hettomei

Cela fonctionnerait si le contrôleur avait un nom de module, mais retournerait le nom du contrôleur si ce n'était pas le cas.

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.name.split("::").first
  end
end

Cependant, si nous changeons cela un peu pour:

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

Vous pouvez déterminer si la classe a un nom de module ou non et renvoyer autre chose que le nom de classe que vous pouvez tester.

6
Steropes

my_class.name.underscore.split('/').slice(0..-2)

ou

my_class.name.split('::').slice(0..-2)

2
sandstrom

Je sais que c'est un vieux fil, mais je viens de découvrir la nécessité d'avoir une navigation distincte en fonction de l'espace de noms du contrôleur. La solution que j'ai trouvée était la suivante dans la disposition de mon application:

<%= render "#{controller.class.name[/^(\w*)::\w*$/, 1].try(:downcase)}/nav" %>

Ce qui semble un peu compliqué mais fait essentiellement ce qui suit - il prend le nom de la classe de contrôleur, qui serait par exemple "People" pour un contrôleur sans espace de nom, et "Admin :: Users" pour un contrôleur à espace de nom. Utilisation de la méthode de chaîne [] avec une expression régulière qui renvoie n'importe quoi avant deux deux points, ou nil s'il n'y a rien. Il change ensuite cela en minuscules (le "try" est là au cas où il n'y a pas d'espace de noms et nil est retourné). Cela nous laisse alors soit avec le namespace soit avec nil. Ensuite, il rend simplement le partiel avec ou sans l'espace de noms, par exemple aucun espace de noms:

app/views/_nav.html.erb

ou dans l'espace de noms admin:

app/views/admin/_nav.html.erb

Bien sûr, ces partiels doivent exister pour chaque espace de noms, sinon une erreur se produit. Maintenant, la navigation pour chaque espace de noms apparaîtra pour chaque contrôleur sans avoir à changer de contrôleur ou de vue.

2

Je ne pense pas qu'il existe un moyen plus propre, et je l'ai vu ailleurs

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.name.split("::").first
  end
end
1
koke

Je recommande gsub au lieu de split. Il est plus efficace que split étant donné que vous n'avez besoin d'aucun autre nom de module.

class ApplicationController < ActionController::Base
  def get_module_name
    @module_name = self.class.to_s.gsub(/::.*/, '')
  end
end
1
Pablo Cantero

Avec de nombreux sous-modules:

module ApplicationHelper
  def namespace
    controller.class.name.gsub(/(::)?\w+Controller$/, '')
  end
end

Exemple: Foo::Bar::BazController => Foo::Bar

0
Cyril