Search code examples
ruby-on-railsfactory-bot

How can i create an object inside of other object?


I want to create a 'post' and a 'card', but to create an card its necessary have company_id

factory :post do
  first_title { Faker::Name.name }
  sub_title { Faker::Name.name }
  email { Faker::Internet.email }
  company_id {}
  card { FactoryBot.create(:card, company_id: company_id) }
end

But i am getting this error:

undefined local variable or method `company_id' for #<FactoryBot::SyntaxRunner:0x00007f629fb1b260

Solution

  • Ideally if your test needs to create a well defined ocntext for it self and not rely on the factories behaviour, so you should call the factories passing the associated objects as a param for each factory call.

    But if you really want to achieve this using the id you can use transient attributes.

    Using the card object:

    factory :company do
      # whatever you need here
    end
    
    factory :card do
      company
    end
    
    factory :post do
      first_title { Faker::Name.name }
      sub_title { Faker::Name.name }
      email { Faker::Internet.email }
      card
    end
    
    let(:company) { FactoryBot.create :company }
    let(:card) { FactoryBot.create(:card, company: company) }
    let!(:post) { FactoryBot.create(:post, card: card) }
    

    Using the transient attribute:

    # factory:
    factory :post do
      first_title { Faker::Name.name }
      sub_title { Faker::Name.name }
      email { Faker::Internet.email }
    
      transient do
        company_id { FactoryBot.create(:company).id }
      end
    
      after(:build) do |post, evaluator|
        card = FactoryBot.create(:card, company_id: evaluator.company_id)
        post.card = card
      end
    end
    # spec:
    let(:company) { FactoryBot.create :company }
    let!(:post) { FactoryBot.create(:post, company_id: company.id) }
    

    Update: I have added a code for the factories in the first example