【问题标题】:Foreign key constraint issue with uniqueness validation test唯一性验证测试的外键约束问题
【发布时间】:2018-11-23 10:06:14
【问题描述】:

运行 Rails 4.2.8

我添加了一个foreign_key 为user_id 的新模型。虽然功能上一切似乎都正常,但当我运行测试确认 user_id 的唯一性验证时,我收到了 ActiveRecord::InvalidForeignKey 错误。详情如下。

迁移

create_table :standard_accounts do |t|
  t.timestamps null: false
  t.references :user, index: true, foreign_key: true
end

型号

class StandardAccount < ActiveRecord::Base
  belongs_to :user

  validates_presence_of :user_id  
  validates_uniqueness_of :user_id
end

structure.sql(由于烦人的原因,我们使用的是 strucuture.sql 而不是 schema)

ALTER TABLE ONLY public.standard_accounts
  ADD CONSTRAINT fk_rails_6bc98ede2c FOREIGN KEY (user_id) REFERENCES public.users(id);

测试

RSpec.describe StripeStandardAccount, type: :model do
  it { should belong_to(:user) }
  it { should validate_presence_of(:user_id) }
  it { should validate_uniqueness_of(:user_id) }
  ...

测试失败

1) StandardAccount should validate that :user_id is case-sensitively unique
 Failure/Error: it { should validate_uniqueness_of(:user_id) }

 ActiveRecord::InvalidForeignKey:
   PG::ForeignKeyViolation: ERROR:  insert or update on table "standard_accounts" violates foreign key constraint "fk_rails_6bc98ede2c"
   DETAIL:  Key (user_id)=(0) is not present in table "users".
   : UPDATE "standard_accounts" SET "user_id" = $1, "updated_at" = $2 WHERE "standard_accounts"."id" = $3
 # ./spec/models/standard_account_spec.rb:9:in `block (2 levels) in <top (required)>'
 # ------------------
 # --- Caused by: ---
 # PG::ForeignKeyViolation:
 #   ERROR:  insert or update on table "standard_accounts" violates foreign key constraint "fk_rails_6bc98ede2c"
 #   DETAIL:  Key (user_id)=(0) is not present in table "users".

我想我可以编辑迁移并删除 foreign_key: true 位(这可能是在 structure.sql 中创建外键约束的原因),但这是由 Rails 默认生成器添加的,虽然我不完全是确定它的目的是什么,这里似乎还有其他问题,因为它应该按原样工作。

【问题讨论】:

  • 听起来可能是在抱怨,因为users 表中没有具有该ID 的用户,所以引用无效?如果您在测试中创建了一个用户,您会遇到同样的错误吗?
  • 是的,我确实遇到了同样的错误。
  • 你能分享这样做的代码吗?
  • @JakeShorty 我刚刚在测试的开头添加了setup { FactoryGirl.create(:user) } 来测试您的建议。
  • 在那之后是否还在尝试使用user_id0

标签: ruby-on-rails postgresql activerecord rspec


【解决方案1】:

解决这个问题的方法是在运行你的 shoulda 测试之前创建一个 StripeStandardAccount 对象的实例。例如:

  # Step 1
  # If you are using FactoryBot (note: you need to use "!" with your "let")
  let!(:stripe_standard_account) { create(:stripe_standard_account) }

  # If you're not using FactoryBot
  StripeStandardAccount.create(your-required-params-go-here)

  # Step 2
  # Then run your shoulda_matcher test
  it { should validate_uniqueness_of(:user_id) }

这是因为您的测试用例需要一个现有实例来与它正在创建的实例进行比较。您不能询问对象的单个实例是否是唯一的。 https://github.com/thoughtbot/shoulda-matchers/issues/682#issuecomment-78124438

【讨论】:

    【解决方案2】:

    原来这实际上是由于shoulda-matchers 库中的一个错误。我能够使用this approach 解决它。

    【讨论】:

      猜你喜欢
      • 2013-01-06
      • 1970-01-01
      • 1970-01-01
      • 2015-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-17
      相关资源
      最近更新 更多