ポリモーフィック(多様性)コードをより簡潔に管理するためのテーブル同士の関係の機能
↓わかりやすいイメージ
豚さん、鴨さん、犬さんがいたとして、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を呼ぶことで関連するオブジェクトを呼ぶことができる