📖

Rails のポリモーフィック関連付けについて理解する

に公開

ラブグラフでインターンをしているりょうさんです!

Rails には、ポリモーフィック関連付けという機能があります。これは、ある1つのモデルが他の複数のモデルに属していることを、1つの関連付けだけで表現できるという機能です。

今回は、このポリモーフィック関連付けについて、あまり理解ができていなかったので、この記事を通して整理していこうと思います。

具体例

以下の状況を仮定しましょう。

学校における「コメント」機能を実装したいとします。

  • 生徒の日記にコメントをつけたい
  • 先生のお知らせにコメントをつけたい
  • 部活動のブログ記事にコメントをつけたい

素直にコメント機能を作成しようとすると、

class Comment < ApplicationRecord
  belongs_to :student_diary, optional: true
  belongs_to :teacher_notice, optional: true
  belongs_to :club_blog, optional: true
end

このように、たくさん belongs_to が増えて、どれにコメントしてるかが曖昧になったり、テーブル設計が複雑になります。
ここで登場するのが、Rails のポリモーフィック関連付けです。

ポリモーフィック関連付けの設計

まず、コメント(Comment)モデルは、どのモデルにも紐づけられるようにテーブルを定義します。

# db/migrate/xxxx_create_comments.rb
class CreateComments < ActiveRecord::Migration
  def change
    create_table :comments do |t|
      t.text :content
      t.references :commentable, polymorphic: true, null: false
      t.timestamps
    end
  end
end

次に、コメントを受け取る側のモデルで関連付けを宣言します。

class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end

class StudentDiary < ApplicationRecord
  has_many :comments, as: :commentable
end

class TeacherNotice < ApplicationRecord
  has_many :comments, as: :commentable
end

class ClubBlog < ApplicationRecord
  has_many :comments, as: :commentable
end

ここにおける commentable というのは、コメントされる「対象」や「親」となる任意のモデル を指す、抽象的な役割名 です。
この例では、StudentDiaryTeacherNoticeClubBlog のそれぞれが commentable なオブジェクトとして振る舞い、共通の Comment モデルと関連付けを持つことができます。

すると、Railsは commentable_typecommentable_id というカラムを見て、

  • commentable_type = "StudentDiary", commentable_id = 1 → 生徒の日記の1番に対するコメント

  • commentable_type = "TeacherNotice" → 先生のお知らせ

  • commentable_type = "ClubBlog" → 部活ブログ

という風に、どのモデルに属しているかを判断してくれるのです!

この2つのカラムは公式でも、

ポリモーフィック関連付けを手動でセットアップする場合は、以下のようにモデルで外部キーカラム(imageable_id)とtypeカラム(imageable_type)の両方を宣言する必要があります。

とあるため、この2つのカラムは存在しています。

mermaid で図解

実際にどのような関連なのか、図で見てみましょう。

クラス図

まとめ

ポリモーフィック関連付けを使うことで、1つのコメントモデルで複数のモデルに対してコメント機能を共通実装できます。テーブル設計・モデル宣言のシンプルさが大きなメリットです。

参考記事

https://railsguides.jp/association_basics.html#ポリモーフィック関連付け

ラブグラフのエンジニアブログ

Discussion