【Rails】polymorphic(ポリモーフィック)って何?使い方は?

Ruby on Rails
記事内に広告が含まれています。

Railsで開発していると、polymorphic(ポリモーフィック)関連という言葉を目にすることがあります。

ただ、実際に使ったことがなかったり、なんとなくで理解しているという方も多いのではないでしょうか?

この記事では、そんな方向けに ポリモーフィック関連の仕組みと使い方 を説明します。

ポリモーフィック(polymorphic)とは?

簡単に言うと、1つのモデル(テーブル)が、複数の親モデルと関連付けられる仕組みです。

例)コメント機能

  • Post(投稿)親モデル
  • Photo(写真)親モデル
  • Comment(コメント)子モデル

投稿と写真にコメントをつけたい!
でも、commentsテーブルを2つ作るのは非効率。

そんなときに使えるのが polymorphic: true です。

実装例

ER図(簡易版)

子テーブルには、関連先のモデル名を示す commentable_type と、関連先レコードのidを示す commentable_id という2つのカラムを用意します。

+---------+        +----------+
|  posts  |        |  photos  |
+---------+        +----------+
| id      |◀─┐  | id       |◀─┐
| title   |    │  | url      |    │
+---------+    │  +----------+    │
               │                  │
               ▼                  ▼
+-----------------------------+
|          comments           |
+-----------------------------+
| id                          |
| body                        |
| commentable_type (string)   |  ← "Post" or "Photo"
| commentable_id (integer)    |  ← 対象モデルのid
+-----------------------------+

モデル設定

親モデルでは:asオプション付きのhas_manyを、子モデルでは:polymorphicオプション付きのbelongs_toを書きます。

ここでのポイントは、has_many:as オプションや belongs_to の引数、そして comments テーブル内の commentable_type / commentable_id というカラム名の「commentable」の部分をすべて一致させていることです。

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

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

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

使い方

post = Post.create(title: "初投稿")
photo = Photo.create(url: "baby.png")

post.comments.create(body: "いいね!")
photo.comments.create(body: "かわいい!")

Comment.all で確認すると、以下のようにどちらのコメントも同じ comments テーブルに保存されます。

idbodycommentable_typecommentable_id
1“いいね!”“Post”1
2“かわいい!”“Photo”1

最後に

ポリモーフィック関連は、少しとっつきにくい名前ですが、使い方はシンプルですね。

最後までお読みいただきありがとうございました。

皆さんからのコメントやSNSでのシェア、嬉しい投稿をいただくと本当に励みになります。

もしこの記事が気に入ったら感想をコメントやSNSでシェアしていただけると嬉しいです。

皆さんの声を聞かせてくださいね!

Ruby on Rails
tetsuをフォローする
簿記はじめるってよ

コメント

タイトルとURLをコピーしました