【问题标题】:PG::ForeignKeyViolation: ERROR after changing a has_and_belongs_to_many association in rails to a has_many :through associationPG::ForeignKeyViolation: 将 rails 中的 has_and_belongs_to_many 关联更改为 has_many :through 关联后出现错误
【发布时间】:2019-09-21 21:20:40
【问题描述】:

我最近将 has_and_belongs_to_many (HABTM) 关联切换为 has_many :through 关联,现在由于违反外键约束,我有很多失败的测试。这是一个示例测试失败消息:

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"

这是创建关联的表单。

这是我的模型与相关协会...

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

以及相关的架构:

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

在浏览器中一切正常。只是我的测试失败了,所有失败的测试都有同样的外键错误。

我不想开始为我的模型添加关联和外键只是为了让我的测试通过,因为预期的行为在浏览器中起作用。

我正在使用固定装置进行测试。这是问题吗?我的灯具是否有可能导致此错误的原因?仅供参考,我想继续使用灯具而不是将应用切换到工厂。

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

【问题讨论】:

    标签: ruby-on-rails postgresql testing activerecord has-many-through


    【解决方案1】:

    尝试删除并重新创建您的测试数据库:

    RAILS_ENV=test rails db:drop db:create
    

    也许测试数据库中有一个主/开发数据库没有的外键约束。

    【讨论】:

    • 谢谢!没有考虑到这一点。它通过就好了。看起来我正在正确地做 has_many :through 固定装置吗?这是一个问号,但 Rails 指南只提到了 HABTM。
    • 难道我需要使用dependent: :nullify?例如,Varianthas_many :choices, through: :selections,但假设我想删除一个变体?我也不想删除相应的选项(这些选项可能是“小”、“中”或“大”。这似乎是正确的方法吗?
    【解决方案2】:

    更新

    我发现了问题,所以在这里发布解决方案以防其他人需要它。

    以下是有效的固定装置:

    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
    

    然后,我需要将我的模型更新为:

    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
    

    我在VariantChoice 型号上都缺少has_many :selections, dependent: :destroy

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-17
      • 1970-01-01
      相关资源
      最近更新 更多