Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test file upload with factorygirl?

I want to test a model with a basic file upload which does not use a plugin (I think it was a bad idea at the time but know I have to deal with tons of existing documents).

The thing is that I want to test the size of the uploaded file, so I need to access to the temfile attribute of file which is a ActionDispatch::Http::UploadedFile

It works quite well in my controllers but I can't find how to make my factory pass.

Attachment Model:

attr_accessor :file # file_field_tag name
attr_accessible :file, :filename # store the filename in the db

before_save :upload_file

def upload_file
  if self.file && File.size(self.file.tempfile) < 10.megabytes
    puts self.file.class.inspect # see below
    File.open("#{Rails.root.to_s}/files/" + self.filename.to_s, 'wb') do |f|
      f.write(self.file.read)
    end
    ensure_file_presence
  end
end

FactoryGirl Attachment:

FactoryGirl.define do
  factory :attachment do
    filename 'anyfile.txt'
    file ActionDispatch::Http::UploadedFile.new(:tempfile => "#{Rails.root}/spec/fixtures/anyfile.txt", :filename => "anyfile.txt")
  end
end

When I run tests, a FactoryGirl.build :attachment will succeed but with a create will fail.

Strange observation: I've displayed the self.file class before the File.open and it is seen as a ActionDispatch::Http::UploadedFile, then I have an error on self.file.read: it has changed into a String.

puts self.file.class.inspect
=> ActionDispatch::Http::UploadedFile

f.write(self.file.read) => NoMethodError: undefined method `read' for #<String:0x007ff50f70f6a0>

I've read other posts that suggest I should use Rack::Test::UploadedFile or fixture_file_upload but I can't make it work, as the tempfile won't exists of any of these 2 solutions.

like image 844
Jérémie Avatar asked Nov 15 '13 18:11

Jérémie


1 Answers

I see one issue. UpLoadedFile (:tempfile) is expecting a File not a String. For you observation, it never changed into a String you defined it as a String. You need to surround it with a File.new() as shown below. You need to put the file there before you try to run the test. Hope this helps!

FactoryGirl.define do
  factory :attachment do
    file ActionDispatch::Http::UploadedFile.new(:tempfile => File.new("#{Rails.root}/spec/fixtures/anyfile.txt"), :filename => "anyfile.txt")
  end
end
like image 197
Richard Avatar answered Sep 20 '22 17:09

Richard