LoginSignup
14
4

More than 5 years have passed since last update.

Ruby on Railsでクラステーブル継承・具象テーブル継承を実現する

Last updated at Posted at 2018-11-02

Ruby on Railsでは単一テーブル継承しかサポートしていないが、クラステーブル継承・具象テーブル継承を実現しようと思ったときにアプリケーション側の実装はどんな感じが良いのか考えてみる。

継承とデータベース設計

まず前提。
アプリケーションの実装でクラス間に継承関係があった場合に、それをデータベース側で表現する方法として、PofEAAに以下3つが示されていて、RoRでは単一テーブル継承のみサポートされている。

  • 単一テーブル継承

  • クラステーブル継承

  • 具象テーブル継承

RoRでの実装

テーブル関係をコードに落とそうと思ったとき、共通テーブルを親クラスとして定義して継承する方法と、共通テーブルの特徴をモジュール化してmixinする2つの方法が考えられると思う。両方とも共通の特徴をクラスに取り込むという意味では同じなのだが言語的には振る舞いが異なるのでそのあたりは下記参照。
https://qiita.com/pink_bangbi/items/2c2f17516cd3a7b4eeac

mixin

共通となる特徴をモジュール化して外部に切り出す方法。モジュールとして切り出して各モデルがモジュールをincludeすることで、コード的には関連するモデルが全て直接ActiveRecordを継承することになる。コーディングするときはuser.subscriptions的に利用できる。

結論から言うと後述の継承を用いた方法はRails的にデメリットが多くて、mixinのほうがおすすめである。

module Chargeable
  belongs_to :customer
  has_many :subscriptions
...
end
class User < ActiveRecord::Base
  include Chargeable
end
class Company < ActiveRecord::Base
  include Chargeable
end
継承

RailsのSTIライクに共通属性を継承する形で利用できるようにする方法。他の言語でのオブジェクト指向プログラミングに慣れている場合は見た目的にもわかりやすくてしっくりくるかなと思う。
ただ、Rails的に結構トラップがあると思っているので注意も必要だったりする。
たとえば親クラスが外部に持つアソシエーションを子クラスで呼び出した場合に、子クラスの外部キーが用いられるたりする。(user.subscriptionsした場合、customer.idを外部キーとしてsubscriptionを取得してほしいところuser.idに紐付いたsubscriptionsが取得されてしまう)
この場合以下のように、親クラスにdelegateして user.subscriptions した場合も customer.subscriptions が呼ばれるようにするなど対応が必要だと思う。

ほかにもたとえば、UserCompanyにポリモーフィック関連するモデルが存在した場合、hogerable_typeカラムに親クラスが設定されてしまうなど。

class Customer < ApplicationRecord
  has_many :subscriptions
  has_one :user
  has_one :company

end
class User < Customer
  belongs_to :customer
  has_many :hoges, as: :hogerable
  delegate :subscriptions, to: :customer
end
class Company < Customer
  belongs_to :customer
  has_many :hoges, as: :hogerable
  delegate :subscriptions, to: :customer
end
class Hoge < ActiveRecord::Base
  belongs_to :hogerable, polymorphic: true
end

結論

14
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
4