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

Associations in traits persists multiple times #91

Open
S1azZy opened this issue Jul 22, 2024 · 2 comments
Open

Associations in traits persists multiple times #91

S1azZy opened this issue Jul 22, 2024 · 2 comments

Comments

@S1azZy
Copy link

S1azZy commented Jul 22, 2024

Describe the bug

If you make a belongs_to association inside trait, it will be created 2 times. This causes an error if there is a uniqueness check.
I have written a test for an example.

On version 0.10.2 it works correct.

To Reproduce

# frozen_string_literal: true

RSpec.describe ROM::Factory do
  include_context "database"

  subject(:factories) do
    ROM::Factory.configure do |config|
      config.rom = rom
    end
  end

  before do
    conn.create_table?(:book_types) do
      primary_key :id
      column :type, String, null: false

      index :type, unique: true
    end

    conn.create_table?(:books) do
      primary_key :id
      foreign_key :book_type_id, :book_types, index: true
    end

    conf.relation(:book_types) do
      schema(infer: true) do
        associations do
          has_many :books
        end
      end
    end

    conf.relation(:books) do
      schema(infer: true) do
        associations do
          belongs_to :book_type
        end
      end
    end

    rom.gateways[:default].use_logger(Logger.new($stdout))
  end

  context "trait with associations" do
    it "creates book type only once" do
      factories.define(:book) do |f|
        f.trait :with_type do |t|
          t.association(:book_type)
        end
      end

      factories.define(:book_type) do |f|
        f.type { "NOT_UNIQUE" }
      end

      factories[:book, :with_type]
      expect(rom.relations[:book_types].count).to eq(1)
    end
  end

  after do
    conn.drop_table?(:books)
    conn.drop_table?(:book_types)
  end
end

And the error

I, [2024-07-22T16:45:11.954139 #19499]  INFO -- : (0.002133s) INSERT INTO "book_types" ("type") VALUES ('NOT_UNIQUE') RETURNING "book_types"."id", "book_types"."type"
E, [2024-07-22T16:45:11.955342 #19499] ERROR -- : PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "book_types_type_index"
DETAILS:  Key (type)=(NOT_UNIQUE) already exists.: INSERT INTO "book_types" ("type") VALUES ('NOT_UNIQUE') RETURNING "book_types"."id", "book_types"."type"
I, [2024-07-22T16:45:11.964446 #19499]  INFO -- : (0.008830s) DROP TABLE IF EXISTS "books"
I, [2024-07-22T16:45:11.970889 #19499]  INFO -- : (0.006384s) DROP TABLE IF EXISTS "book_types"
F

Failures:

  1) ROM::Factory trait with associations creates book type only once
     Failure/Error:
       result = relation
         .with(auto_struct: !tuple_evaluator.has_associations?)
         .command(:create)
         .call(attrs)

     ROM::SQL::UniqueConstraintError:
       PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "book_types_type_index"
       DETAILS:  Key (type)=(NOT_UNIQUE) already exists.
     # ./lib/rom/factory/builder/persistable.rb:48:in `persist'
     # ./lib/rom/factory/builder/persistable.rb:28:in `create'
     # ./lib/rom/factory/attributes/association.rb:82:in `call'
     # ./lib/rom/factory/tuple_evaluator.rb:186:in `block in evaluate_associations'
     # ./lib/rom/factory/attribute_registry.rb:22:in `each'
     # ./lib/rom/factory/attribute_registry.rb:22:in `each'
     # ./lib/rom/factory/tuple_evaluator.rb:178:in `each_with_object'
     # ./lib/rom/factory/tuple_evaluator.rb:178:in `evaluate_associations'
     # ./lib/rom/factory/tuple_evaluator.rb:149:in `evaluate'
     # ./lib/rom/factory/tuple_evaluator.rb:59:in `defaults'
     # ./lib/rom/factory/tuple_evaluator.rb:173:in `evaluate_traits'
     # ./lib/rom/factory/tuple_evaluator.rb:150:in `evaluate'
     # ./lib/rom/factory/tuple_evaluator.rb:59:in `defaults'
     # ./lib/rom/factory/builder.rb:37:in `tuple'
     # ./lib/rom/factory/builder/persistable.rb:27:in `create'
     # ./lib/rom/factory/factories.rb:171:in `[]'
     # ./spec/integration/rom/association_trait_spec.rb:56:in `block (3 levels) in <top (required)>'
     # ------------------
     # --- Caused by: ---
     # PG::UniqueViolation:
     #   ERROR:  duplicate key value violates unique constraint "book_types_type_index"
     #   DETAILS:  Key (type)=(NOT_UNIQUE) already exists.
     #   ./lib/rom/factory/builder/persistable.rb:48:in `persist'
     ```

## Expected behavior

Associations in traits should be created only 1 time.

## My environment

- Affects my production application: YES
- Ruby version: 3.2.2
- OS: MacOS 14.5 (Sonoma)
@solnic
Copy link
Member

solnic commented Aug 3, 2024

Thanks for reporting this! I'll look into it.

@madleech
Copy link

Any progress on this? I'm running into the same issue. It seems to be creating the association once when calling evaluate_associations and then again when calling evaluate_traits.

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

No branches or pull requests

3 participants