39

I am trying to create a new class to that will inherit from ActiveRecord::Base the class needs to be dynamically generated from a string

"general_systems".camelize.singularize = Class.new < ActiveRecord::Base

However I keep getting the error:

undefined method `singularize=' for "GeneralSystems":String

I've also tried to constantize the string

>> foo = "general_systems".camelize.singularize
=> "GeneralSystem"
>> foo.constantize
NameError: uninitialized constant GeneralSystem
    from /var/lib/gems/1.9.1/gems/activesupport-3.0.5/lib/active_support/inflector/methods.rb:124:in `block in constantize'
    from /var/lib/gems/1.9.1/gems/activesupport-3.0.5/lib/active_support/inflector/methods.rb:123:in `each'
    from /var/lib/gems/1.9.1/gems/activesupport-3.0.5/lib/active_support/inflector/methods.rb:123:in `constantize'
    from /var/lib/gems/1.9.1/gems/activesupport-3.0.5/lib/active_support/core_ext/string/inflections.rb:43:in `constantize'
    from (irb):4
    from /usr/bin/irb:12:in `<main>'
>> foo.constantize = Class.new
NoMethodError: undefined method `constantize=' for "GeneralSystem":String
    from (irb):5
    from /usr/bin/irb:12:in `<main>'

Any help would be greatly appreciated.

2
  • you are tyring to call a method "general_systems".camelize.singularize=(Class.new) which is not there. what exactly are you trying to do? Commented Mar 14, 2011 at 17:42
  • 1
    Judging by one of your comments on someone's answer, you already solved the problem with their solution. Perhaps you could select an answer now? Commented Mar 15, 2011 at 23:06

7 Answers 7

38

If you're using Rails, it provides a method called #constantize that will work:

irb(main):017:0> Object.const_get 'House::Owns'
NameError: wrong constant name House::Owns

'House::Owns'.constantize
=> House::Owns
Sign up to request clarification or add additional context in comments.

2 Comments

I get: 1.9.3p392 :019 > 'House::Owns'.constantize NoMethodError: undefined method constantize' for "House::Owns":String from (irb):19 from /Users/ryan/.rvm/rubies/ruby-1.9.3-p392/bin/irb:16:in <main>'`
#constantize is a Rails method. api.rubyonrails.org/classes/ActiveSupport/…
34

Something like this?

>> Object.const_set("general_systems".classify, Class.new)
=> GeneralSystem
>> GeneralSystem.new
=> #<GeneralSystem:0x105b0f738>

1 Comment

this is an activesupport idiom
13
klazz = Class.new(ActiveRecord::Base) do
  def do_something_fun(param1)
    param1.have_fun!
  end
end

klazz_name = "general_systems".singularize.classify
Object.const_set(klazz_name, klazz)

Comments

8

Look at this example from "The Book Of Ruby", included in the Ruby 1.9 installer.

puts("What shall we call this class?> ")
className = gets.strip().capitalize()
Object.const_set(className,Class.new)
puts("I'll give it a method called > 'myname'" ) 
className = Object.const_get(className)
className::module_eval{
  define_method(:myname){ 
    puts("The name of my class is '#{self.class}'" ) 
 } }
 x = className.new x.myname

Comments

5

Given:

class Banana
end

You can fetch the class in plain Ruby with:

Object.const_get 'Banana'
=> Banana

or if you're using Rails:

'Banana'.constantize
=> Banana

Comments

4

If your string contains a namespace, you can use:

require 'rubygems'
require 'active_support/inflector'
parent=String # using String to get a self contained example
# require 'active_record'   # uncomment for ActiveRecord::Base as parent class
# parent=ActiveRecord::Base # uncomment for ActiveRecord::Base as parent class
namespace = 'A::B::general_systems'.split('::') 
class_name = namespace.pop 
namespace = namespace.inject(Object) do |mod, name|
  if mod.constants.collect{|sym| sym.to_s}.include? name.classify
    mod.const_get name.classify
  else
    mod.const_set name.classify, Module.new
  end
end

klass = if namespace.constants.include? class_name.classify
  namespace.const_get class_name.classify
else
  namespace.const_set class_name.classify, Class.new(parent)
end

object = klass.allocate # allocate new object of klass
object.send :initialize # initialize object
object.class
object.class.superclass

Comments

1

try

>> "general_systems".classify
=> "GeneralSystem"

2 Comments

Thank you all, I ended up with:<pre><code>Object.const_set(loader.classify, Class.new(ActiveRecord::Base)) db_loader = Object.const_get(loader.classify) db_loader.create(input_system) </code></pre> And that works very nicely.
@Telmo: For future reference, use backticks rather than <pre><code>.

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.