Ruby on Rails

【Rails】STI(Single Table Inheritance)の使い方について

Railsガイドを読んでいた際にSTI(Single Table Inheritance)がでてきて??となったので、これについて調べたことを記事にしたいと思います。

https://railsguides.jp/autoloading_and_reloading_constants.html#sti-%E5%8D%98%E4%B8%80%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E7%B6%99%E6%89%BF

STI(単一テーブル継承)とは

同一テーブル内に継承関係にあるクラスのカラムをすべて持ってしまうことを言います。例えば次のような継承関係にあるモデルがあるとします。

それぞれのテーブルを作ってカラムを作っていくのが通常かと思いますが、STIでは一つのテーブルに収めるといった表現をします。

RailsでのSTIの使い方

RailsではSTIがデフォルトでサポートされていて、テーブル定義を行うだけでかんたんに使うことができます。

class CreatePlayers < ActiveRecord::Migration[6.1]
  def change
    create_table :players do |t|
      t.string  :name
      t.string  :club
      t.integer :pitching_speed
      t.string :position
      t.string  :type
      t.timestamps
    end
  end
end

typeカラムを保持したテーブルを作成します。positionカラムはSockerPlayerとBaseballPlayerで使用、pitching_speedカラムはPitcherで使用するためのカラムとしました。
それでは、実際にレコードを作ってみます。

Player.create(name: 'Uchii')
=> #<Player:0x00007f96543d25b0
 id: 1,
 name: "Uchii",
 club: nil,
 pitching_speed: nil,
 position: nil,
 type: nil>
# Playerモデルから作った場合のtypeはnilになる

BaseballPlayer.create(name: 'Yamada', club: 'Yakuruto')
=> #<BaseballPlayer:0x00007f96523be5f8
 id: 2,
 name: "Yamada",
 club: "Yakuruto",
 pitching_speed: nil,
 position: nil,
 type: "BaseballPlayer">
# typeカラムに自動でモデル名が入る

Pitcher.create(name: 'Morishita', pitching_speed: 148, position: 'pitcher', club: 'Hiroshima')
=> #<Pitcher:0x00007f9652c6b778
 id: 3,
 name: "Morishita",
 club: "Hiroshima",
 pitching_speed: 148,
 position: "pitcher",
 type: "Pitcher">

上のようにplayersテーブルの各レコードのtypeカラムに、モデル名のBaseballPlayer, Pitcherがそれぞれ保存されました。次にそれぞれのモデルに対する操作で発行されるSQLを見ておきます。

Pitcher.find_by(name: 'Morishita')
SELECT "players".* FROM "players" WHERE "players"."type" = ? AND "players"."name" = ? LIMIT ?  [["type", "Pitcher"], ["name", "Morishita"], ["LIMIT", 1]]

Pitcher.count
SELECT COUNT(*) FROM "players" WHERE "players"."type" = ?  [["type", "Pitcher"]]

自動で対象となるモデルをtypeカラムによって絞り込んで、検索やカウントを行っていることが分かります。

まとめ

以上がRailsのSTIの使い方でした。Railsにこんな機能があるなんて知らなかったです。
継承関係をつくるときの選択肢の一つとして覚えておきたいと思いました!
ここまで読んでいただき、ありがとうございました。
参考にしたブログ記事を下に乗せておきます。

参考

https://easyramble.com/rails-activerecord-single-table-inheritance.html
https://dev.classmethod.jp/articles/rails-sti-with-one-controller/

ABOUT ME
sakai
東京在住の30歳。元々は車部品メーカーで働いていてましたが、プログラミングに興味を持ちスクールに通ってエンジニアになりました。 そこからベンチャー → メガベンチャー → 個人事業主になりました。 最近は生成 AI 関連の業務を中心にやっています。 ヒカルチャンネル(Youtube)とワンピースが大好きです!