90

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.

Vjatseslav Gedrovits
  • 1,191
  • 1
  • 9
  • 12
  • 4
    Just 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. – quandrum Dec 28 '12 at 14:50
  • Thank you for this, to be honest didn't checked what it do in manual. – Vjatseslav Gedrovits Dec 28 '12 at 15:58

4 Answers4

93
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
Eugene Rourke
  • 4,934
  • 1
  • 22
  • 24
  • With that you cannot access class methods. My solution above works correctly with class methods. – Vjatseslav Gedrovits Dec 28 '12 at 13:45
  • `Loading development environment (Rails 3.2.9) irb(main):001:0> name = "PartnerGateway" => "PartnerGateway" irb(main):002:0> klass = name.constantize.new => # irb(main):003:0> klass.name => nil` – Vjatseslav Gedrovits Dec 28 '12 at 14:20
  • `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 #` – Vjatseslav Gedrovits Dec 28 '12 at 14:20
  • With my method you can do the both ways. "KlassExample".constantize.self_method_name and klass = "KlassExample".constantize.new klass.normal_method – Vjatseslav Gedrovits Dec 28 '12 at 14:28
  • yeah... it don't prove anything you obviously don't call new them you use "Object.const_get" try klass2.new.name – Eugene Rourke Dec 28 '12 at 14:30
  • Well, so that can be done by klass2 = (Object.const_get name).new like you do with klass = name.constantize.new – Eugene Rourke Dec 28 '12 at 14:33
  • that your problem? why do you so insist on proving your way somehow better when it obviously do the exact same thing? – Eugene Rourke Dec 28 '12 at 14:41
  • You think that your solution is elegant and correct? Check top comment please. – Vjatseslav Gedrovits Dec 28 '12 at 15:56
50

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 
maninalift
  • 703
  • 6
  • 10
19

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!

Pushp Raj Saurabh
  • 1,174
  • 12
  • 16
  • Don't use this! It's very vulnerable approach: https://www.praetorian.com/blog/ruby-unsafe-reflection-vulnerabilities – TiSer Jun 17 '20 at 19:19
  • 2
    @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 Jun 18 '20 at 19:47
  • 1
    Thanks 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 Jun 20 '20 at 11:48
  • This 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. – Pushp Raj Saurabh Jun 20 '20 at 11:54
  • 1
    In 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. – TiSer Jun 26 '20 at 14:36
7

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.

RubesMN
  • 939
  • 1
  • 12
  • 22