Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PostgreSQL inheritance in ActiveRecord?

So we all know that rails' STI (single table inheritance) is icky because it leads to a cluttered data model and suboptimal database.

However PostgreSQL seems to handle inheritance quite beautifully!

Is there a way to get rails' nice clean STI API while utilizing Postgres inheritance instead of painfully wide tables and "type" columns?

like image 797
Daniel Upton Avatar asked Apr 08 '12 23:04

Daniel Upton


People also ask

How does inheritance work in Rails?

Inheritance is when a class receives or inherits the attributes and behavior of another class. The class that is inheriting the behavior is called the subclass (or derived class) and the class it inherits from is called the superclass (or base class). Imagine several classes - Cat, Dog, Rabbit, and so on.

What is inheritance in PostgreSQL?

Inheritance in PostgreSQL allows you to create a child table based on another table, and the child table will include all of the columns in the parent table. Let's take a database that's used to store blueprints for different types of homes.

What is STI rails?

Single Table Inheritance (STI) models are defined as separate classes inheriting from one base class, but they aren't associated with separate tables — they share one database table. The table contains a type column that defines which subclass an object belongs to.

What is inheritance in Ruby?

Inheritance is when a class inherits behavior from another class. The class that is inheriting behavior is called the subclass and the class it inherits from is called the superclass.


2 Answers

However PostgreSQL seems to handle inheritance quite beautifully!

Really? Did you take a close look at the small print in the manual? For example:

  • Unique constraints (and hence also primary keys) are not possible over inheritance levels.
  • References to inherited tables and the base table do not mix. I.e. (taken roughly from the manual): capitals extends cities. Your address table wants to reference cities. It can. But the no address with a capital can be used.

These two things are very important in anything beyond a small "Hello World" project. So I cannot imagine, that anything productive can be implemented using PostgreSQL inheritance.

like image 90
A.H. Avatar answered Oct 13 '22 01:10

A.H.


In short - no there no nice clean STI API for what you are trying to accomplish as of right now.

I actually looked into that a about a year ago and came to a conclusion that it is not a good idea for several reasons:

  1. If you want to utilize PostgreSQL specific features - you are basically marrying yourself to that DB. Don't get me wrong PostgreSQL is a great DB and I've used it on a number of occasions, but you are going to be stuck with that DB and app design.
  2. Most likely if you start using DB specific features you'll either end up implementing them manually ( running some kind of commands on the DB or using GUI) or writing some kind of script that you will have to invoke whenever you are running db:migrate ( you will have to do it if you want to do proper testing). After awhile it becomes cumbersome and annoying.
  3. If you find that you are more and more annoyed with, to quote you "painfully wide tables and "type" columns" then:
    • Your table design needs to be rethought and redone
    • Your models may not be a good candidates for STI
    • You just have to live with it.

Most IT problems really come down to this: Effort vs Benefit.

In your case you should ask yourself this question:

  • How much time do you want to spend on implementing a better STI structure if it will only speed up your raw SQL query by a few seconds? Maybe it's better to write a more explicative SQL query? Most applications don't grow to the size where it really becomes an issue. But it maybe different in your case.

P.S.:

Also a quick tip on structuring STI in your app: If you find that you have a lot of models that use STI like a ProductCategory, CommentCategory, PhoneCategory, ClientCategory that all inherit from Cateogory - I tend to organize them in folders inside model directory. Then in application.rb just add a line: config.autoload_paths += Dir[Rails.root.join('app', 'models', '{**/**}')]

like image 41
konung Avatar answered Oct 12 '22 23:10

konung