I'm running into a problem with Minitest and fixtures for associated ActiveRecord models (Rails. 4.2.3).
Here are the two models:
# vanguard_fund.rb
class VanguardFund < ActiveRecord::Base
belongs_to :benchmark_fund
...
end
# benchmark_fund.rb
class BenchmarkFund < ActiveRecord::Base
has_many :vanguard_funds
end
Pretty straight-forward. Now here are the fixtures:
# vanguard_funds.yml
vf1:
name: Vanguard Fund 1
benchmark_fund: bm1
# benchmark_funds.yml
bm1:
name: Benchmark Fund 1
Now I'm getting the following error when running any tests:
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'
There is a benchmark fund ID (479852872) but it seems like that record isn't found in the BenchmarkFunds table when the VanguardFund is created??
Any advice?
I believe that Rails tries to disable referential integrity checks before loading fixtures. If your PostgreSQL user is not a superuser, then this fails silently, and subsequently the fixture loading will fail with the ActiveRecord::InvalidForeignKey
errors you are seeing.
The fix is to make your PostgreSQL user a superuser. Connect to PostgreSQL with a privileged account and then issue an ALTER USER ... WITH SUPERUSER
command.
On Ubuntu, I did it like this:
su -l postgres -c "psql -c 'alter user jenkins with superuser;'"
Where jenkins
in this case was the user that was failing to run the Rails tests. This fixed the problem for me.
There is an explanation of this in the edge version of the Rails testing guide (emphasis added):
In order to remove existing data from the database, Rails tries to disable referential integrity triggers (like foreign keys and check constraints). If you are getting annoying permission errors on running tests, make sure the database user has privilege to disable these triggers in testing environment. (In PostgreSQL, only superusers can disable all triggers. Read more about PostgreSQL permissions here).