5

I want to be able to dynamically create classes, for scripting outside my Rails app, that inherit from ActiveRecord.

I'm stuck on something like this:

require 'active_record'

def create_arec(table_name)
  Class.new ActiveRecord::Base do
    self.table_name = table_name
    yield
  end
end

Band = create_arec 'bands' do
  scope :only_rock, -> {where genre: 'rock'}
end

rock_bands = Band.only_rock #undefined method `only_rock'

How do I make it work, or can someone show me better way to do it?

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Ondřej Želazko
  • 648
  • 7
  • 16
  • 3
    dude! for real? why? and if! just use `class_eval`. you are going to be killed by someone if they have to maintain this! i tell you, not kidding! – phoet Oct 11 '13 at 13:18
  • maybe I was more curious if you can yield that block within block for Class.new then intended to actually use that.. Anyway, yeah thanks, class_eval will be much better. I love ruby. – Ondřej Želazko Oct 11 '13 at 13:24
  • write an answer to your question and mark it resolved, so that people don't have to look into this anymore. – phoet Oct 11 '13 at 13:42
  • the evil `yield` here is to execute the block in `main` context, causing the method available everywhere. To make thing worse, the later execute will overwrite previous methods. Using `class_eval` will switch the context from `main` to the new class `self`. – zhongxiao37 Jun 30 '20 at 01:53

1 Answers1

5

Nailed it:

def create_arec(table_name, &block)
  klass = Class.new(ActiveRecord::Base){self.table_name = table_name}
  klass.class_eval &block
  klass
end

thanks @phoet

Ondřej Želazko
  • 648
  • 7
  • 16