⚒️

Railsのポリモーフィック関連付けに関してやで!!

2025/03/06に公開

Rails案件でポリモーフィックにぶつかり、自身の理解も含めてまとめることにしました。
※関西出身なので、タイトルを関西弁にしました笑

Ruby on Rails のポリモーフィック関連付けとは?

ポリモーフィック関連付け(Polymorphic Association) とは、 1つのモデルが複数の異なるモデルと関連を持てる仕組み

通常の belongs_to 関連は特定の1つのモデルを参照するが、ポリモーフィック関連付けを使うと 複数のモデルを柔軟に参照 できる


具体例:コメント機能

例えば、Post(投稿)と Photo(写真)のどちらにも Comment(コメント)を付けられる設計とする

1. 通常の関連付け

通常の belongs_to を使うと、Comment モデルには post_idphoto_id という2つのカラムが必要になる


class Comment < ApplicationRecord
  belongs_to :post, optional: true
  belongs_to :photo, optional: true
end

しかし、この方法では Comment がどのモデルに属しているかを判別しづらく、拡張性が低い


2. ポリモーフィック関連付け

ポリモーフィックを使うと、Comment モデルが どのモデルに属しているかを1つのカラムで表現 可能

モデル設計


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

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

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

マイグレーション


class CreateComments < ActiveRecord::Migration[7.0]
  def change
    create_table :comments do |t|
      t.text :content
      t.references :commentable, polymorphic: true, null: false

      t.timestamps
    end
  end
end

commentable_type には PostPhoto などのモデル名が入り、

commentable_id には対応するレコードのIDが入る


使い方

コメントを作成


post = Post.create(title: "新しい記事")
photo = Photo.create(url: "photo.jpg")

comment1 = post.comments.create(content: "これは投稿へのコメント")
comment2 = photo.comments.create(content: "これは写真へのコメント")

データの中身


Comment.all
# =>
# | id | content                  | commentable_type |commentable_id|
# |----|--------------------------|---------------|------------------|
# | 1  | これは投稿へのコメント    | Post           | 1           |
# | 2  | これは写真へのコメント    | Photo          | 1                |

commentable_typeには該当するモデル名(≒ テーブル名)が入り、commentable_idcommentable_type に該当するモデルに存在するレコードIDを意味する(厳密には違う感じがするが、理解としては遠からずという感じです、、、)と解釈しました、、
個人的には中間テーブルと思想は似ていると感じました。

関連データを取得


post.comments   # => Post に付いたコメント
photo.comments  # => Photo に付いたコメント

ポリモーフィック関連から元のモデルを取得


comment = Comment.first
comment.commentable  # => postオブジェクトが返る


ポリモーフィックのメリット

  1. 複数のモデルで共通の関連を使える
    • CommentPost だけでなく PhotoVideo などにも適用できる
  2. テーブルの構造がシンプル
    • post_idphoto_id などのカラムを個別に作らずに済む
  3. 拡張しやすい
    • 新しく EventArticle などのモデルを追加しても Comment の構造を変更する必要がない

注意点

  1. 検索時のパフォーマンス
    • commentable_type文字列 なので、検索時に インデックスが効きにくい
    • acts_as_taggable_on のような STI (Single Table Inheritance) を使うのも選択肢
  2. 関連を扱う際の制約
    • commentable のクラスが特定できないため、dependent: :destroy の挙動に注意

まとめ

ポリモーフィック関連付けは 1つのモデルが異なる複数のモデルに関連を持つとき に便利

柔軟な設計ができる一方で、パフォーマンス面や設計の複雑さも考慮する必要あり。

参考資料

Rails のポリモーフィック関連付けの解説と方法

ポリモーフィック関連付

Discussion