どうもこんにちは。
今回はポリモーフィックについてまとめます。
ポリモーフィックってなんぞや?
ポリモーフィックとは、複数のモデル同士の関連付けの考え方です。
この考え方は、異なるモデルを単一の関連で扱う機能です。
例えば、以下のようにテーブルが存在しているとします。
commentsテーブル
カラム名 | 型 | 値1 | 値2 | 値3 |
---|---|---|---|---|
id | integer | 1 | 2 | 3 |
comment | text | ワンちゃんかわいい!! | よろしくお願いします。 | この時期寒くね? |
article_id | integer | null | 1 | null |
photo_id | integer | 2 | null | null |
tweet_id | integer | null | null | 1 |
articlesテーブル
カラム名 | 型 | 値1 | 値2 |
---|---|---|---|
id | integer | 1 | 2 |
article_title | string | 私の自己紹介 | 私の会社について |
photosテーブル
カラム名 | 型 | 値1 | 値2 |
---|---|---|---|
id | integer | 1 | 2 |
photo_title | string | 山からの景色 | 飼っているペットの写真 |
tweetsテーブル
カラム名 | 型 | 値1 | 値2 |
---|---|---|---|
id | integer | 1 | 2 |
tweet_title | string | 海なう | 美味しいご飯なう |
このような状態だと、commentsテーブルではarticle_id
に値が入っているときにphoto_id
とtweet_id
はnull
になってしまっていますね。
デメリット
データベースの容量の無駄
上記のようにデータベースを作成してしまうと、無駄なカラムが出現してしまい、無駄に容量を使用してしまいます。
これは、データベース使用料などのコストがかかってしまうことに繋がってしまいます。
拡張性の欠如
上記のデータベースだと、記事,写真,ツイート以外のものに対してコメントできるようになった場合、カラムを増やなければなりません。
これもデータベースの容量の無駄に繋がってしまいますね。。。
データの整合性
article_id
カラム,photo_id
カラム,tweet_id
カラム全てに値が入っていたり、全てに値が入っていなかったりする可能性があります。
この場合、チェックする機構を作ればいい話ですが、ポリモーフィックを導入するとこのチェックする機構が必要なくなります。
ポリモーフィックを導入するとどうなる?
Commentテーブルは以下のようになります。
commentsテーブル
カラム名 | 型 | 値1 | 値2 | 値3 |
---|---|---|---|---|
id | integer | 1 | 2 | 3 |
comment | text | ワンちゃんかわいい!! | よろしくお願いします。 | この時期寒くね? |
commentable_type | string | Photo | Article | Tweet |
commentable_id | integer | 2 | 1 | 1 |
nullがなくなってカラムも減ります!
では実際に実装してみましょう。
実装手順
手順1. Commentテーブルを作成する
以下のコマンドでマイグレーションファイルを作成する。
rails g migration CreateCommentTable
以下のようにマイグレーションファイルを編集します。
create_table :comments do |t|
t.string :content
t.references :commentable, polymorphic: true, index: true
t.timestamps
end
手順2. Commentモデルに設定する
class Comment < ApplicationRecord
belongs_to :commentable, polymorphic: true
end
手順3. 関連させたいモデルに設定する
class Article < ApplicationRecord
has_many :comments, as: :commentable
end
class Photo < ApplicationRecord
has_many :comments, as: :commentable
end
class Event < ApplicationRecord
has_many :comments, as: :commentable
end
手順4. コントローラに処理を記述
class ArticlesController < ApplicationController
before_action :set_article, only: %i[comment_create]
def comment_create
@comment = Comment.new(comment_params)
@comment.commentable_type = 'Article'
@comment.commentable_id = @article.id
if @comment.save
redirect_to articles_path
else
render :new
end
end
private
def set_article
@article = Article.find(params[:id])
end
def comment_params
params.require(:comment).permit(:comment)
end
end
Photo,Tweetのコントローラに対しても同様にコードを記述すればOKです!
うまくやれば、Commentsコントローラに一括で実装できます!
まとめ
ポリモーフィックはデータベース使用料などのコストを抑えるなどの目的のために実装すべき仕組みだと思います。
以上