What is Single Table Inheritance?
In a nutshell, STI allows you to create sub-classes of a particular database table. Using a single table, you can cast rows to specific objects that extend the base model.
How to create STI relationships in Rails
Lets say we have a model Computer
class Computer < ActiveRecord:Base
# in app/models
# Fields:
# String name
# String owner
# String manafacturer
# String color
def default_browser
"unknown!"
end
end
Now, we want to differentiate between Macs and PCs. It doesn’t really make sense to make a different table for each, since they both have pretty much the same columns. Instead we can create a new column,
type, which tells Rails to use STI on Computer. Lets look at what the models might look like.class Computer < ActiveRecord:Base
# in app/models
# Fields:
# String name
# String owner
# String manafacturer
# String color
# String type
def default_browser
"unknown!"
end
end
class Mac < Computer
# in app/models
# this is for Computers with type="Mac"
before_save :set_color
# Lets say all macs are silver, no point setting these ourselves
def set_color
self.color = "silver"
self.manafacturer = "apple"
end
# Lets overwrite the default_browser method
def default_browser
"safari"
end
end
class PC < Computer
# in app/models
# Lets overwrite the default_browser method
def default_browser
"ie =("
end
end
Anytime Rails opens up the
computer object, it looks for the subclass corresponding to type. For instance,type="CoolComputer" corresponds to model CoolComputer < Computer.
How to use STI Models
To create a new mac, you can do:
m = Mac.new m.name = "kunal's mac" m.owner = "kunal" m.save m # => #<Mac id: 1, name: "kunal's mac", owner: "kunal", manafacturer: "apple", color: "silver", type: "Mac", ...>
Whats even cooler is ActiveRecord queries. Lets say we want all the computers
Computer.all # => [#<Mac id: 1, name: "kunal's mac", owner: "kunal", manafacturer: "apple", color: "silver", type: "Mac", ...>, #<Mac id: 2, name: "anuj's mac", owner: "anuj", manafacturer: "apple", color: "silver", type: "Mac", ...>, #<PC id: 3, name: "bob's pc", owner: "bob", manafacturer: "toshiba", color: "blue", type: "PC", ...>]
Yup, it automatically gives you the correct objects! You can find out the type of a particular object by calling
.type, is_a? or .classComputer.first.type == Mac # true Computer.first.is_a? Mac # true Computer.first.class == Mac # true
If we only want Macs, we can do
Mac.all
Useful post. Thanks Nikhi
ReplyDelete