Home > Software engineering >  Foreign key violations found in your fixture data. Ensure you aren't referring to labels that d
Foreign key violations found in your fixture data. Ensure you aren't referring to labels that d

Time:07-07

I run a single test with

rake test TEST=test/system/my_test.rb

and see this:

rake test TEST=test/system/my_test.rb
Running 1 tests in a single process (parallelization threshold is 50)
Run options: --seed 48133

# Running:

E

Error:
myTest#test_visiting_the_index:
RuntimeError: Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations.
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.2.4/lib/active_record/fixtures.rb:633:in `block in insert'
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.2.4/lib/active_record/fixtures.rb:621:in `each'
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.2.4/lib/active_record/fixtures.rb:621:in `insert'
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.2.4/lib/active_record/fixtures.rb:607:in `read_and_insert'
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.2.4/lib/active_record/fixtures.rb:567:in `create_fixtures'
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.2.4/lib/active_record/test_fixtures.rb:268:in `load_fixtures'
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.2.4/lib/active_record/test_fixtures.rb:122:in `setup_fixtures'
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activerecord-7.0.2.4/lib/active_record/test_fixtures.rb:10:in `before_setup'
    /Users/st/.rbenv/versions/3.0.3/lib/ruby/gems/3.0.0/gems/activesupport-7.0.2.4/lib/active_support/testing/setup_and_teardown.rb:40:in `before_setup'


rails test test/system/my_test.rb:12



Finished in 0.190845s, 5.2399 runs/s, 0.0000 assertions/s.
1 runs, 0 assertions, 0 failures, 1 errors, 0 skips

The critical part being:

Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations.

Is there any way to narrow down which fixture(s) the error is emanating from?

What I've tried

  • I tried to see if I can load a single fixture at a time in the rails console, that way I could figure out which is causing it (but no luck doing that)
  • I see a similar conversation here.

CodePudding user response:

If you're using postgres, check the database logs:

ERROR:  insert or update on table "friendships" violates foreign key constraint "fk_rails_e3733b59b7"
DETAIL:  Key (user_id)=(999) is not present in table "users".

You can check the integrity yourself as well. You'll get an error from fixtures, but the records should stay in the database. Reset to make sure there are no leftovers.

RAILS_ENV=test bin/rails db:reset
RAILS_ENV=test bin/rails db:fixtures:load
RAILS_ENV=test bin/rails c 

Run this in the console, you should get the same error as the log above.

ActiveRecord::Base.connection.execute(<<~SQL)
  do $$
    declare r record;
  BEGIN
  FOR r IN (
    SELECT FORMAT(
      'UPDATE pg_constraint SET convalidated=false WHERE conname = ''%I''; ALTER TABLE %I VALIDATE CONSTRAINT %I;',
      constraint_name,
      table_name,
      constraint_name
    ) AS constraint_check
    FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'
  )
    LOOP
      EXECUTE (r.constraint_check);
    END LOOP;
  END;
  $$;
SQL


# =>
# PG::ForeignKeyViolation: ERROR:  insert or update on table "friendships" violates foreign key constraint "fk_rails_e3733b59b7" (ActiveRecord::InvalidForeignKey)
# DETAIL:  Key (user_id)=(999) is not present in table "users".

https://github.com/rails/rails/blob/v7.0.3/activerecord/lib/active_record/connection_adapters/postgresql/referential_integrity.rb#L41


For sqlite3, run this in the console instead:

ActiveRecord::Base.connection.execute("PRAGMA foreign_key_check")

# => [{"table"=>"friendships", "rowid"=>1, "parent"=>"users", "fkid"=>0}]

https://github.com/rails/rails/blob/v7.0.3/activerecord/lib/active_record/connection_adapters/sqlite3_adapter.rb#L214

CodePudding user response:

Since I had a lot of fixtures, I went through every fixture and ensured that when it was referencing a fixture, that that fixture being referenced actually existed. Why? For some unrelated reasons, some of my fixtures were referencing other fixtures which didn't exist.

Small example, suppose comments belongs_to a post this will work:

# Posts fixture
one:
  title: MyString
  content: MyText

# Comment fixture
one: 
  comment_content: MyString
  post: one

but this will give the error in the question:

# Posts fixture
one:
  title: MyString
  content: MyText

# Comment fixture
one: 
  comment_content: MyString
  post: somethingrandom

So you have to make sure your 'belongs to' fixtures are pointing to things that actually exist (in the above example, somethingrandom, doesn't exist, so it will give the error).

A small example to better understand the problem

I found it extremely helpful to make a minimal reproducible app as an example, but doing the following:

rails new testapp
cd testapp
rails g scaffold posts title content:text 
rails g scaffold comment comment_content:text post:belongs_to
# Add this to post.rb: has_many :comments, dependent: :destroy
rake db:migrate

At this point rails test should succeed and posts.yml should look like this:

one:
  title: MyString
  content: MyText

two:
  title: MyString
  content: MyText

and comments.yml like this:

one:
  comment_content: MyText
  post: one

two:
  comment_content: MyText
  post: two

Now you can fiddle with the fixtures to reproduce various errors. Suppose we go into comments.yml and change the name of the post that the comment 'one' belongs to:

posts.yml:

one:
  title: MyString
  content: MyText

two:
  title: MyString
  content: MyText

and comments.yml like this:

one:
  comment_content: MyText
  post: one

two:
  comment_content: MyText
  post: twwo # <-- typo!

With the typo, now when we run the tests rake test, we get the error:

RuntimeError: Foreign key violations found in your fixture data. 
Ensure you aren't referring to labels that don't exist on associations.

Related problem

Technically a different problem, but if you leave out the item that a fixture belongs to, you will get

Error:
PostsControllerTest#test_should_create_post:
ActiveRecord::NotNullViolation: PG::NotNullViolation: 
ERROR:  null value in column "post_id" violates not-null constraint

(try leaving out post: one in the above example`).

To address that, systematically work through all model files (and their corresponding fixture files) and ensure every belongs_to association is satisfied:

  • Open the first model file in your app
  • Open the corresponding fixtures file in your app
  • Check that the every belongs_to in the model file has a corresponding item in the fixture.
    • E.g. if a book belongs_to :author, then the book fixture must have author: one (where 'one' is the name of a fixture in the author fixtures).
  • Repeat for each model file in the app.
  • Related