LoginSignup
2
2

More than 5 years have passed since last update.

参照整合されているマスターデータをseed.rbで初期値セットする (Rails, PostgreSQL)

Last updated at Posted at 2015-10-08

課題

参照整合されているマスターデータをseed.rbを用いて初期値セットしたい。
初回のセットは問題なくできるのだが、参照されているマスターデータの削除・更新をしようとすると、「外部参照しているデータがあるからダメよ」とその処理の時点でエラーが発生してしまう。
そうするとマスターデータの更新を行うことができないじゃないか。。

結論としては、参照検査されるタイミングをデータの処理時点ではなく、トランザクションの終了時に遅延させるすることで対応した。

状況

下記テーブルにて、採用活動の採用状況管理を行っているとする。

リクルーティング者

  • テーブル名:Recruiting
  • カラム: name, age, address, status

リクルーティング状況マスター

  • テーブル名: RecruitingStatus
  • カラム: status

外部キー制約

recruiting.statusに対してrecruiting_status.statusから外部キー制約を行う。

対策

そこで、参照検査されるタイミングを遅延することで、一時的に削除・更新をできるようにした。

db/migrate/...にて外部キーを作成する際、PostgreSQLはデフォルトだとNOT DEFERRABLEなのでDEFERRABLE INITIALLY IMMEDIATEで作成する。

class AddForeignKeyToRecruiting < ActiveRecord::Migration
  def up
    execute <<-SQL
      ALTER TABLE
        "recruiting"
      ADD CONSTRAINT
        "recruiting_recruiting_status_fk"
      FOREIGN KEY
        ("status")
      REFERENCES
        "recruiting_status" ("status")
      ON DELETE NO ACTION
      ON UPDATE CASCADE
      DEFERRABLE INITIALLY IMMEDIATE;
    SQL
  end

  def down
    execute <<-SQL
      ALTER TABLE
        "recruiting"
      DROP CONSTRAINT if exists "recruiting_recruiting_status_fk";
    SQL
  end
end

seed.rbを用いて初期データを追加する。

  • トランザクションの中で処理を行う。
  • SET CONSTRAINTS recruiting_recruiting_status_fk DEFERREDDEFERRABLE INITIALLY DEFERREDに変更する。
begin
  ActiveRecord::Base.transaction do
    connection = ActiveRecord::Base.connection
    deferred_sql = 'SET CONSTRAINTS recruiting_recruiting_status_fk DEFERRED'
    connection.execute(deferred_sql)

    RecruitingStatus.delete_all

    RecruitingStatus.create!([
      { status: '不採用' },
      { status: '採用' },
    ])
  end
rescue => e
  puts "Rollback for RecruitingStatus:\n#{e}"
end

これでseed.rbを用いてマスターデータのセット・更新ができるようになった。

参考

SET CONSTRAINTS

2
2
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
2