2

I have two classes

class ClassOne def do_something [...] end end class ClassTwo def do_something [...] end end 

I am getting a class name (either ClassOne or ClassTwo) from the database and I want to call do_something in that class

so I have

class_name = "ClassOne" 

and I want to call ClassOne.do_something or ClassTwo.do_something if class_name is equals to "ClassTwo".

I can't do it using a simple if condition, I have many classes and am checking if the class exists before calling..

Is there a way to do it?

3 Answers 3

6

For vanilla ruby:

Kernel.const_get('ClassOne').do_something 

For Rails:

'ClassOne'.constantize.do_something 
Sign up to request clarification or add additional context in comments.

3 Comments

I am getting an undefined method 'do_something' for #<Class:0x9c9026c> (NoMethodError) Any idea why?
You need to def self.do_something to use it as a class method.
Or leave the classes are they are and call Kernel.const_get('ClassOne').new.do_something / 'ClassOne'.constantize.new.do_something
2

Although you can convert any arbitrary string to a class using constantize from ActiveSupport if available, this could cause exceptions if users can submit the string in question. It might be safer to use a case:

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

The same thing could be achieved with a Hash or Array defining valid classes and testing with either [] or include? accordingly.

3 Comments

Let alone potential security issues as the user could discover all your class names or potential reveal the value of constants if they can generate the string.
The strings are not user generated. In the future I might be adding new classes and I don't want to update this part of the code every time a new class is available..
Remember you can pass around classes as variables within the same Ruby process, so there's no need to keep them as strings. It's fairly common to do things like using_class = condition ? ClassA : ClassB and then operate on that variable as if it was the class itself. Duck-typing makes this possible.
-1

eval("#{classname}.do_something")

Note: you have to change your code to def self.do_something, otherwise these are instance methods. It looks like this is your intention.

1 Comment

No, please, no. eval is not something you just whip out to do something like this. This is best reserved for situations where there is simply no other way.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.