112

How do I call a class from a string containing that class name inside of it? (I guess I could do case/when but that seems ugly.)

The reason I ask is because I'm using the acts_as_commentable plugin, among others, and these store the commentable_type as a column. I want to be able to call whatever particular commentable class to do a find(commentable_id) on it.

Thanks.

6 Answers 6

153

I think what you want is constantize

That's an RoR construct. I don't know if there's one for ruby core

Sign up to request clarification or add additional context in comments.

2 Comments

perfect, that's just what I was looking for.
For plain Ruby, you'd use Module.const_get. The advantage of constantize is that it works even with deeply nested namespaces, so you could do 'Functional::Collections::LazyList'.constantize and get the class LazyList from the module Collections in the module Functional, whereas with const_get, you'd have to do something like 'Functional::Collections::LazyList'.split('::').reduce(Module, :const_get).
53
"Object".constantize # => Object

1 Comment

Please note that .constantize is a Rails method, you won't find it in plain Ruby
52

It depends on the string...

If it already has the proper shape (casing, pluralization, etc), and would otherwise map directly to an object, then:

Rails:

'User'.constantize # => User

Ruby:

Module.const_get 'User' # => User

But otherwise (note the difference in casing):

'user'.constantize # => NameError: wrong constant name user

Module.const_get 'user' # => NameError: wrong constant name user

Therefore, you must ask... is the source string singular or plural (does it reference a table or not?), is it multi-word and AlreadyCamelCased or is_it_underscored?

With Rails you have these tools at your disposal:

Use camelize to convert strings to UpperCamelCase strings, even handling underscores and forward slashes:

'object'.constantize # => NameError: wrong constant name object
'object'.camelize # => "Object"
'object'.camelize.constantize # => Object
'active_model/errors'.camelize # => "ActiveModel::Errors"
'active_model/errors'.camelize.constantize # => ActiveModel::Errors

Use classify to convert a string, which may even be plural (i.e. perhaps it's a table reference), to create a class name (still a string), then call constantize to try to find and return the class name constant (note that in Ruby class names are constants):

'users'.classify => "User" # a string
'users'.classify.constantize # => User

'user'.classify => "User" # a string
'user'.classify.constantize # => User

'ham_and_eggs'.classify # => "HamAndEgg"

In POR (Plain Old Ruby), you have capitalize, but it only works for the first word:

Module.const_get 'user'.capitalize => User

...otherwise you must use fundamental tools like strip, split, map, join, etc. to achieve the appropriate manipulation:

class HamAndEgg end # => nil
Module.const_get ' ham and eggs '.strip.gsub(/s$/,'').split(' ').map{|w| w.capitalize}.join # => HamAndEgg

3 Comments

You should use camelize instead of classify since classify is for table names and doesn't handle pluralization very well.
Your answer is really valuable, but you should use "titleize" for table name which includes by space, and remove white space from string to make meaning full class name.
@SSR yes, you could: ' ham and eggs '.titleize.gsub(/ /,'').constantize # => HamAndEggs
25

I know this is an old question but I just want to leave this note, it may be helpful for others.

In plain Ruby, Module.const_get can find nested constants. For instance, having the following structure:

module MyModule
  module MySubmodule
    class MyModel
    end
  end
end

You can use it as follows:

Module.const_get("MyModule::MySubmodule::MyModel")
MyModule.const_get("MySubmodule")
MyModule::MySubmodule.const_get("MyModel")

Comments

7

When ActiveSupport is available (e.g. in Rails): String#constantize or String#safe_constantize, that is "ClassName".constantize.

In pure Ruby: Module#const_get, typically Object.const_get("ClassName").

In recent rubies, both work with constants nested in modules, like in Object.const_get("Outer::Inner").

Comments

5

If you want to convert string to actuall class name to access model or any other class

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`

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.