はじめに
こんにちは!オンラインスクールでRuby on Railsを中心に学習中のくりと申します🐣
uuidを使用するテーブルを外部キーとして参照しようとした際、
マイグレーションファイルの適用に失敗し書き方につまずいたため、備忘録としてまとめます。
初学者のアウトプット記事です。間違いやより良い方法がありましたら、コメント等で教えていただけますと幸いです🙇♀️
前置き
travel_booksテーブルとnotesテーブルはリレーションを組むようにします。
travel_booksテーブルにはuuidを採用しており、notesテーブルに外部キーとして
travel_booksテーブルのuuidを参照させます。
補足:uuid導入の経緯
開発中の旅行のしおりを投稿するサービスでは、ユーザーがしおりを投稿する際に公開・非公開を選択できるようにしています。 通常データベースのidには連番が用いられますが、連番のidはURLから容易に推測されやすく、非公開のしおりでも第三者から閲覧されるリスクがありました。 それを回避するためにランダムな文字列であるuuidを導入しました。※上記のテーブルは簡易的な構造に書き換えています
環境
- macOS(Apple Silicon)
- Docker
- Ruby 3.2.3
- Rails 7.2.1
- PostgreSQL
結論
references型カラムに、参照する外部キーの型(type: :uuid
)を指定し、
foreign_keyオプションで明示的に外部キーとして参照するテーブルとカラム(foreign_key: { to_table: :<参照先テーブル名>, primary_key: :<カラム名> }
)を指定する必要がありました。
class CreateNotes < ActiveRecord::Migration[7.2]
def change
create_table :notes, id: :uuid do |t|
t.references :travel_book, null: false, type: :uuid, foreign_key: { to_table: :travel_books, primary_key: :uuid }
t.string :title, null: false
t.text :body
t.timestamps
end
end
end
Railsガイドに既存のカラムに外部キー制約をつける場合記載があったため、こちらを参考にしました。
Railsガイド引用(※1):
参照される主キーを持つテーブルから、外部キーを追加するテーブルのカラム名を導出できない場合は、:columnオプションでカラム名を指定できます。また、参照される主キーが:idでない場合は、:primary_keyオプションを利用できます。
add_foreign_key :articles, :authors, column: :reviewer, primary_key: :email
上はarticlesテーブルに制約を追加します。この制約は、emailカラムがarticles.reviewerフィールドと一致する行が、authorsテーブルに存在することを保証します。
たとえば、authors.emailを参照するarticles.reviewerに外部キーを追加するには以下のようにします。
つまったポイント
foreign_keyオプションでテーブルとカラムを指定しない場合、外部キーがuuidを参照できずエラーになる
最初はRilsガイドの内容から、referencesカラムにtype: :uuid
をつけるだけで、参照先のテーブルのidではなく、uuidを参照するようになるのかと思いました。
class CreateNotes < ActiveRecord::Migration[7.2]
def change
create_table :notes, id: :uuid do |t|
t.references :travel_book, type: :uuid, foreign_key: true ## ここ
t.string :title, null: false
t.text :body
t.timestamps
end
end
end
Railsガイド引用(※2):
- UUIDで参照を追加する
モデル間の関連付けを参照で作成するときは、主キーの種別との一貫性を維持するために、以下のようにデータ型を:uuidとして指定します。create_table :posts, id: :uuid do |t| t.references :author, type: :uuid, foreign_key: true # 他のカラム... t.timestamps end
この例では、postsテーブルのauthor_idカラムはauthorsテーブルのidカラムを参照しています。主キーの種別を明示的に:uuidに設定することで、外部キーカラムが参照する主キーのデータ型と一致することが保証されます。他の関連付けやデータベースに合わせて構文を調整してください。
しかし、マイグレーションファイルを適用すると、以下のエラーが出力されてしまいました。
id以外のカラムを外部キーとして参照する際は、foreign_keyオプションに明示的に参照するテーブルとカラムを記述する必要があるようでした。
PG::UndefinedColumn: ERROR: column "id" referenced in foreign key constraint does not exist
参考・引用資料
引用
Railsガイド引用(※1)
Railsガイド引用(※2)
参考