21
votes

What i'm looking to do is have a base class for some of my models that has some default activerecord behavior:

class Option < ActiveRecord::Base
  has_many :products

  def some_method
    #stuff
  end

  #etc..etc..
end

class ColorOption < Option
  #stuff...
end


class FabricOption < Option
  #stuff...
end

However, I want ColorOption and FabricOption to each be in their own tables. I do NOT want to use STI or have a table for the base class "Option". The only way I've gotten this to work is with some non-inheritance metaprogramming magic. But I wondered if there was a way to tell AR that the base class does not need a table. Its just there for extra behavior, and to put the other subclasses in their own table as usual.

Thanks, Craig

3

3 Answers

58
votes

What you want is an abstract class:

class Option < ActiveRecord::Base
  self.abstract_class = true
end

class ColorOption < Option
  ...
end

class FabricOption < Option
  ...
end
17
votes

Looks like a case for a module that you include.

module Option
  def self.included(base)
    base.has_many :products
  end

  # other instance methods
end

class ColorOption < ActiveRecord::Base
  include Option
  set_table_name '???' # unless ColorOption / FabricOption have same table -> move to Option module

  #stuff...

end


class FabricOption < Option
  include Option
  set_table_name '???' # unless ColorOption / FabricOption have same table -> move to Option module

  #stuff...
end

More info: http://mediumexposure.com/multiple-table-inheritance-active-record/

6
votes

I had similar problem, but I wanted also to change the way AR was setting table_name for my models, that for example MyProject model would have table name "MY_PROJECT".

I've achieved it by creating abstract AR class, as @FFrançois said, and with inherited method, where I'm changing table name, like this:

class MyModel < ActiveRecord::Base
  self.abstract_class = true

  def self.inherited(subclass)
    subclass.table_name = subclass.name.underscore.upcase
  end
end

class MyProject < MyModel
end

Now MyProject.table_name gives MY_PROJECT :)