Minitest:关联AR模型的装置导致ActiveRecord :: InvalidForeignKey:运行测试时的PG :: ForeignKeyViolation

时间:2015-09-04 17:00:25

标签: ruby-on-rails ruby postgresql fixtures minitest

我遇到Minitest和相关ActiveRecord模型灯具的问题(Rails.4.2.3)。

以下是两种模式:

# vanguard_fund.rb
class VanguardFund < ActiveRecord::Base
  belongs_to :benchmark_fund
  ...
end

# benchmark_fund.rb
class BenchmarkFund < ActiveRecord::Base
  has_many :vanguard_funds
end

非常直截了当。现在这里是灯具:

# vanguard_funds.yml
vf1:
  name: Vanguard Fund 1
  benchmark_fund: bm1

# benchmark_funds.yml    
bm1:
  name: Benchmark Fund 1

现在我在运行任何测试时遇到以下错误:

ERROR["test_#name_returns_the_name_of_the_VanguardFund", BaseTest, 2015-06-08 13:39:28 +0000]
 test_#name_returns_the_name_of_the_VanguardFund#BaseTest (1433770768.22s)
ActiveRecord::InvalidForeignKey:         ActiveRecord::InvalidForeignKey: PG::ForeignKeyViolation: ERROR:  insert or update on table "vanguard_funds" violates foreign key constraint "fk_rails_994ab6fe75"
        DETAIL:  Key (benchmark_fund_id)=(479852872) is not present in table "benchmark_funds".
        : INSERT INTO "vanguard_funds" ("name", "created_at", "updated_at", "id", "benchmark_fund_id") VALUES ('Vanguard Fund 1', '2015-09-04 16:48:23', '2015-09-04 16:48:23', 263706224, 479852872)
            test_after_commit (0.4.1) lib/test_after_commit.rb:15:in `block in transaction_with_transactional_fixtures'
            test_after_commit (0.4.1) lib/test_after_commit.rb:9:in `transaction_with_transactional_fixtures'

一个基准资金ID(479852872),但在创建VanguardFund时,似乎在BenchmarkFunds表中找不到记录?

有什么建议吗?

1 个答案:

答案 0 :(得分:7)

我相信Rails会在加载灯具之前尝试禁用参照完整性检查。如果您的PostgreSQL用户不是超级用户,那么这将无声地失败,随后夹具加载将因您看到的ActiveRecord::InvalidForeignKey错误而失败。

修复方法是让您的PostgreSQL用户成为超级用户。使用特权帐户连接到PostgreSQL,然后发出ALTER USER ... WITH SUPERUSER命令。

在Ubuntu上,我这样做了:

su -l postgres -c "psql -c 'alter user jenkins with superuser;'"

在这种情况下,jenkins是无法运行Rails测试的用户。这解决了我的问题。

edge version of the Rails testing guide(强调补充)中有一个解释:

  

为了从数据库中删除现有数据,Rails尝试禁用参照完整性触发器(如外键和检查约束)。如果在运行测试时遇到恼人的权限错误,请确保数据库用户有权在测试环境中禁用这些触发器。 (在PostgreSQL中,只有超级用户可以禁用所有触发器。了解有关PostgreSQL权限的更多信息here)。