I recently switched a has_and_belongs_to_many
(HABTM) association to a has_many:through
association and now I have a lot of failing tests due to violating foreign key constraints. Here's an example test failure message:
DRb::DRbRemoteError: PG::ForeignKeyViolation: ERROR: update or delete on table "choices" violates foreign key constraint "fk_rails_d6ffbc38aa" on table "selections"
DETAIL: Key (id)=(506907318) is still referenced from table "selections"
Here's the form that creates the association.
Here are my models with the relevant associations...
models/variant.rb
class Variant < ApplicationRecord
has_many :selections
has_many :choices, through: :selections
end
models/choice.rb
class Choice < ApplicationRecord
has_many :variants, through: :selections
belongs_to :option
end
models/selection.rb
class Selection < ApplicationRecord
belongs_to :choice
belongs_to :variant
end
And the relevant schemas:
create_table "variants", force: :cascade do |t|
t.string "sku"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "account_id"
t.bigint "product_id"
t.index ["account_id"], name: "index_variants_on_account_id"
t.index ["product_id"], name: "index_variants_on_product_id"
end
create_table "choices", force: :cascade do |t|
t.string "name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
t.bigint "option_id"
t.bigint "account_id"
t.index ["account_id"], name: "index_choices_on_account_id"
t.index ["option_id"], name: "index_choices_on_option_id"
end
create_table "selections", force: :cascade do |t|
t.bigint "choice_id"
t.bigint "variant_id"
t.datetime "created_at", precision: 6
t.datetime "updated_at", precision: 6
t.index ["choice_id"], name: "index_selections_on_choice_id"
t.index ["variant_id"], name: "index_selections_on_variant_id"
end
Everything works fine in the browser. It's just my tests that are failing and all of the failing tests have this same foreign key error.
I don't want to start adding associations and foreign keys to my models just to get my tests passing since the expected behavior is working in the browser.
I'm using fixtures for my tests. Is this the problem? Is there something about my fixtures that could be causing this error? FYI, I want to continue using fixtures and not switch the app to factories.
test/fixtures/variants.yml
small_t_shirt_in_red:
id: 1
account: fuzz
product: t_shirt
sku: FUZZ-T-001
choices: small, red
medium_generic_gadget_in_blue:
id: 2
account: generic_gadgets
product: gadget
sku: GENERIC-001
choices: medium, blue
test/fixtures/choices.yml
small:
name: Small
medium:
name: Medium
large:
name: Large
red:
name: Red
blue:
name: Blue
test/fixtures/selections.yml
small_t_shirt_selection:
choice_id: 1
variant_id: 1
red_t_shirt_selection:
choice_id: 4
variant_id: 1
medium_generic_selection:
choice_id: 2
variant_id: 2
blue_generic_selection:
choice_id: 5
variant_id: 2
Try dropping and recreating your test DB:
RAILS_ENV=test rails db:drop db:create
Maybe the test DB has a foreign key constraint in it that the main/dev DB doesn't.
I figured out the problem, so posting the solution here in case anyone else needs it.
Here are the fixtures that worked:
test/fixtures/variants.yml
small_t_shirt_in_red:
account: fuzz
product: t_shirt
sku: FUZZ-T-001
choices: small, red
medium_generic_gadget_in_blue:
account: generic_gadgets
product: gadget
sku: GENERIC-001
choices: medium, blue
test/fixtures/choices.yml
small:
name: Small
medium:
name: Medium
large:
name: Large
red:
name: Red
blue:
name: Blue
test/fixtures/selections.yml
red_t_shirt_selection:
choice: red
variant: small_t_shirt_in_red
medium_generic_selection:
choice: medium
variant: medium_generic_gadget_in_blue
Then, I needed to update my models to this:
models/variant.rb
class Variant < ApplicationRecord
has_many :selections, dependent: :destroy
has_many :choices, through: :selections
end
models/choice.rb
class Choice < ApplicationRecord
has_many :selections, dependent: :destroy
has_many :variants, through: :selections
belongs_to :option
end
models/selection.rb
class Selection < ApplicationRecord
belongs_to :choice
belongs_to :variant
end
I was missing the has_many:selections, dependent: :destroy
on both the Variant
and Choice
models.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.