ruby convertit le nom de la classe en chaîne en classe réelle

87

Comment appeler une classe à partir d'une chaîne contenant ce nom de classe à l'intérieur? (Je suppose que je pourrais faire le cas / quand mais cela semble moche.)

La raison pour laquelle je demande est que j'utilise le acts_as_commentableplugin, entre autres, et que ceux-ci stockent le commentable_type sous forme de colonne. Je veux pouvoir appeler n'importe quelle classe commentable particulière pour en faire un find(commentable_id).

Merci.

non trié
la source

Réponses:

131

Je pense que ce que tu veux c'est constantize

C'est une construction RoR. Je ne sais pas s'il y en a un pour le noyau rubis

Jamie Wong
la source
parfait, c'est exactement ce que je cherchais.
non trié
40
Pour Ruby ordinaire, vous utiliseriez Module.const_get. L'avantage de constantizeest que cela fonctionne même avec des espaces de noms profondément imbriqués, vous pouvez donc faire 'Functional::Collections::LazyList'.constantizeet obtenir la classe LazyList à partir du module Collections dans le module Functional, alors qu'avec const_get, vous devez faire quelque chose comme 'Functional::Collections::LazyList'.split('::').reduce(Module, :const_get).
Chuck
45
"Object".constantize # => Object
jtbandes
la source
Veuillez noter qu'il .constantizes'agit d'une méthode Rails, vous ne la trouverez pas en Ruby brut
Edgar Ortega
35

Étant donné une chaîne, premier appel classify pour créer un nom de classe (toujours une chaîne), puis appelez constantize pour essayer de trouver et de renvoyer la constante de nom de classe (notez que les noms de classe sont des constantes ).

some_string.classify.constantize
user664833
la source
10
Vous devriez utiliser camelize au lieu de classify car classify est pour les noms de table et ne gère pas très bien la pluralisation.
Peter Brown
1
Merci! c'est génial!
duykhoa
2
Votre réponse est vraiment précieuse, mais vous devriez utiliser "titleize" pour le nom de la table qui inclut par espace, et supprimer les espaces blancs de la chaîne pour donner un sens au nom complet de la classe.
SSR
22

Je sais que c'est une vieille question mais je veux juste laisser cette note, cela peut être utile pour d'autres.

En Ruby simple, Module.const_getpeut trouver des constantes imbriquées. Par exemple, ayant la structure suivante:

module MyModule
  module MySubmodule
    class MyModel
    end
  end
end

Vous pouvez l'utiliser comme suit:

Module.const_get("MyModule::MySubmodule::MyModel")
MyModule.const_get("MySubmodule")
MyModule::MySubmodule.const_get("MyModel")
Edgar Ortega
la source
7

Quand ActiveSupport est disponible (par exemple dans Rails): String#constantizeou String#safe_constantize, c'est-à-dire "ClassName".constantize.

En pur Ruby:, Module#const_gettypiquement Object.const_get("ClassName").

Dans les rubis récents, les deux fonctionnent avec des constantes imbriquées dans des modules, comme dans Object.const_get("Outer::Inner").

skalee
la source
6

Si vous souhaitez convertir une chaîne en nom de classe actuall pour accéder au modèle ou à toute autre classe

str = "group class"

> str.camelize.constantize 'or'
> str.classify.constantize 'or'
> str.titleize.constantize

Example :
  def call_me(str)
    str.titleize.gsub(" ","").constantize.all
  end

Call method : call_me("group class")

Result:
  GroupClass Load (0.7ms) SELECT `group_classes`.* FROM `group_classes`
SSR
la source