简体   繁体   中英

How to create multiple records with FactoryGirl? Currently images are applied only to first record

I am getting strange behavior from a spec/ factory. What am I doing wrong?

# feature spec 

feature 'avatars' do
  let(:user1) { create :user_with_profile, role: 1 }
  let(:user2) { create :user_with_profile, role: 2 }
  let(:user3) { create :user_with_profile, role: 3 }
  let(:user4) { create :user_with_profile, role: 4 } 

  scenario 'displays user avatars' do 
    expect(find("ul.users")).to_not have_selector "img.role1[title='#{user1.name}']"
    expect(find("ul.users")).to_not have_selector "img.role2[title='#{user2.name}']"
    expect(find("ul.users")).to_not have_selector "img.role3[title='#{user3.name}']"
    expect(find("ul.users")).to_not have_selector "img.role4[title='#{user4.name}']"
  end
end

# factory

FactoryGirl.define do
  factory :user do
    email { Faker::Internet.email }
    password Faker::Internet.password(10, 20)
    trait :name do
      name Faker::Name.name
    end
    # images are handled with Carrierwave
    trait :avatar do
      avatar { Rack::Test::UploadedFile.new(File.join(Rails.root, 'spec', 'support', 'images', 'test_image.jpg')) }
    end
    factory :user_with_profile, traits: [:name, :avatar]
  end
end 

# view
<ul class='users'>
  <% Users.all.each do |user| %>
    <%= content_tag :li, class: "user_#{user.id}" do %>
      <%= link_to user_path(user), title: user.name do %>
        <% if user.avatar? %>
          <%= image_tag user.avatar_url(:large), title: user.name, class: "role#{user.role}" %>
        <% else %>
          <%= content_tag :div, class: "role#{user.role}" do %>
            <%= user.initials %>
          <% end %>
        <% end %>
      <% end %>
    <% end %>
  <% end %>
</ul>

The test is failing:

Failure/Error: expect(find("ul.users")).to have_selector "img.role2[title='#{user2.name}']"
expected to find css "img.role2[title='Jakob John']" but there were no matches

I thought it odd that user1 was passing whereas user 2 was failing, so I got rspec to save_and_open_page .

<ul class="users">
  <li class="user_1">
    <a title="Jakob Johnson" href="/users/1">
      <img title="Jakob Johnson" class= 'role1' src="/avatars/users/1/large/0000000005_35594307d1.jpg">
    </a>
  </li>
  <li class="user_2">
    <a title="Jakob Johnson" href="/users/2">
      <div class='role2'>JJ</div>
    </a>
  </li>
  ## user3 and user4 also have divs not imgs
</ul>

Exactly the same code and factory is used for each user, so:

  1. Why has FactoryGirl created user1 with an avatar, and the other users without?
  2. Why has FactoryGirl created all users with the same name?

Am I using FactoryGirl incorrectly? I can't work out what I'm doing wrong, and any advice appreciated.

The reason FactoryGirl is creating all users with the same name is because the name value is being set when your factory is defined. To get around this you should use lazy attributes: https://github.com/thoughtbot/factory_girl/blob/master/GETTING_STARTED.md#lazy-attributes

to do this use parenthesis in your name trait as follows:

trait :name do
  name { Faker::Name.name }
end

this will mean that a new name is generated each time a new instance is created.

Unfortunately I can't see exactly what the problem is with your avatar. One thing you could try is fixture_file_upload and see if that helps.

To use this you need to add include ActionDispatch::TestProcess in your spec helper. Then try changing your avatar trait to:

trait :avatar do
  avatar { fixture_file_upload(Rails.root.join('spec', 'support', 'images', 'test_image.jpg'), 'image/jpg') }
end

I hope that helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM