⚒️
Railsのポリモーフィック関連付けに関してやで!!
Rails案件でポリモーフィックにぶつかり、自身の理解も含めてまとめることにしました。
※関西出身なので、タイトルを関西弁にしました笑
Ruby on Rails のポリモーフィック関連付けとは?
ポリモーフィック関連付け(Polymorphic Association) とは、 1つのモデルが複数の異なるモデルと関連を持てる仕組み
通常の belongs_to
関連は特定の1つのモデルを参照するが、ポリモーフィック関連付けを使うと 複数のモデルを柔軟に参照 できる
具体例:コメント機能
例えば、Post
(投稿)と Photo
(写真)のどちらにも Comment
(コメント)を付けられる設計とする
1. 通常の関連付け
通常の belongs_to
を使うと、Comment
モデルには post_id
と photo_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
には Post
や Photo
などのモデル名が入り、
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_id
はcommentable_type
に該当するモデルに存在するレコードIDを意味する(厳密には違う感じがするが、理解としては遠からずという感じです、、、)と解釈しました、、
個人的には中間テーブルと思想は似ていると感じました。
関連データを取得
post.comments # => Post に付いたコメント
photo.comments # => Photo に付いたコメント
ポリモーフィック関連から元のモデルを取得
comment = Comment.first
comment.commentable # => postオブジェクトが返る
ポリモーフィックのメリット
-
複数のモデルで共通の関連を使える
-
Comment
をPost
だけでなくPhoto
やVideo
などにも適用できる
-
-
テーブルの構造がシンプル
-
post_id
やphoto_id
などのカラムを個別に作らずに済む
-
-
拡張しやすい
- 新しく
Event
やArticle
などのモデルを追加してもComment
の構造を変更する必要がない
- 新しく
注意点
-
検索時のパフォーマンス
-
commentable_type
は文字列
なので、検索時に インデックスが効きにくい -
acts_as_taggable_on
のようなSTI (Single Table Inheritance)
を使うのも選択肢
-
-
関連を扱う際の制約
-
commentable
のクラスが特定できないため、dependent: :destroy
の挙動に注意
-
まとめ
ポリモーフィック関連付けは 1つのモデルが異なる複数のモデルに関連を持つとき に便利
柔軟な設計ができる一方で、パフォーマンス面や設計の複雑さも考慮する必要あり。
Discussion