【Rails】Polymorphicを使用した複数モデルの関連付け
Polymorphic(多様性)関連付けは、さまざまなモデルを同じ関連テーブルに関連付けるのに便利です。Polymorphic関連付けの使い方について詳しく説明します。
Polymorphic関連付けとは?
Polymorphic関連付けは、1つのテーブルを複数のモデルと関連付けるための方法です。これにより、異なるモデルのインスタンスを同じテーブルに格納できます。
関連付けするメリット
- 
シンプルなデータ構造 
 Polymorphic関連付けを使用することで、異なるモデルのインスタンスを同じテーブルに格納できます。データベース内のテーブル数を減らし、データベース構造をシンプルに保つことができます。例えば、いいねやコメントなどのアクティビティを追跡する場合、複数のテーブルを作成せずに1つのアクティビティテーブルで管理できます。
- 
効率的なクエリ 
 アクティビティの種類に関係なく、アクティビティデータを効率的にクエリできます。特定のユーザーに関連するすべてのアクティビティを取得する場合、1つのクエリで処理できます。これに対して、異なるアクティビティごとにテーブルを分けると、各テーブルに対して別々のクエリを実行する必要があります。
- 
拡張性 
 アプリケーションが成長するにつれて、新しい種類のアクティビティを追加する必要があるかもしれません。Polymorphic関連付けを使用すると、新しいアクティビティタイプを簡単に追加できます。新しいモデルを作成せずに、既存のアクティビティテーブルを使用して新しいアクティビティを追跡できます。
- 
コードの簡略化 
 異なるアクティビティごとにテーブルを作成せずに、1つのアクティビティテーブルを使用することで、コードを簡略化できます。
使用するシチュエーション
1. 1つのテーブルに異なる種類のリレーションシップを持つ場合
あるウェブアプリケーションには「コメント」機能があり、このコメントは「記事」と「写真」の2つの異なるモデルに関連付けられている場合。
通常の方法では、次のように2つの中間テーブルを使用する必要があります:
- ArticleComments (記事のコメント)
- PhotoComments (写真のコメント)
これらの中間テーブルを使用すると、2つの異なるモデルに対するコメントの管理が少し複雑になります。
代わりに、Polymorphicリレーションを使用すると、1つの「Comments」テーブルで異なるモデルに関連付けられたコメントを管理できます。データベース内の実際のテーブルは次のようになります:
Commentsテーブル:
| id | comment_text | commentable_id | commentable_type | 
|---|---|---|---|
| 1 | "素晴らしい記事です!" | 1 | "Article" | 
| 2 | "素晴らしい写真です!" | 1 | "Photo" | 
| 3 | "また記事を読みたいです!" | 2 | "Article" | 
このように、異なるモデルに関連付けられたコメントが同じテーブルで管理されています。commentable_id と commentable_type の組み合わせによって、どのモデルに関連付けられているかを特定できます。
2. リレーションシップが同じモデルに対して異なる名前で存在する場合:
例えば、「フォロワー」と「フォローしているユーザー」という2つの異なるリレーションシップがあるとします。通常、これらの関連付けは次のように別々の名前で定義されます:
- フォロワーのリレーションシップ: has_many :followers, class_name: "User", foreign_key: "follower_id"
- フォローしているユーザーのリレーションシップ: has_many :following, class_name: "User", foreign_key: "following_id"
しかし、これをPolymorphicリレーションを使用して単純化できます。次のように1つのテーブルで管理できます:
Relationshipsテーブル:
| id | follower_id | following_id | relationable_id | relationable_type | 
|---|---|---|---|---|
| 1 | 1 | 2 | 1 | "User" | 
| 2 | 3 | 1 | 2 | "User" | 
| 3 | 2 | 4 | 1 | "Page" | 
このように、1つのテーブルで「フォロワー」や「フォローしているユーザー」など、さまざまなリレーションシップを持つことができます。
具体例
では1つの具体例をもとに使い方を説明していきます。
例: コメントといいね
コメントといいねの機能があるとします。通常、それぞれの機能は別々のテーブルに格納されます。しかし、これらのアクションはどちらも「アクティビティ」として追跡できます。この場合、Polymorphic関連付けを使用して、異なるモデル(コメント、いいね)を同じ「アクティビティ」テーブルに格納できます。
実装手順
上記の「コメント」と「いいね」の例を元に、Polymorphic関連付けを実装する手順を説明します。
ステップ 1: データベースの設計
まず、データベーステーブルを設計します。以下は、コメント、いいね、およびアクティビティのテーブルの一部です。
- 
コメント(comments)テーブル: - 
id(コメントID)
- 
user_id(ユーザーID)
- 
content(コメントの内容)
 
- 
- 
いいね(likes)テーブル: - 
id(いいねID)
- 
user_id(ユーザーID)
- 
likable_id(いいね対象のID)
- 
likable_type(いいね対象の種類)
 
- 
- 
アクティビティ(activities)テーブル (Polymorphic関連付けを使用): - 
id(アクティビティID)
- 
user_id(ユーザーID)
- 
action(アクションの内容: コメントかいいねかなど)
- 
activity_id(コメントIDまたはいいねID)
- 
activity_type(コメントまたはいいねの種類)
 
- 
ステップ 2: モデルの作成
次に、これらのテーブルに対応するモデルを作成します。モデルは以下のようになります。
# Commentモデル
class Comment < ApplicationRecord
  belongs_to :user
end
# Likeモデル (Polymorphic関連付けを使用)
class Like < ApplicationRecord
  belongs_to :user
  belongs_to :likable, polymorphic: true
end
# Activityモデル (Polymorphic関連付けを使用)
class Activity < ApplicationRecord
  belongs_to :user
  belongs_to :activity, polymorphic: true
end
ステップ 3: ビューとコントローラ
コメントといいねの作成、表示、削除などのビューとコントローラを設定します。これらの部分は通常のRails開発と同じように行います。
関連付けによるデータの比較
Polymorphic関連付け前:
- Commentモデルのデータベース内データ
| id | user_id | content | created_at | updated_at | 
|---|---|---|---|---|
| 1 | 1 | コメント1 | 2023-09-26 10:00:00 | 2023-09-26 10:00:00 | 
| 2 | 2 | コメント2 | 2023-09-26 11:00:00 | 2023-09-26 11:00:00 | 
- Likeモデルのデータベース内データ
| id | user_id | likeable_id | likeable_type | created_at | updated_at | 
|---|---|---|---|---|---|
| 1 | 1 | 1 | Comment | 2023-09-26 10:30:00 | 2023-09-26 10:30:00 | 
| 2 | 2 | 2 | Comment | 2023-09-26 11:30:00 | 2023-09-26 11:30:00 | 
Polymorphic関連付け後:
- Commentモデルのデータベース内データ(変更なし)
| id | user_id | content | created_at | updated_at | 
|---|---|---|---|---|
| 1 | 1 | コメント1 | 2023-09-26 10:00:00 | 2023-09-26 10:00:00 | 
| 2 | 2 | コメント2 | 2023-09-26 11:00:00 | 2023-09-26 11:00:00 | 
- Likeモデルのデータベース内データ(Polymorphic関連付けを使用)
| id | user_id | likable_id | likable_type | created_at | updated_at | 
|---|---|---|---|---|---|
| 1 | 1 | 1 | Comment | 2023-09-26 10:30:00 | 2023-09-26 10:30:00 | 
| 2 | 2 | 2 | Comment | 2023-09-26 11:30:00 | 2023-09-26 11:30:00 | 
| 3 | 1 | 3 | Post | 2023-09-26 12:00:00 | 2023-09-26 12:00:00 | 
- Activitiesモデルのデータベース内データ (Polymorphic関連付けを使用)
| id | user_id | action | activity_id | activity_type | created_at | updated_at | 
|---|---|---|---|---|---|---|
| 1 | 1 | コメント | 1 | Comment | 2023-09-26 10:30:00 | 2023-09-26 10:30:00 | 
| 2 | 2 | コメント | 2 | Comment | 2023-09-26 11:30:00 | 2023-09-26 11:30:00 | 
| 3 | 1 | いいね | 1 | Like | 2023-09-26 12:00:00 | 2023-09-26 12:00:00 | 
| 4 | 2 | いいね | 2 | Like | 2023-09-26 12:30:00 | 2023-09-26 12:30:00 | 
| 5 | 1 | コメント | 3 | Comment | 2023-09-26 13:00:00 | 2023-09-26 13:00:00 | 
| 6 | 2 | いいね | 3 | Like | 2023-09-26 13:30:00 | 2023-09-26 13:30:00 | 
す。
Polymorphic関連付けを導入することで、LikeモデルがCommentモデルとPostモデルの両方を参照できるようになりました。
また、1つの activities テーブルで異なるモデル(コメントといいね)に関するアクティビティ情報が格納できました。このように、異なるモデルのデータを同じテーブルで管理することができ、柔軟性と効率性が向上します。
まとめ
Polymorphic関連付けは、異なるモデルを同じテーブルに格納したり、複数のモデルを1つの関連に結び付けたりする場合にとても便利です!
こういうのは実際に使ってみないと覚えづらいですよね。ポートフォリオで1部使用したのでそちらも参考になれば幸いです。



Discussion