Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

FactoryGirl::AttributeDefinitionError: Attribute already defined: user

I created factory client and contract. I run test, but display error

FactoryGirl.define do
  factory :client, class: User do
    role 'client'
    first_name 'John'
    sequence(:last_name) {  |n| "client#{n}" }
    sequence(:email) { |n| "client#{n}@example.com" }
    # avatar { Rack::Test::UploadedFile.new(File.join(Rails.root, 'public', 'images', '128.jpg')) }
    password 'password'
    password_confirmation 'password'
  end
end

support/controller_macros.rb

module ControllerMacros
  def login_client
    before do
      @client = create(:client)
      #@request.env['devise.mapping'] = Devise.mappings[:client]
      sign_in @client
    end
  end
end

FactoryGirl.define do
  factory :contract do
    sequence(:title) { |n| "translation#{n}" }
    amount 150
    additional_information 'X' * 500
    due_date { 21.days.from_now }

    association :user, factory: :client
    association :user, factory: :contractor
  end
end

I run test rspec spec/controllers/contracts_controller_spec.rb

require 'rails_helper'

describe ContractsController do
  login_client
  let(:contract) { create(:contract) }

  describe 'POST #create' do

    context 'with valid attributes' do
      it 'redirects to payment page' do
        post :create, contract: attributes_for(:contract)
        expect(response).to redirect_to payment_new_path
      end
    end
  end
end

Error display:

Failure/Error: post :create, contract: attributes_for(:contract)
  FactoryGirl::AttributeDefinitionError:
    Attribute already defined: user

What is wrong in factory or test?

like image 393
Dmitrij Avatar asked Oct 15 '25 22:10

Dmitrij


1 Answers

Factory :contract defines two attributes named user, which isn't allowed.

Give them unique (within the factory) labels, e.g.:

FactoryGirl.define do
  factory :contract do
    sequence(:title) { |n| "translation#{n}" }
    amount 150
    additional_information 'X' * 500
    due_date { 21.days.from_now }

    association :client, factory: :client
    association :contractor, factory: :contractor
  end
end

As they seem fitting, I've chosen attribute names corresponding with the factory names. This allows to even shorten this, by leaving out the factory name:

FactoryGirl.define do
  factory :contract do
    sequence(:title) { |n| "translation#{n}" }
    amount 150
    additional_information 'X' * 500
    due_date { 21.days.from_now }

    client
    contractor
  end
end

(See http://www.rubydoc.info/gems/factory_girl/file/GETTING_STARTED.md, section "Associations":

If the factory name is the same as the association name, the factory name can be left out.

)

like image 58
das-g Avatar answered Oct 17 '25 11:10

das-g