ポリモーフィック関連付けとは

動機

Railsで記事に埋め込み機能を実装する際に、ポリモーフィック関連付けが出てきたので、理解を深めるためにも備忘録としてメモを書いていきます。

以下のモデル構成で説明していきます。

# article_block.rb

class ArticleBlock < ApplicationRecord
  belongs_to :article
  belongs_to :blockable, polymorphic: true, dependent: :destroy
  # ...
end
# sentence.rb

class Sentence < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  # ...
end
# medium.rb

class Medium < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  # ...
end
# embed.rb

class Embed < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  # ...
end
# article.rb

class Article < ApplicationRecord
  has_many :article_blocks, -> { order(:level) }, inverse_of: :article
  has_many :sentences, through: :article_blocks, source: :blockable, source_type: 'Sentence'
  has_many :media, through: :article_blocks, source: :blockable, source_type: 'Medium'
  has_many :embeds, through: :article_blocks, source: :blockable, source_type: 'Embed'
  # ...
end


ポリモーフィックとはなにか?

ポリモーフィック関連付けを使うと、ある1つのモデルが他の複数のモデルに属していることを、1つの関連付けだけで表現できます。

:引用 Active Record の関連付け - Railsガイド

上記のコードを例にすると、ArticleBlockモデルは、複数のモデルSentence, Medium, Embedに属していることを1つの関連付けのblockableだけで表現できています。

ポリモーフィックってなんなの?という人におすすめの記事です。
Railsのポリモーフィック関連とはなんなのか - Qiita

この記事を読んで、「ダックタイピング」、「インターフェース」という言葉がでてきてあまり理解できなかったので、調べようと思いました。

ポリモーフィック関連付けの方法

説明

  • belongs_to宣言に:polymorphicオプションを指定すると、ポリモーフィック関連になる
  • 参照先となるモデルをあらかじめ定義せず、参照元となるオブジェクトごとに指定する関連

    使い方

  • 参照元となるモデルに対応するテーブルに、参照先のIDと参照先クラスを指定するカラムをそれぞれ生成
  • 参照先のIDを保存するカラムは、
    「belongs_to宣言で渡す関連名_id」
  • 参照先クラスを指定するカラムは「関連名type」

:引用 ポリモーフィック関連 | Railsドキュメント


今回のモデル構成で説明してみます。

下記のArticleBlockクラスでポリモーフィック関連を利用するために、belongs_to :blockablepolymorphicオプションが指定されています。

# article_block.rb

class ArticleBlock < ApplicationRecord
  belongs_to :article
  belongs_to :blockable, polymorphic: true, dependent: :destroy
  # ...
end


asオプションとは?

:asオプションを設定すると、ポリモーフィック関連付けを指定できます。

:引用  Active Record の関連付け - Railsガイド

ポリモーフィック関連付けの利点

1つのモデルが他の複数のモデルに属していることを、一つの関連付けだけで表現できることです。 両者のコードを比べるとポリモーフィック関連付けありの方がコードが見やすくなっているのがわかると思います。

# article_block.rb

# ポリモーフィック関連付けなし

class ArticleBlock < ApplicationRecord
  belongs_to :article
  belongs_to :sentence
  belongs_to :medium
  belongs_to :embed
  # ...
end
# article_block.rb

# ポリモーフィック関連付けあり

class ArticleBlock < ApplicationRecord
  belongs_to :article
  belongs_to :blockable, polymorphic: true, dependent: :destroy
  # ...
end

参考にしたサイト

Active Record の関連付け - Railsガイド

ポリモーフィック関連 | Railsドキュメント

Railsのポリモーフィック関連とはなんなのか - Qiita

ポリモーフィック関連のコントローラー - 猫Rails