ポリモーフィック関連を使うと、複数のモデルに属していることを1つの関連付けで表現できる
July 30, 2020
こんにちは、たわらです。
ポリモーフィック関連について整理した記事です。
モデルのコードはこんな感じ
ブログ記事を作成するサービスを考えます。記事をブロックを追加するかたちで作成します。記事は、Ariticle ブロックを複数持っているということです。そして、記事ブロックには 3 種類あります。文章と画像です。
Sentence モデルと Medium モデルがあり、それらに Ariticleblock モデルがポリモーフィック関連しているとします。
それぞれこんなふうになります。
Ariticleblock モデル
class ArticleBlock < ApplicationRecord
belongs_to :article
belongs_to :blockable, polymorphic: true, dependent: :destroy
# ...
end
Sentence モデル
class Sentence < ApplicationRecord
has_one :article_block, as: :blockable, dependent: :destroy
# ...
end
Medium モデル
class Medium < ApplicationRecord
has_one :article_block, as: :blockable, dependent: :destroy
# ...
end
Articleblock モデルにpolymorphic: true
とあります。これでポリモーフィック関連ができます。blockable という存在しないテーブル名に属している、と読めます。
Sentence モデルと Medium モデルにはas: :blockable
とあります。Articleblock モデルに blockable として関連する、と読めます。
カラムの作成はこんな感じ
Ariticle ブロックのカラムにはポリモーフィック関連のための準備が必要です。
class CreateArticleBlocks < ActiveRecord::Migration[5.2]
def change
create_table :article_blocks do |t|
t.belongs_to :article
t.belongs_to :blockable, polymorphic: true
t.timestamps
t.index :level
end
end
end
〇〇 able を作成する必要があるようです。
こうすると自動的に Ariticleblock テーブルに、blockable_id と blockable_type が追加されます。
この状態で、Sentence.new をすると自動的に、blockable_id に適当な数値が入り、blockable_type に"Sentence"と入ります。
コンソールでの出力はこんな感じ
[1] pry(main)> ArticleBlock.first
ArticleBlock Load (1.7ms) SELECT `article_blocks`.* FROM `article_blocks` ORDER BY `article_blocks`.`id` ASC LIMIT 1
=> #<ArticleBlock:0x00007ffa2e9d37f0
id: 1,
article_id: 1,
blockable_type: "Sentence",
blockable_id: 1,
created_at: Wed, 15 Jul 2020 16:43:32 JST +09:00,
updated_at: Wed, 15 Jul 2020 16:43:32 JST +09:00>
[2] pry(main)> ArticleBlock.first.blockable
ArticleBlock Load (0.6ms) SELECT `article_blocks`.* FROM `article_blocks` ORDER BY `article_blocks`.`id` ASC LIMIT 1
Sentence Load (1.2ms) SELECT `sentences`.* FROM `sentences` WHERE `sentences`.`id` = 1 LIMIT 1
=> #<Sentence:0x00007ffa2eaa9fd0 id: 1, body: "<p>およよよよ</p>", created_at: Wed, 15 Jul 2020 16:43:32 JST +09:00, updated_at: Wed, 15 Jul 2020 16:43:46 JST +09:00>