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.

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


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

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

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")

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").


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`
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.