Skip to content

ActiveRecord support for PostgreSQL's native inherited tables (multi-table inheritance)

License

Notifications You must be signed in to change notification settings

TwilightCoders/active_record-mti

Repository files navigation

Version      Build Status Code Climate Test Coverage Dependencies

ActiveRecord::MTI

ActiveRecord support for PostgreSQL's native inherited tables (multi-table inheritance)

Supports

  • Ruby: 2.3, 2.4, 2.5
  • ActiveRecord: 4.2, 5.0, 5.1

Confirmed production use in 4.2

Installation

Add this line to your application's Gemfile:

gem 'active_record-mti'

And then execute:

$ bundle

Or install it yourself as:

$ gem install active_record-mti

Usage

class Account < ::ActiveRecord::Base
  # table_name is 'accounts'
  # ...
end

class User < Account
  # table_name is 'account/users'
  # ...
end

class Developer < Account
  # table_name is 'account/developers'
  # ...
end

class Admin < User
  self.table_name = 'admins'
  # ...
end

class Hacker < Developer
  # table_name is 'account/developer/hackers'
  # ...
end

In most cases, you shouldn't have to do anything beyond installing the gem. ActiveRecord::MTI will do it's best to determine the nature of inheritance in your models. If your models map to their own tables, ActiveRecord::MTI will step in and make sure inheritance is treated appropriately. Otherwise it will gracefully acquiesce to ActiveRecord's built-in STI. (see Table Names section below).

Queries

ActiveRecord queries work as usual with the following differences:

  • The default query of "*" is changed to include the OID of each row for subclass discrimination. The default select will be SELECT "accounts"."tableoid" AS tableoid, "accounts".* (for example)

Table Names

Conventionally—to indicate the nature of inheritance—ActiveRecord::MTI expects the table_name of a child model to follow the singular_parent_table_name/plural_child_table_name pattern. As always, if you need to deviate from this, you can explicitly set the table_name as shown below, or configure ActiveRecord::MTI using the configure block.

Note, ActiveRecord::MTI will fall back on the unnested table_name if it's unable to find the nested form, and short of that, it will use the superclass's table_name.

Configuration

ActiveRecord::MTI can be configured using a configure block.

# config/initializers/active_record_mti.rb

ActiveRecord::MTI.configure do |config|
  config.table_name_nesting = true
  config.nesting_seperator = '/'
  config.singular_parent = true
end

Migrations

In your migrations define a table to inherit from another table:

class CreateAccounts < ActiveRecord::Migration
  def change
    create_table :accounts do |t|
      t.jsonb      :settings
      t.timestamps null: false
    end

    create_table :users, inherits: :accounts do |t|
      t.string     :firstname
      t.string     :lastname
    end

    create_table :developers, inherits: :users do |t|
      t.string     :url
      t.string     :api_key
    end
  end
end

Schema

A schema will be created that reflects the inheritance chain so that rake:db:schema:load will work

ActiveRecord::Schema.define(version: 20160910024954) do

  create_table "accounts", force: :cascade do |t|
    t.jsonb    "settings"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  create_table "users", inherits: "accounts" do |t|
    t.string "firstname"
    t.string "lastname"
  end

  create_table "developers", inherits: "users" do |t|
    t.string "url"
    t.string "api_key"
  end

end

Contributing

  1. Fork it ( https://github.com/TwilightCoders/active_record-mti/fork )
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

About

ActiveRecord support for PostgreSQL's native inherited tables (multi-table inheritance)

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages