💡

RailsのActiveRecordにおける、ポリモーフィック関連付けとは

2024/01/08に公開

RailsのActiveRecordには多くの関連付け(アソシエーション)が存在していますが、今回はその中からポリモーフィック関連付けについて解説していきたいと思います。

ポリモーフィック関連付けとは

ポリモーフィック関連付けとは、1つのモデルが複数のモデルに属している状態を表現するための関連付けです。
異なる種類のモデルに対し一つの記述で関連付けが可能になります。
例えばCommentモデルが存在し、このモデルはArticle(記事),Photo(写真),Video(動画)に対して存在できるとします。
この場合、以下の様にCommentモデルを複数モデルに対してbelongs_toしたいところです。

Comment.rb
belongs_to :article
belongs_to :photo
belongs_to :video

ですが、この関連付けは望ましくありません。
こう設定した場合、commentは複数のモデルに対して一つ存在することになるからです。
記事、写真、ビデオに対して共通のコメントが存在するというケースは非常に稀であるため、この関連付けは問題です。
これを解消するにはそれぞれのモデルに対して別のモデル(例えばArticles_commentなど)を用意しなければなりませんが、同一の構造と運用を行うモデルが複数存在することもやはり問題です。
こういう場合にポリモーフィック関連付けの出番です。

ポリモーフィック関連付けの記法

ポリモーフィック関連付けを行う場合は、各モデルに以下の様に記述します。

Comment.rb
belongs_to :commentable, polymorphic: true
Article.rb
has_many :comments, as: :commentable
Photo.rb
has_many :comments, as: :commentable
Video.rb
has_many :comments, as: :commentable

Commentモデルにbelongs_to :commentable, polymorphic: trueを設定することでcommentモデルをポリモーフィック関連付けで取り扱う準備が整います。
commentableはポリモーフィック関連付けのインターフェースの様に取り扱うことができ、各モデルでas: :commentableを通してcommentモデルにポリモーフィック関連付けできます。

ポリモーフィック関連付けと通常の関連付けの違い

ポリモーフィック関連付けと通常の関連付けの違いを挙げていこうと思います。

  1. 柔軟性の違い
    通常の関連付けでは、一つの関連付けで一つの種類のモデルに対してのみ関連づけることができます。
    対してポリモーフィック関連付けでは、一つの関連付けで複数の種類のモデルに対して対して関連付けることができます。
    これはポリモーフィック関連付けが関連付け先を抽象的に宣言することで関連付け対象を動的に変更することができるためです。
    ただ注意点として一つのポリモーフィック関連付けで関連付けることができるのは一つのモデルのみです。
    モデルの種類は問いませんが、モデルの個数は一つということです。
    複数のモデルに対して関連付けするためには通常の関連付けと同じようにポリモーフィック関連付けを複数宣言する必要があります。
  2. 再利用性の違い
    通常の関連付けでは、決まった一つのモデルにのみ関連付けられ他のモデルと関連付けるためには記述の追加及び変更が必要となります。
    対してポリモーフィック関連付けでは、新たにモデルを追加した場合にも変更なしで関連付けることができます。
    これも、ポリモーフィック関連付けが抽象的なインターフェースを持つことのメリットの一つです。
  3. データベース定義の違い
    通常の関連付けではデータベース上に関連付け先のIDを外部キーとして持つことが必要となります。
    対してポリモーフィック関連付けではデータベース上に関連付け先のIDの他にも関連付け先のモデルのクラス名を保持する必要があります。
    関連付け先のクラスが分からなければ、IDの値が何を指しているのかが分からないためです。

最後に

ポリモーフィック関連付けは通常の関連付けに比べ柔軟性に富みますが、過剰に使用するとコードが複雑化してメンテナンスが困難になりがちです。
シンプルな設計の場合はあえてポリモーフィック関連付けを使うべきなのかどうかは慎重に検討する必要があるでしょう。
通常の関連付けの方がコードはシンプルなため、使い分けが大事と言えそうです。

Discussion