ポリモーフィック(多様性)コードをより簡潔に管理するためのテーブル同士の関係の機能

↓わかりやすいイメージ

豚さん、鴨さん、犬さんがいたとして、3人の鳴き声を聞きたいときに、「ブヒブヒって言ってください」「クワクワと叫んでください」「ワンワンと鳴いてください」とそれぞれの振る舞いごとに命令をいうのではなく、3匹共に「鳴いてください。」と命令した方が楽だし、いちいち命令先の動物達のことを考えて命令しませんよね。プログラミングでも同じで、いちいちオブジェクトの実態のことを考えてコードを書いていたらコードは汚くなるし、大変です。鳴き声を出力するメソッド(命令)は全部同じ名前で使いたいのです。鳴き声についてはオブジェクトごとに勝手に変わってくれればいいのです。

下の例で言えば、ArticleBlockに記述しているpolymorphicがそれにあたります。

関係としてはArticle<ArticleBlock(1対多)の関係があって、

ArticleBlockとsentence,midium,embedをそれぞれ繋ぐ機能として

belongs_to :blockable, polymorphic: trueが使われています。

class Article < ApplicationRecord
  belongs_to :category
  belongs_to :author

  has_many :article_tags
  has_many :tags, through: :article_tags
  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'
〜略
class ArticleBlock < ApplicationRecord
belongs_to :article
belongs_to :blockable, polymorphic: true, dependent: :destroy
class Sentence < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  has_one :article, through: :article_block
end
class Medium < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  has_one :article, through: :article_block
〜略
class Embed < ApplicationRecord
  has_one :article_block, as: :blockable, dependent: :destroy
  has_one :article, through: :article_block
〜略

ポリモーフィックを使うことで出来ること

例えばsentence側からarticleを取ってくることができる(medium,embedも同様)

@sentence.article
=> #<Article:0x00007ff5a4fc9e68
 id: 8,
 category_id: 2,
 author_id: 4,
 uuid: "59271c4a-efba-45b2-a0cc-2c73b05d7acc",
 slug: "testes_2",
 title: "test_2",
 description: "",
 body: nil,
 state: "draft",
 published_at: nil,
 created_at: Thu, 28 Oct 2021 06:23:39 JST +09:00,
 updated_at: Fri, 29 Oct 2021 09:36:34 JST +09:00,
 deleted_at: nil>

article_blockからblockableを呼ぶことで関連するオブジェクトを呼ぶことができる