2012-03-08 2 views
2

J'ai deux classesGet classe par son nom dans Ruby

class ClassOne 
    def do_something 
     [...] 
    end 
end 

class ClassTwo 
    def do_something 
     [...] 
    end 
end 

Je reçois un nom de classe (soit ClassOne ou ClassTwo) de la base de données et je veux appeler do_something dans cette classe

donc je ai

class_name = "ClassOne" 

et je veux appeler ClassOne.do_something ou ClassTwo.do_something si class_name est égal à "ClassTwo".

je ne peux pas le faire à l'aide d'un simple si la condition, j'ai beaucoup de classes et je vérifie si la classe existe avant d'appeler ..

Est-il possible de le faire?

Répondre

6

Pour le rubis de vanille:

Kernel.const_get('ClassOne').do_something 

Pour Rails:

'ClassOne'.constantize.do_something 
+0

Je reçois une 'méthode non définie 'do_something' pour # (NoMethodError)' Une idée pourquoi? – applechief

+1

Vous devez 'def self.do_something' pour l'utiliser comme méthode de classe. – sgtFloyd

+2

Ou laisser les classes sont elles et appellent 'Kernel.const_get ('ClassOne'). New.do_something' /' 'ClassOne'.constantize.new.do_something' –

2

Bien que vous pouvez convertir une chaîne arbitraire à une classe en utilisant constantize de ActiveSupport le cas échéant, cela pourrait provoquer des exceptions si les utilisateurs peuvent soumettre la chaîne en question. Il pourrait être plus sûr d'utiliser un case:

case (with_class) 
when 'ClassOne', 'ClassTwo' 
    with_class.constantize.do_something 
else 
    raise "Um, what are you doing?" 
end 

pourrait être atteint la même chose avec un Hash ou Array définissant les classes valides et les tests soit [] ou include? en conséquence.

+1

Laissé seul les problèmes de sécurité potentiels que l'utilisateur pourrait découvrir toute votre classe Les noms ou potentiels révèlent la valeur des constantes s'ils peuvent générer la chaîne. –

+0

Les chaînes ne sont pas générées par l'utilisateur. À l'avenir, je pourrais ajouter de nouvelles classes et je ne veux pas mettre à jour cette partie du code chaque fois qu'une nouvelle classe est disponible. – applechief

+0

Rappelez-vous que vous pouvez faire circuler des classes en tant que variables dans le même processus Ruby. pour les garder comme des ficelles. Il est assez courant de faire des choses comme 'using_class = condition? ClassA: ClassB' et ensuite opérer sur cette variable comme si c'était la classe elle-même. Canard-typage rend cela possible. – tadman

-1

eval("#{classname}.do_something")

Note: vous devez changer votre code à def self.do_something, sinon ce sont des méthodes d'instance. Il semble que ce soit votre intention.

+0

Non, s'il vous plaît, non. 'eval' n'est pas quelque chose que vous venez de faire pour faire quelque chose comme ça. C'est mieux réservé aux situations où il n'y a tout simplement pas d'autre moyen. – tadman