Home > Software engineering >  rails dependent: :destroy works with wrong ID value
rails dependent: :destroy works with wrong ID value

Time:10-26

my schema.db

  create_table 'pet', force: :cascade do |t|
    t.string 'name'
    t.datetime 'created_at', precision: 6, null: false
    t.datetime 'updated_at', precision: 6, null: false
  end

  create_table 'user', force: :cascade do |t|
    t.string 'name'
    t.references :pet, index: true, foreign_key: { on_delete: :nullify }
    t.datetime 'created_at', precision: 6, null: false
    t.datetime 'updated_at', precision: 6, null: false
  end

user model

class User < ApplicationRecord
  has_one :pet, foreign_key: :id, dependent: :destroy
end

pet model

class Pet < ApplicationRecord
  belongs_to :user, optional: true
end

show.erb

    <%= link_to t('delete'), user_path(id: @user.id), method: :delete %>
    <%= link_to t('.pet_delete'), pet_path(@auser.pet_id), method: :delete %>

user controller

  def destroy
    User.destroy(params[:id])
    redirect_to users_path
  end

pet controller

  def destroy
    Pet.destroy(params[:id])
    redirect_to users_path
  end

Problem : if i delete user id 5 with pet id 5, dependent destroy works well and it deletes (user id 5) & (pet id 5)

if i have user id 5 with pet id nil, and user id 4 with pet id 5, when i delete user id 5, user 5 deleted with user4's pet (pet id 5) so leftover result -> user id 5 delete, user id 4 with nil pet

something is wrong but i can't find what is problem. dependent destroy can only find same userId and petId in the same time.

i expecting if i delete user id 3 with pet id 1, want to make delete well i tried change position of dependent destroy(on pet model), change schema.rb's on_delete nullify to delete but not worked.

CodePudding user response:

The problem is that you specified id as a foreign key.

class User < ApplicationRecord
  has_one :pet, foreign_key: :id, dependent: :destroy
end

You need to specify user_id instead:

class User < ApplicationRecord
  has_one :pet, foreign_key: :user_id, dependent: :destroy
end

But, in a simple case like this you don't need to specify foreign key at all. As long as you have a column named user_id in pets table it will just work, since Rails automatically assumes that the foreign key should be <model>_id.

Also, please keep in mind that the foreign key should be added to the child, not the parent. So, you need to add user_id to pets table, not pet_id to the users table.

In the end, your schema.rb should look something like this:

  create_table 'pet', force: :cascade do |t|
    t.string 'name'
    t.datetime 'created_at', precision: 6, null: false
    t.datetime 'updated_at', precision: 6, null: false
    t.references :user, index: true, foreign_key: { on_delete: :nullify } # <== this should be added
  end

  create_table 'user', force: :cascade do |t|
    t.string 'name'
    # t.references :pet, index: true, foreign_key: { on_delete: :nullify } <== this should be removed
    t.datetime 'created_at', precision: 6, null: false
    t.datetime 'updated_at', precision: 6, null: false
  end
  • Related