'How can I create class “Item” before the class “Transaction” exist, with FactoryBot?

I was wondering if anyone can help. I am receiving an error message in the terminal saying Validation failed: Item must exist. I think that happens because FactoryBot is trying to create a Transaction class before the Item class, I think, I have to find a way to make the Item exist first before the Transaction, I tried many different ways, but had no success so far. optional: true is not an option, appreciate any help. ps: this is my first time I am asking a help in StackOverflow so apologies if something is not right in my post.

Down below you can find 3 files, if you want to see other files let me know.

require "test_helper"

class PurchasesControllerTest < ActionDispatch::IntegrationTest
  describe "#index" do
    let(:user_id) { Faker::Internet.uuid }
    let(:payload) { { user_id:, account_number: 1 } }
    let(:purchase_count) { 3 }

    before do
      WebMock.stub_request(:get, "#{ENV['IDENTITY_SERVICE_URL']}/users/#{user_id}")
             .to_return(status: 200, body: user_response(user_id:), headers: jsonapi_headers)         

      create(:as_asset)
      purchase_count.times do
        create(:purchase, user_id: 1)
      end
    end
    it "returns successful response" do
      get purchases_url, headers: authorization_header(payload)
      assert_response :success
      assert_match(/"total":#{purchase_count}/, response.body)
    end

    context "when unauthorized" do
      it "returns unauthorized response" do
        get purchases_url
        assert_response :unauthorized
      end
    end
  end
end

FactoryBot.define do
  factory :purchase do
    user_id { Faker::Internet.uuid }
    for_as_asset

    trait :for_gasset do
      association :item, factory: :gasset
    end

    trait :for_as_asset do
      association :item, factory: :as_asset
    end

    after(:create) do |object|
      create(:transaction, purchase_id: object.id, purchase_type: "Purchase")
    end
  end
end

FactoryBot.define do
  factory :transaction do
    item_id { 4 }
    item_type { "AsAsset" }
    user_id { Faker::Internet.uuid }
    purchase_ref { "Purchase reference" }
  end
end


Solution 1:[1]

The answer to my question:

Added item_id: object.item_id, item_type: object.item_type inside the block statement of purchase factory.

FactoryBot.define do
  factory :purchase do
    for_gasset
    after(:create) do |object|
      create(:transaction, user_id: object.user_id, item_id: object.item_id, item_type: object.item_type, purchase_id: object.id, purchase_type: "Purchase")
    end

    trait :for_gasset do
      association :item, factory: :gasset
    end

    trait :for_as_asset do
      association :item, factory: :as_asset
    end

    user_id { Faker::Internet.uuid }
  end
end

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Homeless Viktor