Created
September 14, 2013 09:16
-
-
Save devmug/6560431 to your computer and use it in GitHub Desktop.
Single table inheritance (sti's) rails 3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Single Table Inheritance in Rails 3 | |
What is Single Table Inheritance? | |
STI allows you to create subclasses 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 | |
Custom Inheritance Column | |
If you want to use another column instead of type to use for STI, you can simply add this to the top of your model: | |
set_inheritance_column 'whatever_you want' | |
Note: If you have a database column named type, you can turn off Single Table Inheritance by changing the inheritance column to something other than type. | |
Organizing This in Rails | |
After using STI, I ended up with a bloated models folder because all of the many custom sub models | |
I created were in the models folder. To solve this, I created a folder in models to store all of my computer specific models | |
* app | |
* models | |
* computer.rb | |
* computers | |
* pc.rb | |
* mac.rb | |
Rails doesn’t automatically open subfolders in the models folder, so I added in config/application.rb: | |
# Load Subfolder Models | |
config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**}')] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment