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