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 .class
Computer.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