2010-07-20 15 views
117

J'ai personne modèle qui a de nombreuses images, où les images ont un champ de saisie des données Paperclip appelé, une version abrégée affichée ci-dessous:Comment utiliser Factory Girl pour générer un accessoire Paperclip?

class Person 
    has_many :images 
    ... 
end 

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

personne doit avoir au moins une image attachée.

Lorsque vous utilisez factorygirl, j'ai le code semblable à ce qui suit:

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 

(NB J'ai également essayé le code commenté ci-dessus a également été essayé) La plupart du temps quand je lance des fonctionnalités de concombre, je obtenir une erreur semblable à ce qui suit:

Aucun fichier ou répertoire - /tmp/stream,9887,0.png (Errno :: ENOENT)

...

Parfois, les tests s'exécutent avec succès. Est-ce que quelqu'un peut me dire quel est le problème que j'ai ici ou comment ils utilisent ensemble FactoryGirl et Paperclip pour réaliser quelque chose comme ce que j'essaye d'accomplir?

J'utilise Rails 3.

+2

Up vote en question juste pour l'utilisation de Keyzer Soze comme nom de test! – Breno

+0

Ce que @Breno a dit ... –

+0

Quand je fais cela ... les photos sont générées et placées dans le dossier public/système chaque fois que je lance la suite de tests. Les photos ne sont pas détruites après l'exécution de la suite de tests. Est-ce que quelqu'un d'autre remarque cela? – Jwan622

Répondre

4

Essayez d'utiliser ActionController :: TestUploadedFile. Vous pouvez simplement définir la propriété du fichier à une instance de TestUploadedFile et paperclip devrait prendre soin du reste. Par exemple

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

Que testez-vous exactement? Ce trombone va joindre le fichier avec succès? Cela ressemble vraiment à un test que paperclip devrait gérer, pas à votre application.

Avez-vous essayé

a.data { File.join(Rails.root, 'features', 'support', 'file.png') } 

Nous utilisons Machiniste au lieu de factory_girl et vient utilisé des choses comme

Image.blueprint do 
    image { RAILS_ROOT + 'spec/fixtures/images/001.jpg' } 
end 

Bien, nous ne sommes pas vraiment tester beaucoup quand nous faisons cela, nous généralement juste voulez avoir un objet Image valide.

+0

J'ai des modèles qui nécessitent une association valide avec un modèle compatible Paperclip, lui-même avec une pièce jointe valide. – Eric

25

J'utilise le code dans l'essentiel ci-dessous:

Rails 2

http://gist.github.com/162881

Rails 3

https://gist.github.com/313121

+1

Je me demandais juste les mêmes choses et cela fonctionne magnifiquement. Merci. Je l'ai mis dans un initialiseur. – Todd

+3

Vous avez une erreur 'stack_level_too_deep' avec l'extrait Rails 3. – dhulihan

+1

Chose à noter: L'essentiel ci-dessus utilise l'ancienne syntaxe FactoryGirl. DanS answer utilise la nouvelle syntaxe. –

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

C'est la solution fonctionnelle la plus simple. – superluminary

82

Vous pouvez utiliser fixture_file_upload

include ActionDispatch::TestProcess dans votre aide de test, voici une usine exemple:

factory :user do 
    avatar { fixture_file_upload(Rails.root.join('spec', 'photos', 'test.png'), 'image/png') } 
end 

Dans l'exemple ci-dessus, spec/photos/test.png doit existe dans votre répertoire racine des applications avant d'exécuter vos tests.

+2

Cette réponse est tout à fait correcte mais il peut être plus clair de dire que l'inclusion de TestProcess doit être incluse dans l'Usine et pas simplement dans votre spéc_helper. –

+2

Merci pour la clarification, Andrew. Vous devrez peut-être placer "include ActionDispatch :: TestProcess" avant le bloc FactoryGirl.define (ce qui n'est pas le cas dans cet article: https://gist.github.com/313121). – Sam

+3

De plus, les '{}' sont requis. Il se brise sans cela – Edmund

44

récent syntaxe FG et ne comprend nécessaire

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

ou, mieux encore,

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

Je l'aime, mais gardez à l'esprit que rails 4 supprime app/assets/images/rails.png, vous devrez donc expliquer ce changement :) – stephenmurdoch

+0

Cela fonctionne mais malheureusement les images sont chargées dans/tmp – pmontrasio

37

Desmond Bowe sur chez Pivotal Labs suggests avoiding fixture_file_upload en raison de problèmes de fuite de mémoire. Au lieu de cela, vous devez définir les champs de Paperclip directement dans votre usine:

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

pour moi. Aussi assez simple pour ne pas avoir besoin d'un fichier existant dans le dossier spec/test. – bibstha

+0

Easy peezie, citron squeezie !!!! –

+1

En plus d'éviter les fuites de mémoire, les tests seront plus rapides. – evedovelli

0

Les réponses ci-dessus, dans certains cas peuvent aider, et celui réellement aidé dans un de mes situations, mais l'utilisation d'un Carrierwave, la solution précédente de cette question n'a pas fonctionné cette fois.

PREMIERE APPROCHE:

Pour moi ajouter un after :create résolu le problème pour moi comme ceci:

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

Réglage fichier vidéo en ligne comme video_file { File.new("#{Rails.root}/spec/fixtures/sample.mp4") } ne fonctionnait pas et il a été les erreurs de déclaration.

APPROCHE DEUXIÈME:

Définition d'une usine comme celui-ci (changement personal_file à votre nom de pièce jointe):

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 

Et ajouter ces lignes au config/environemnts/test.rb:

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