【Rails】STI(Single Table Inheritance)とポリモーフィックの違いと使い方

目次

STI

STIとは

STIは、1つのデータベーステーブルで複数のモデルを管理する仕組みです。

共通の属性や振る舞いを持つ複数のモデルを効果的に管理することができます。

例えば、複数の食べ物を販売しているとき、その名前や価格などを同じテーブルに保存して管理することができます。

ここでは販売している食べ物を管理するためのFoodモデルを作成してSTIを実現してみます。

まずはモデルとしてFoodモデルを作成します。

class Food < ApplicationRecord
end

Foodモデルには以下の属性を持っている想定とします。

name [sring]
price [integer]
type [string] # STIをするために必要なカラム

そして実際に管理していきたいモデルを作成します。

ここでは野菜とお肉を管理したいのでVegetableモデルとMeatモデルを作成します。

ここで注意すべきなのは最初に作成したFoodのクラスを継承する必要があることです。

class Vegetable < Food
end
class Meat < Food
end

この状態で野菜とお肉のデータを作成してみます。

Vegetable.create(name: '人参', price: 100)
Meat.create(name: '牛肉', price: 500)

このようにしてcreateするとFoodクラスを継承しているので、foodsテーブルにデータが保存されます。

例えばFood.find(1)をすると以下のようなデータを取得できます。

<Food id: 1, name: '人参', price: 100, type: 'Vegetable'>

typeカラムには自動的にcreateしたときのモデル名が入ります。

このtypeによって1つのテーブルで複数モデルを管理できるようになっています。

ポリモーフィック

ポリモーフィックとは

ポリモーフィックは、1つのアソシエーションを複数のモデルに対して設定することができる仕組みです。

これにより、1つのモデルが複数の他のモデルと関連付けられることが可能になります。

例えば、コメントが複数のモデル(投稿、画像、ビデオなど)に対して紐付けられる場合、ポリモーフィックを使用して柔軟な関連付けを実現できます。

ここではコメントを投稿できる記事や画像がある場合のポリモーフィック関連を実現してみます。

commentモデルのマイグレーションファイルは以下を想定します。

class CreateComments < ActiveRecord::Migration[7.1]
  def change
    create_table :comments do |t|
      t.references :commentable, polymorphic: true
      t.string :title
      t.text :content

      t.timestamps
    end
  end
end

上記をマイグレーションするとcommentsテーブルにはcommentable_typecommentable_idカラムが自動生成されます。

関連付けを定義するCommentモデルは以下のようにし、belongs_toメソッドにpolymorphic: trueオプションを指定しポリモーフィック関連を有効にします。

class Comment < ApplicationRecord
  belongs_to :commentable, polymorphic: true
end

次に記事(Articleモデル)や画像(Imageモデル)にポリモーフィック関連付けをして、複数のモデルに対して1つのCommentモデルを関連付けてみます。

class Article < ApplicationRecord
  has_many :comments, as: :commentable
end

class Image < ApplicationRecord
  has_many :comments, as: :commentable
end

上記の例では、Commentモデルがポリモーフィック関連付けを持ち、ArticleモデルとImageモデルが関連付けられています。

この状態で記事のデータを作成して、どのように登録されているか確認したいと思います。

article = Article.create(name: 'sample_name')
comment = article.comments.create(title: 'sample_title', content: 'sample_text')

上記のようにデータを作成した後、Comment.find_by(commentable: article)をすると以下のようなデータを取得できます。

<Comment id: 1, commentable_type: "Article", commentable_id: 1, title: "sample_title", content: "sample_content", ...>

違いとメリット・デメリット

STIとポリモーフィックの違いは、主にデータの構造と関連付けの柔軟性にあります。

STIは1つのテーブルに複数のモデルを持つため、データベースのカラムが無駄になる可能性があります。

一方、ポリモーフィックは複数のモデルを1つのアソシエーションで関連付けることができるため、より柔軟性がありますが、データベースの設計がやや複雑になることがあります。

STIは簡単に実装できますが、データベースの冗長性が問題になる可能性があり、ポリモーフィックは柔軟性が高いですが、データベースの設計が複雑になることがあります。

まとめ

どちらの手法も、正しく使用することでコードの保守性を向上させ、アプリケーションの拡張性を高めることができます。

自分のプロジェクトの要件に最適な選択を行い、効果的なデータベース設計を行っていきましょう。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次