Skip to content

Instantly share code, notes, and snippets.

@pote
Created February 5, 2014 20:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pote/8832185 to your computer and use it in GitHub Desktop.
Save pote/8832185 to your computer and use it in GitHub Desktop.
Single Table Inheritance
# Use in subclasses like:
# delegate_details :win_ratio, :tanning_time, to: :wrestling_details
def self.delegate_details(*attributes)
options = attributes.extract_options!
association_name = options.fetch(:to) {
raise ArgumentError.new "You must specify the name of the details association"
}
define_method association_name do
super() || send("build_#{association_name}")
end
attributes.each do |attribute_name|
# Getter, setter, and boolean getter (in case it's a boolean attribute)
def_delegators association_name,
:"#{attribute_name}", :"#{attribute_name}=", :"#{attribute_name}?"
end
end
ActiveRecord::Schema.define(:version => 20130203210553) do
create_table "people", :force => true do |t|
t.string :name
t.string :shoe_size
t.string :place_of_birth
t.string :blood_type
end
create_table :scientists, :force => true do |t|
t.string :name
t.string :shoe_size
t.string :place_of_birth
t.string :blood_type
t.string :university
end
create_table :chefs, :force => true do |t|
t.string :name
t.string :shoe_size
t.string :place_of_birth
t.string :blood_type
t.string :hat_size
end
end
ActiveRecord::Schema.define(:version => 20130203210553) do
create_table "people", :force => true do |t|
t.string :name
t.string :shoe_size
t.string :place_of_birth
t.string :blood_type
t.string :type # => Needed for the ORM to know which kind of object its dealing with.
t.string :university # => The Scientist field(s)
t.string :hat_size # => The Chef field(s)
end
end
require 'sequel'
DB = Sequel.connect 'sqlite://database.db'
class Person < Sequel::Model
# has name, shoe_size, place_of_birth, blood_type
end
Person.plugin :class_table_inheritance, key: :type
class Chef < Person
# has hat_size
end
class Scientist < Person
# has university
end
class Physicist < Scientist
# has lightsaber_color
end
Sequel.migration do
change do
create_table :people do
primary_key :id
String :name
String :shoe_size
String :place_of_birth
String :blood_type
String :type
end
create_table :chefs do
foreign_key :id, :people
String :hat_size
end
create_table :scientists do
foreign_key :id, :people
String :university
end
create_table :physicists do
foreign_key :id, :scientists
String :lightsaber_color
end
end
end
Scientist.create(name: 'Alan Turing', shoe_size: '41', university: 'Cambridge')
# => #<Scientist @values={:id=>1, :name=>"Alan Turing", :shoe_size=>"41", :place_of_birth=>nil, :blood_type=>nil, :type=>"Scientist", :university=>"Cambridge"}>
Chef.create(name: 'Guy Fieri', shoe_size: '45', hat_size: '12')
# => #<Chef @values={:id=>2, :name=>"Guy Fieri", :shoe_size=>"45", :place_of_birth=>nil, :blood_type=>nil, :type=>"Chef", :hat_size=>"12"}>
Chef.create(name: 'Guy Fieri', shoe_size: '45', hat_size: '12')
# => #<Chef @values={:id=>3, :name=>"Guy Fieri", :shoe_size=>"45", :place_of_birth=>nil, :blood_type=>nil, :type=>"Chef", :hat_size=>"12"}>
Person.all
# => [#<Scientist @values={:id=>1, :name=>"Alan Turing", :shoe_size=>"41", :place_of_birth=>nil, :blood_type=>nil, :type=>"Scientist"}>, #<Chef @values={:id=>2, :name=>"Guy Fieri", :shoe_size=>"45", :place_of_birth=>nil, :blood_type=>nil, :type=>"Chef"}>, #<Chef @values={:id=>3, :name=>"Guy Fieri", :shoe_size=>"45", :place_of_birth=>nil, :blood_type=>nil, :type=>"Chef"}>]
Scientist.first(university: 'Cambridge')
# => #<Scientist @values={:id=>1, :name=>"Alan Turing", :shoe_size=>"41", :place_of_birth=>nil, :blood_type=>nil, :type=>"Scientist", :university=>"Cambridge"}>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment