0

I don't get why I'm having orphans records when I try to destroy a user. A User has one Cart which has many CartItem


User has one cart:
class User < ApplicationRecord
  has_one :cart, dependent: :destroy
  has_many :cart_items, through: :cart, dependent: :destroy
  has_many :samples, through: :cart_items, source: :cartable, source_type: 'Sample'
  has_many :tracks, through: :cart_items, source: :cartable, source_type: 'Track'
end

:dependent

Controls what happens to the associated object when its owner is destroyed:

  • :destroy causes the associated object to also be destroyed

https://apidock.com/rails/v5.2.3/ActiveRecord/Associations/ClassMethods/has_one

Cart has many items:

class Cart < ApplicationRecord
  belongs_to :user
  has_many :cart_items, dependent: :destroy
  has_many :samples, through: :cart_items, source: :cartable, source_type: 'Sample'
  has_many :tracks, through: :cart_items, source: :cartable, source_type: 'Track'
end

:dependent

Controls what happens to the associated objects when their owner is destroyed. Note that these are implemented as callbacks, and Rails executes callbacks in order. Therefore, other similar callbacks may affect the :dependent behavior, and the :dependent behavior may affect other callbacks.

  • :destroy causes all the associated objects to also be destroyed.

https://apidock.com/rails/v5.2.3/ActiveRecord/Associations/ClassMethods/has_many

And items:

class CartItem < ApplicationRecord
  belongs_to :cart
  belongs_to :cartable, polymorphic: true
end


I'd like to be able to destroy a User with for example User.last.destroy, but instead I've an error:
ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR:  update or delete on table "users" violates foreign key constraint "fk_rails_ea59a35211" on table "carts"
DETAIL:  Key (id)=(227) is still referenced from table "carts".

I was thinking that has_one :cart, dependent: :destroy would do the job but it looks like I'm wrong. What am I missing ?

Thanks for your time

Eyeslandic
  • 14,553
  • 13
  • 41
  • 54
Sumak
  • 927
  • 7
  • 21
  • 3
    What is `Cart.where(user_id: 227).count`? Perhaps you've managed to create multiple carts for one user, and that's messing up the database integrity. If you delete all "duplicate" carts, you could add a validation or even a unique index database constraint, to prevent it happening again. – Tom Lord Jul 03 '19 at 17:32
  • Indeed ! I have no idea how this happens tho (this is how I was crowding my Cart model: `10.times { |i| Cart.create!(user_id: User.all[i].id) }`. I've added a reference to cart to the users db, thanks for the debug and the advises :) – Sumak Jul 03 '19 at 18:29
  • What database ur using? – Giridharan Jul 03 '19 at 20:02
  • PostgreSQL, why that ? – Sumak Jul 03 '19 at 20:29
  • If you're using the `rails console`, try `reload!`ing it in case you're not working with the latest code. If you're sure you're working with the latest code, try isolating the issue to a minimal user with just 1 cart and 1 cart_item, and try deleting it. If you're able to delete that new specific user, there's most likely a database inconsistency. – Waclock Jul 04 '19 at 03:43
  • I got your error when doing `Model.find(1).delete` however `Model.find(1).destroy` worked. Are you sure you're using `destroy` and not `delete`? – Eyeslandic Jul 04 '19 at 11:45
  • Possible duplicate of [How to use dependent: :destroy in rails?](https://stackoverflow.com/questions/29560805/how-to-use-dependent-destroy-in-rails) – Eyeslandic Jul 04 '19 at 11:50

1 Answers1

1

I was facing this problem on my development machine, then I found root cause of this issue after lot of debugging and analysis. Postgres was creating extra constraints which was causing this. You need to drop the constraints. You can do this by a migration.

rails g migration remove_fk_constraints

class RemoveFkConstrains < ActiveRecord::Migration[5.2]
  def up
    execute "ALTER TABLE carts DROP CONSTRAINT fk_rails_ea59a35211;"
  end
end
Eyeslandic
  • 14,553
  • 13
  • 41
  • 54
Giridharan
  • 568
  • 4
  • 14
  • I just tried this and you're right if one uses `Model.find(1).delete` this error message shows, however `Model.find(1).destroy` works as advertised – Eyeslandic Jul 04 '19 at 11:51