How to instantiate class from name string in Rails?
Solution 1
klass = Object.const_get "ClassName"
about class methods
class KlassExample
def self.klass_method
puts "Hello World from Class method"
end
end
klass = Object.const_get "KlassExample"
klass.klass_method
irb(main):061:0> klass.klass_method
Hello World from Class method
Solution 2
Others may also be looking for an alternative that does not throw an error if it fails to find the class. safe_constantize
is just that.
class MyClass
end
"my_class".classify.safe_constantize.new # #<MyClass:0x007fec3a96b8a0>
"omg_evil".classify.safe_constantize.new # nil
Solution 3
You can simply convert a string and initialize a class out of it by:
klass_name = "Module::ClassName"
klass_name.constantize
To initialize a new object:
klass_name.constantize.new
I hope this turns out to be helpful. Thanks!
Solution 4
I'm surprised nobody is considering security and hacking in their responses. Instantiation of an arbitrary string that likely came even indirectly from user input is asking for trouble and hacking. We all should/must be whitelisting unless we're sure the string is fully controlled and monitored
def class_for(name)
{
"foo" => Foo,
"bar" => Bar,
}[name] || raise UnknownClass
end
class_for(name_wherever_this_came_from).create!(params_somehow)
How you would know the appropriate params arbitrarily without having a whitelist would be challenging but you get the idea.
Related videos on Youtube
Comments
-
Vjatseslav Gedrovits almost 2 years
How we can instantiate class from it's name string in Ruby-on-Rails?
For example we have it's name in database in format like "ClassName" or "my_super_class_name".
How we can create object from it?
Solution:
Was looking for it myself, but not found, so here it is. Ruby-on-Rails API Method
name = "ClassName" instance = name.constantize.new
It can be even not formatted, we can user string method .classify
name = "my_super_class" instance = name.classify.constantize.new
Of course maybe this is not very 'Rails way', but it solves it's purpose.
-
quandrum over 11 yearsJust FYI, constantize is an ActiveSupport convenience method that does
Object.const_get
and Classify is an ActiveSupport method that tries to turn a string into a standard class formatting. What you are doing is identical to Evginey's answer, with some additional checks. While constantize is probably a better solution(because it does sanity checks), it helps to understand the tools you using. -
Vjatseslav Gedrovits over 11 yearsThank you for this, to be honest didn't checked what it do in manual.
-
-
Vjatseslav Gedrovits over 11 yearsWith that you cannot access class methods. My solution above works correctly with class methods.
-
Vjatseslav Gedrovits over 11 years
Loading development environment (Rails 3.2.9) irb(main):001:0> name = "PartnerGateway" => "PartnerGateway" irb(main):002:0> klass = name.constantize.new => #<PartnerGateway id: nil, name: nil, partner_id: nil, gateway: nil, changed_by_id: nil, deleted_at: nil, created_at: nil, updated_at: nil> irb(main):003:0> klass.name => nil
-
Vjatseslav Gedrovits over 11 years
irb(main):005:0> klass2 = Object.const_get name => PartnerGateway(id: integer, name: string, partner_id: integer, gateway: string, changed_by_id: integer, deleted_at: datetime, created_at: datetime, updated_at: datetime) irb(main):006:0> klass2.name => "PartnerGateway" irb(main):008:0> klass2.id NoMethodError: undefined method
id' for #<Class:0xac3e4c0>` -
Vjatseslav Gedrovits over 11 yearsWith my method you can do the both ways. "KlassExample".constantize.self_method_name and klass = "KlassExample".constantize.new klass.normal_method
-
Eugene Rourke over 11 yearsyeah... it don't prove anything you obviously don't call new them you use "Object.const_get" try klass2.new.name
-
Eugene Rourke over 11 yearsWell, so that can be done by klass2 = (Object.const_get name).new like you do with klass = name.constantize.new
-
Eugene Rourke over 11 yearsthat your problem? why do you so insist on proving your way somehow better when it obviously do the exact same thing?
-
Vjatseslav Gedrovits over 11 yearsYou think that your solution is elegant and correct? Check top comment please.
-
TiSer almost 4 yearsDon't use this! It's very vulnerable approach: praetorian.com/blog/ruby-unsafe-reflection-vulnerabilities
-
Pushp Raj Saurabh almost 4 years@TiSer Can you please explain how is it vulnerable as long as I don't constantize a string from my request parameters?
-
Pushp Raj Saurabh almost 4 yearsThanks for the link to the blog. This is quite helpful. As long as we use constantize without passing any request params to it and enclose it in a private function, I don't see a threat.
-
Pushp Raj Saurabh almost 4 yearsThis line in the blog shared by you is extremely critical to keep in mind when working with reflections: Reflection is used to modifying the nature of a program at runtime and should not be used with Strings from untrusted sources.
-
TiSer almost 4 yearsIn your direct example - yes, but I don't know where you will want to make such object transformation from single whole string to a class in real world.