Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Rupicon 2014 Single table inheritance

Rupicon 2014 Single table inheritance

  • Be the first to comment

  • Be the first to like this

Rupicon 2014 Single table inheritance

  1. 1. Single Table Inheritance (STI) Raul Pristopan 1 / 22
  2. 2. Agenda 1. Introduction 2. What is STI? 3. When should we use STI? 4. How do we implement STI? 5. Reasons why you shouldn't use STI 6. Demo 2 / 22
  3. 3. Introduction 3 / 22
  4. 4. Introduction In the beginning everything always works. Things get complicated with time when you start adding new features. Some weeks ago I had to refactor some parts of a project and also add some new features to it. After some hours of reviewing the actual code I run into some problems: 1. Same code in multiple places 2. Same data stored in 2 or more tables create_table "users", :force => true do |t| ... t.string "image_file_name" t.string "image_content_type" t.integer "image_file_size" t.datetime "image_updated_at" ... 4 / 22
  5. 5. Introduction create_table "activities", :force => true do |t| ... t.string "image_file_name" t.string "image_content_type" t.integer "image_file_size" t.datetime "image_updated_at" ... create_table "image_attachments", :force => true do |t| t.string "image_file_name" t.string "image_content_type" t.integer "image_file_size" t.datetime "image_updated_at" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.integer "used_by_count", :default => 1 t.text "original_url" end 5 / 22
  6. 6. What is STI? STI is basically the idea of using a single table to reflect multiple models that inherit from a base model, which itself inherits from ActiveRecord::Base. In the database schema, sub-models are indicated by a single "type" column. In other words we have: a base class descendant classes 6 / 22
  7. 7. When should we use STI? Should be considered when dealing with model classes that share much of the same functionality and data fields (granular control over extending or adding to each class individually) When you have duplicate code over and over for multiple tables (and not being DRY) STI permits you to use keep your data in a single table while writing specialized functionality. 7 / 22
  8. 8. When should we use STI? Suppose you have three classes in your application which model similar things. To make this easier to think about I’ll be referring to some hypothetical classes by name: Business and Employee. Let’s consider three choices for modeling this situation: 1. Polymorphic Associations (separate classes, multiple tables) 2. Single Table Inheritance (separate classes, one table) 3. Single Class with conditionals (one class, one table) 8 / 22
  9. 9. When should we use STI? Polymorphic Associations (separate classes, multiple tables) With Polymorphic Associations we use modules to share code among classes. We have the following active record models for a “Business” and an “Employee”. class Business < ActiveRecord::Base # Methods, variables and constants end class Employee < ActiveRecord::Base # Methods, variables and constants end 9 / 22
  10. 10. When should we use STI? Polymorphic Associations (separate classes, multiple tables) For the contact information, we have the following active record models: class PhoneNumber < ActiveRecord::Base # Methods, variables and constants end class Website < ActiveRecord::Base # Methods, variables and constants end 10 / 22
  11. 11. When should we use STI? Polymorphic Associations (separate classes, multiple tables) Now, for the associations, Business and Employee models can have many phone numbers and websites. And conversely, Phone Number/Website can belong to either a Business model or an Employee model. class Business < ActiveRecord::Base has_many :phone_numbers, :as => phonable has_many :websites, :as => webable end class Employee < ActiveRecord::Base has_many :phone_numbers, :as => phonable has_many :websites, :as => webable end 11 / 22
  12. 12. When should we use STI? Polymorphic Associations (separate classes, multiple tables) class PhoneNumber < ActiveRecord::Base belongs_to :phonable, :polymorphic => true end class Website < ActiveRecord::Base belongs_to :webable, :polymorphic => true end Having the above setup, you can get a collection of phone numbers for a business instance via the call “@business.phone_numbers. Similarly, you can get a collection of phone numbers for an employee instance via “@employee.phone_numbers”. 12 / 22
  13. 13. When should we use STI? Single Class with conditionals (one class, one table) A Single Class is not exactly a design pattern, or anything particularly interesting. I’m thinking of a model with a type-like attribute (maybe called kind) and some if statements in methods where you need different behavior for different kinds of objects. 13 / 22
  14. 14. When should we use STI? Questions to ask yourself When deciding how to design your data models, here are some questions to ask yourself: 1. Are the objects, conceptually, children of a single parent? 2. Do you need to do database queries on all objects together? 3. Do the objects have similar data but different behavior? 14 / 22
  15. 15. How do we implement STI? Create the base class Model: Employee Attributes: Name - String Age - Integer Department - String $ rails generate model Employee name:string age:integer department:string # /app/models/employee.rb class Employee < ActiveRecord::Base # Methods, variables and constants end 15 / 22
  16. 16. How do we implement STI? Add a :type attribute as a string to the base class $ rails generate migration add_type_to_employee type:string 16 / 22
  17. 17. How do we implement STI? Create any necessary descendant classes # /app/models/developer.rb class Developer < Employee # Methods, variables and constants end # /app/models/tester.rb class Tester < Employee # Methods, variables and constants end 17 / 22
  18. 18. Reasons why you shouldn't use STI It creates a cluttered data model Why don’t we just have one table called objects and store everything as STI? STI tables have a tendency to grow and expand as an application develops, and become intimidating and unweildy as it isn’t clear which columns belong to which models. 18 / 22
  19. 19. Reasons why you shouldn't use STI It forces you to use nullable columns If sub-classes that you intend to use for STI have many different data fields, then including them all in the same table would result in a lot of null values and make it difficult to scale over time. In this case, you may end up with so much code in your model sub-classes that the shared functionality between sub-classes is minimal and warrants separate tables. A comic book must have an illustrator, but regular books don’t have an illustrator. Subclassing Book with Comic using STI forces you to allow illustrator to be null at the database level (for books that aren’t comics), and pushes your data integrity up into the application layer, which is not ideal. 19 / 22
  20. 20. Reasons why you shouldn't use STI It prevents you from efficiently indexing your data Every index has to reference the type column, and you end up with indexes that are only relevant for a certain type. 20 / 22
  21. 21. Reasons why you shouldn't use STI Two objects types have similar attributes Both airplanes and bicycles have wheels, but it probalby doesn’t make sense to group them into the same table, given that intuitively, they’re different objects that will have vastly different functionality and data fields in an application. Demo 21 / 22
  22. 22. Thank you! 22 / 22

×