Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Composite PKs break fixture loading for many-to-many associations #51461

Open
fragkakis opened this issue Apr 1, 2024 · 2 comments · May be fixed by #51462
Open

Composite PKs break fixture loading for many-to-many associations #51461

fragkakis opened this issue Apr 1, 2024 · 2 comments · May be fixed by #51462

Comments

@fragkakis
Copy link

Steps to reproduce

Copy the following fixture files in a directory:

posts.yml

one:
    title: "My first post"
    account_id: 1
    labels: one, two

labels.yml

one:
    text: "Label 1"
two:
    text: "Label 2"

and use them here:

# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  git_source(:github) { |repo| "https://github.com/#{repo}.git" }

  gem "rails"
  # If you want to test against edge Rails replace the previous line with this:
  # gem "rails", github: "rails/rails", branch: "main"

  gem "sqlite3"
end

require "active_record"
require "minitest/autorun"
require "logger"

# This connection will do for database-independent bug reports.
ActiveRecord::Base.establish_connection(adapter: "sqlite3", database: ":memory:")
ActiveRecord::Base.logger = Logger.new(STDOUT)

ActiveRecord::Schema.define do

  create_table :posts, force: true, primary_key: %i[id account_id] do |t|
    t.integer :id
    t.integer :account_id
    t.string :title
  end

  create_table :posts_labels, force: true do |t|
    t.integer :post_id
    t.integer :account_id
    t.references :label, foreign_key: true
  end

  create_table :labels, force: true do |t|
    t.string :text
  end
end

class Post < ActiveRecord::Base
  self.primary_key = %i[id account_id]
  has_many :posts_labels
  has_many :labels, through: :posts_labels
end

class PostsLabel < ActiveRecord::Base
  belongs_to :post, query_constraints: [:post_id, :account_id]
  belongs_to :label
end

class Label < ActiveRecord::Base
  has_many :posts_labels
  has_many :posts, through: :posts_labels
end

# Load the fixtures into the database (update the directory)
ActiveRecord::FixtureSet.create_fixtures("/fixtures-directory/", %w[posts labels])

class BugTest < Minitest::Test
  def test_association_stuff
    assert_equal 1, Post.count
    assert_equal 2, Label.count
    assert_equal 2, Post.first.labels.count # Fails here
  end
end

Expected behavior

According to the documentation of ActiveRecord::FixtureSet, the fixture for the intermediate many-to-many table can be skipped.

Actual behavior

The fixtures are not loaded correctly. These are the sql statements for the fixtures (notice the null):

DELETE FROM "posts";
DELETE FROM "posts_labels";
DELETE FROM "labels";
INSERT INTO "posts" ("id", "account_id", "title") VALUES (980190962, 1, 'My first post');
INSERT INTO "posts_labels" ("post_id", "label_id") VALUES (NULL, 980190962);
INSERT INTO "posts_labels" ("post_id", "label_id") VALUES (NULL, 298486374);
INSERT INTO "labels" ("id", "text") VALUES (980190962, 'Label 1');
INSERT INTO "labels" ("id", "text") VALUES (298486374, 'Label 2')

System configuration

Rails version: 7.1.3.2

Ruby version: 3.2.2

@fatkodima
Copy link
Member

fatkodima commented Apr 2, 2024

@fragkakis Can you verify that the linked PR solves your issue?

You also need to change has_many :posts_labels to has_many :posts_labels, query_constraints: [:post_id, :account_id].

@fragkakis
Copy link
Author

Hello @fatkodima, thank you for the PR.

I confirm it solves the issue ✅.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants