如何使用Factory Girl生成一个Paperclip附件?

120

我有一个名为“Person”的模型,其中包含许多Image对象,每个Image对象都有一个Paperclip附件字段称为“data”,下面是缩写版本:

class Person
  has_many :images
  ...
end

class Image
  has_attached_file :data
  belongs_to :person
  ...
end

每个人都必须至少附加一张图片。

当使用FactoryGirl时,我有类似以下代码:

Factory.define :image do |a|
  a.data { File.new(File.join(Rails.root, 'features', 'support', 'file.png')) }
  a.association :person
end

Factory.define :person do |p|
  p.first_name 'Keyzer'
  p.last_name 'Soze'
  p.after_create do |person|
    person.assets = [Factory.build(:image, :person => person)]
  end
  # p.images {|images| [images.association(:image)]}
end

(注意:我也尝试了上面注释掉的代码)

大多数情况下,当我运行Cucumber特性时,我会遇到类似于以下的错误:

没有这样的文件或目录-/tmp/stream,9887,0.png(Errno::ENOENT)

...

有时测试可以成功运行。

有人能告诉我这里出了什么问题,或者他们如何一起使用FactoryGirl和Paperclip来实现类似我所尝试的东西吗?

我正在使用Rails 3。


2
仅因使用Keyzer Soze作为您的测试名称而对问题进行点赞! - Breno
当我这样做时...每次运行测试套件时,照片都会生成并放置在public/system文件夹中。这些照片在测试套件运行完毕后不会被销毁。还有其他人注意到这一点吗? - Jwan622
8个回答

90

你可以使用fixture_file_upload

在测试助手中添加include ActionDispatch::TestProcess,这里是一个示例工厂:

include ActionDispatch::TestProcess

FactoryBot.define do
  factory :user do
    avatar { fixture_file_upload(Rails.root.join('spec', 'photos', 'test.png'), 'image/png') }
  end
end
在上面的例子中,在运行测试之前,spec/photos/test.png需要存在于应用程序的根目录中。
请注意,FactoryBotFactoryGirl的新名称。

2
这个答案是完全正确的,但更清晰的说法可能是TestProcess包含需要与工厂一起包含,而不仅仅是在spec_helper中。 - Andrew Hubbs
2
感谢澄清,安德鲁。您可能还需要在 FactoryGirl.define 块之前放置 "include ActionDispatch::TestProcess"(这不是此 gist 中发生的情况:https://gist.github.com/313121)。 - Sam
4
需要加上 { },否则会出现错误。 - bigpotato
3
进一步说明:include ActionDispatch::TestProcess 应该插入到工厂文件的最顶部, FactoryGirl.define do...end 块之外。 - Frank Koehl

50

新的FG语法,无需包含任何内容

factory :user do
  avatar { File.new(Rails.root.join('app', 'assets', 'images', 'rails.png')) }
end

或者,更好的是。

factory :user do
  avatar { File.new("#{Rails.root}/spec/support/fixtures/image.jpg") } 
end

2
我喜欢它,但请记住Rails 4会删除app/assets/images/rails.png。所以您需要考虑这个变化 :) - stephenmurdoch

39

Pivotal Labs的Desmond Bowe建议避免使用fixture_file_upload,因为会导致内存泄漏问题。相反地,你应该在工厂中直接设置paperclip字段:

factory :attachment do
  supporting_documentation_file_name { 'test.pdf' }
  supporting_documentation_content_type { 'application/pdf' }
  supporting_documentation_file_size { 1024 }
  # ...
end

对我来说可以工作。而且足够简单,不需要在spec/test文件夹中存在现有文件。 - Bibek Shrestha
2
除了避免内存泄漏,这种方式还可以使测试更快。 - evedovelli
所提到的博客文章已移至pivotal.io/blog - Karsten S.
很遗憾,这不能与“content_type”上的附件验证一起使用。为此,您需要一个有效的文件对象。 - Karsten S.

25

1
只是想知道同样的事情,这个方法非常好用。谢谢。我把它放在了初始化器里。 - Todd
1
需要注意的是:上面的主旨使用了旧的FactoryGirl语法。DanS的答案使用了新的语法。 - Andrew Hubbs

14
file { File.new(Rails.root.join('spec', 'fixtures', 'filename.png')) }

这是最简单的功能性解决方案。 - superluminary

4

尝试使用ActionController :: TestUploadedFile。 您只需将文件属性设置为TestUploadedFile的实例,paperclip应该会处理其余部分。 例如

valid_file = File.new(File.join(Rails.root, 'features', 'support', 'file.png'))  
p.images { 
   [
     ActionController::TestUploadedFile.new(valid_file, Mime::Type.new('application/png'))
   ] 
}

0

以上的回答在某些情况下可能有所帮助,实际上其中一个回答在我的某个情况下确实有所帮助,但是当使用Carrierwave时,这个问题之前的解决方案这次并没有奏效。

第一种方法:

对我来说,添加after :create就像这样解决了我的问题:

after :create do |b|
  b.update_column(:video_file, File.join(Rails.root, 'spec', 'fixtures', 'sample.mp4'))
end

设置内联视频文件,例如video_file { File.new("#{Rails.root}/spec/fixtures/sample.mp4") }并没有成功,而且报告了错误。

第二种方法:

定义一个工厂,像这样(将personal_file更改为您的附件名称):

FactoryGirl.define do
  factory :contact do
    personal_file { File.new("#{Rails.root}/spec/fixtures/personal_files/my_test_file.csv") }
    personal_file_content_type 'text/csv'

  end
end

并将以下行添加到 config/environments/test.rb 文件中:

config.paperclip_defaults = {
  url: "#{Rails.root}/spec/fixtures/:attachment/:filename",
  use_timestamp: false
}

-1
你到底在测试什么?是那个纸夹能够成功地附加文件吗?这似乎是纸夹应该处理的测试,而不是你的应用程序。
你试过了吗?
a.data { File.join(Rails.root, 'features', 'support', 'file.png') }

我们使用 Machinist 而不是 factory_girl,只是用了一些类似的东西。
Image.blueprint do
  image { RAILS_ROOT + 'spec/fixtures/images/001.jpg' }
end

虽然这样做时我们并没有进行太多的测试,但通常我们只是想获得一个有效的Image对象。


我有一些模型,需要与启用Paperclip的模型建立有效关联,本身具有有效附件。 - Eric

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接