2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Rails】マイグレーションファイルでidではなくuuidを外部キーに設定する方法

Last updated at Posted at 2025-03-15

はじめに

こんにちは!オンラインスクールで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):

  1. 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)

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?