18 votes

Comment utiliser la fille de l'usine pour créer des listes associées avec un has_many avec une validation qui le requiert à la création.

Dans une application Rails, vous disposez de trois modèles, Utilisateur, Article et Réviseur, avec les relations et validations suivantes :

class User < ActiveRecord::Base
  has_many :articles
  has_many :reviewers
end

class Reviewer < ActiveRecord::Base
  belongs_to :user
  belongs_to :article
end

class Article < ActiveRecord::Base
  belongs_to :user
  has_many :reviewers

  validate :has_reviewers?

  def has_reviewers?
    errors.add(:base, "article must have at least one reviewer.") if self.reviewers.blank?
  end
end

Et les usines suivantes utilisant la nouvelle DSL :

FactoryGirl.define do

  factory :user do
    name { (8...20).map{ ('a'..'z').to_a[rand(26)] }.join }
    age  { Kernel.rand(100) }
  end

  factory :article do
    body "This is the article content"
    title "This is the title"
    user
    after_create do |article|
      article.reviewers = create_list(:user, 2)
    end
  end

  factory :reviewer do
    user
    article
    state { ["published","draft","rejected","archived"][Kernel.rand(4)] }
  end

end

La fabrique pour créer l'article ne fonctionne pas car la validation échoue avant que les réviseurs ne soient créés :

> FactoryGirl.create(:article)
ActiveRecord::RecordInvalid: Validation failed: article must have at least one reviewer.

J'ai fait plus de tentatives que je ne voudrais l'admettre pour essayer de surmonter cet obstacle, mais je suis bloqué ! Une idée que j'ai eue était de créer les évaluateurs comme ceci :

  factory :article do
    body "This is the article content"
    title "This is the title"
    user
    reviewers {|a| [FactoryGirl.create(:reviewer, article: a)] }
  end

mais dans ce contexte, le "a" n'est pas l'instance. Donc cela ne fonctionne pas non plus, comme avant.

22voto

Blizzo Points 654

J'ai reposté cette question sur la page github de Factory Girl en tant que problème et j'ai trouvé la réponse :

before_create do |article|
  article.reviewers << FactoryGirl.build(:reviewer, article: article)
end

La clé était de le faire dans un before_create, de sorte que les validations n'aient pas encore été lancées, et de s'assurer de pousser le critique nouvellement créé dans la liste des critiques de l'instance en cours de création. Merci à Unixmonkey d'avoir répondu et de m'avoir fait essayer de nouvelles choses :)

https://github.com/thoughtbot/factory_girl/issues/369#issuecomment-5490908

3voto

Unixmonkey Points 7947
factory :article do
  reviewers {|a| [a.association(:reviewer)] }
end

o

factory :article do
  before_create do |a|
    FactoryGirl.create(:reviewer, article: a)
  end
end

1voto

Michaël Witrant Points 4258

La nouvelle syntaxe est la suivante :

before(:create) do |article|
  article.reviewers << FactoryGirl.build(:reviewer, article: article)
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X