Low commit activity in last 3 years
ActiveRecord-Cti is a library implemented Class Table Inheritance on Ruby on Rails. Class Table Inheritance (CTI) is useful under the circumstances that an ActiveRecord object is in multiple positions or has multiple roles, and you want to describe it's structure on the database. For Example, one person may be a player and a coach in a soccer team.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

 Project Readme

ActiveRecord::Cti

ActiveRecord-Cti is a library implemented Class Table Inheritance on Ruby on Rails. Class Table Inheritance (CTI) is useful under the circumstances that an ActiveRecord object is in multiple positions or has multiple roles, and you want to describe it's structure on the database. For example, one person may be a player and a coach in a soccer team.

Why use activerecord-cti ?

In ActiveRecord, Single Table Inheritance(STI) is implemented as a method of how to express inheritance model on database. Class Table Inheritance (CTI) has more powerful and flexible expressiveness for inheritance model on database than it of STI.

For Example, Suppose you want to describe the following class structure on database.

Class Diagram

But STI has a disadvantage that it is not possible to represent one record as an object of two different models at the same time.

people talbe (STI)

id type name birth_year position_name license_name
1 Player Ryan Giggs 1973 midfielder
2 Coach Ryan Giggs 1973 UEFA Pro

As mentiond above, for expressing two Person's subclasses objects, which are Player and Coach, you have to insert two records into people table in STI. It is cursed that the contents of name and birth_year columns are duplicated and position_name and license_name columns are sparse.

CTI can solve these problems by using multiple related tables like shown below, literally for class table inheritance.

ER Diagram

Installation

To install activerecord-cti on Rails, put this line in your Gemfile:

gem 'activerecord-cti'

And then execute bundle install

$ bundle install

How to use

Preparation

First of all, generate the files of models you want to apply CTI to, and execute migration.

$ rails g model Person name:string birth_year:integer
$ rails g model Player person_id:integer position_name:string 
$ rails g model Coach person_id:integer licence_name:string
$ rake db:migrate

Next, add the following line into Person model, which is base class.

class Person < ApplicationRecord
  include ActiveRecord::Cti::BaseClass #added
end

By this mix-in, Person model is configured as base class in CTI, and automatically becomes abstract class as well.

And then, rewrite files of subclass models for inheriting base class.

class Player < Person
end
class Coach < Person
end

Coding

To save data of Ryan Giggs as a football player, describe following:

player = Player.new(
  name: 'Ryan Giggs',
  birth_year: 1973,
  position_name: 'midfielder'
)
player.save

So that his data is automatically split into two related tables.

MariaDB> SELECT * FROM people limit 1;
+----+----------------+------------+
| id | name           | birth_year |
+----+----------------+------------+
|  1 | Ryan Giggs     | 1973       |
+----+----------------+------------+

MariaDB> SELECT * FROM players limit 1;
+----+----------------+---------------+
| id | person_id      | position_name |
+----+----------------+---------------+
|  1 | 1              | midfielder    |
+----+----------------+---------------+

Then, Ryan Giggs started coaching at Manchester United in 2013 as well as being a player. To save the data of Giggs as a coach to DB, describe following:

player = Player.find_by(name: 'Ryan Giggs')
coach = player.to_coach(licence_name: 'UEFA Pro')
coach.save

So that his data is newly inserted into only coaches table.

MariaDB> SELECT * FROM coaches limit 1;
+----+----------------+--------------+
| id | person_id      | licence_name |
+----+----------------+--------------+
|  1 | 1              | UEFA Pro     |
+----+----------------+--------------+

To get Ryan Giggs's Data as a coach, describe following:

Coach.find_by_name('Ryan Giggs') #<Coach id: 1, name: "Ryan Giggs", licence_name: 'UEFA Pro'>

Like this, pserson_id, which coaches table has as foreign_key reffered to base class object, is concealed.

License

The gem is available as open source under the terms of the MIT License.