ruby convert class name in string to actual class
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 commentab开发者_运维技巧le_type as a column. I want to be able to call whatever particular commentable class to do a find(commentable_id)
on it.
Thanks.
I think what you want is constantize
That's an RoR construct. I don't know if there's one for ruby core
"Object".constantize # => Object
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
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")
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")
.
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`
精彩评论