Search code examples
ruby-on-railsfactory-botrspec-rails

File upload, factory_girl & database_cleaner


In my model, I have to choose an asset, saved in a editorial_asset table.

include ActionDispatch::TestProcess

FactoryGirl.define do
  factory :editorial_asset do
    editorial_asset { fixture_file_upload("#{Rails.root}/spec/fixtures/files/fakeUp.png", "image/png") }
  end
end

so I have attached in my model factory an association on :editorial_asset

Upload work great, but take too much time (1s per example)

I'm wonder if it's possible to create uploads one time before each examples, and say in the factory: "find instead of create"

But the problem with database_cleaner, I cannot except tables with :transaction, truncation take 25sec instead of 40ms !

EDIT

The factory that need an asset

FactoryGirl.define do
  factory :actu do
    sequence(:title) {|n| "Actu #{n}"}
    sequence(:subtitle) {|n| "Sous-sitre #{n}"}

    body Lipsum.paragraphs[3]

    # Associations
    user
    # editorial_asset
  end
end

The model spec

require 'spec_helper'

describe Actu do
  before(:all) do
    @asset = create(:editorial_asset)
  end

  after(:all) do
    EditorialAsset.destroy_all
  end

  it "has a valid factory" do
    create(:actu).should be_valid
  end

end

So a working way is

  it "has a valid factory" do
    create(:actu, editorial_asset: @asset).should be_valid
  end

but there's no way to inject automatically association ?


Solution

  • Since you're using RSpec, you could use a before(:all) block to set up these records once. However, anything done in a before-all block is NOT considered part of the transaction, so you will have to delete anything from the DB yourself in an after-all block.

    Your factory for the model that has an association to the editorial asset could then, yes, try to first find one before creating it. Instead of doing something like association :editorial_asset you could do:

    editorial_asset { EditorialAsset.first || Factory.create(:editorial_asset) }
    

    Your rspec tests could then look like this:

    before(:all) do
        @editorial = Factory.create :editorial_asset
    end
    
    after(:all) do
        EditorialAsset.destroy_all
    end
    
    it "already has an editorial asset." do
        model = Factory.create :model_with_editorial_asset
        model.editorial_asset.should == @editorial
    end
    

    Read more about before and after blocks on the Rspec GitHub wiki page or on the Relish documentation:

    https://github.com/rspec/rspec-rails

    https://www.relishapp.com/rspec