Techioz Blog

Ruby: テーブルの更新または削除が外部キー制約に違反します

概要

現在、Shop.last.destroy を実行するとこのエラーが発生しますが、理由がわかりません。

PG::ForeignKeyViolation: ERROR:  update or delete on table "credit_changes" violates foreign key constraint "fk_rails_16918229d0" on table "sms_historicals" (ActiveRecord::InvalidForeignKey)

そしてこれはPostgres DBです

私のモデルは次のようになります。

class SmsHistorical < ApplicationRecord
  belongs_to :customer
  belongs_to :credit_change, optional: true
  belongs_to :notification_setting, optional: true
end

class CreditChange < ActiveRecord::Base 
  belongs_to :credit
  belongs_to :customer
  has_one :sms_historicals
  has_one :email_historicals
end

これらのテーブルを作成するための移行は次のとおりです。

create_table :credit_changes, if_not_exists: true do |t|
  t.integer "credit_id"
  t.text "credit_notes"
  t.decimal "credit_amount_changed", precision: 4, scale: 2, default: 0.0
  t.datetime "date"
  t.string "transaction_type"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
end

class CreateSmsHistoricals < ActiveRecord::Migration[6.1]
  def change
    create_table :sms_historicals, if_not_exists: true do |t|
      t.string :phone_number
      t.text :message
      t.references :customer, null: true, foreign_key: true, on_delete: :cascade
      t.references :credit_change, null: true, foreign_key: true, on_delete: :cascade
      t.references :notification_setting, null: true, foreign_key: true, on_delete: :cascade
      t.timestamps
    end
  end
end

解決策

belongs_to :credit_change は、Sms テーブルと Credit テーブルの間の FK です。そして、クレジット ID は Sms テーブルに保存されます。 Credit を削除する場合は、Sms テーブルのデータもクリアする必要があります。例えば

class CreditChange < ActiveRecord::Base 
  has_one :sms_historicals, dependent: :nullify
end

Sms テーブルのbelongs_to :credit_changeをオプションとして設定しているため、ここでは :nullify を選択します。ただし、他のものにすることもできます: https://guides.rubyonrails.org/association_basics.html#options-for-has-one