2
votes

Valeur nulle de Factory Bot HABTM dans la table de jointure

Je reçois une erreur (frustrante!) lors de l'exécution des tests rspec (avec Factory Bot) pour mon application Rails. Je vois l'erreur suivante:

let!(:staff_user) { FactoryBot.create(:a_staff_member) }

Elle est intermittente - différents tests généreront l'erreur sur différentes exécutions - ce qui pourrait suggérer une condition de concurrence?

Mes modèles sont configuré comme:

1) groups {|s| [s.association(:group)]}

2) after(:build) {|user| user.groups = [create(:group)]}

3) groups {[FactoryBot.create(:group)]}

Les membres du personnel DOIVENT appartenir à un groupe - avec une validation de:

FactoryBot.define do
  factory :group do
    sequence(:title) { |n| "Group Number #{n}" }
    sequence(:short_title) { |n| "GRP#{n}" }
    sequence(:url_slug) { |n| "grp#{n}" }
  end
end

Utilisateurs

factory :a_staff_member, class: User do
    first_name { Faker::Name.first_name }
    last_name { Faker::Name.last_name }
    username { "#{first_name}_#{last_name}".downcase.gsub(/[^a-z]/i, '') }
    email { "#{first_name}.#{last_name}@example.ac.uk".downcase }
    user_type { :staff }
    groups {|s| [s.association(:group)]}
end

validates :groups, presence: { message: 'Staff must be in at least one group' }, if: :staff?

Le facteur commun à tous les échecs tests est la fabrique de création d'utilisateurs (et la création de groupes donnée à un utilisateur DOIT appartenir à un groupe) - c'est donc là que j'ai concentré mes efforts.

Étant donné que l'erreur est sur la table groups_users I ' Je suppose qu'il essaie de sauvegarder une entrée dans la table de jointure avant que le groupe n'existe dans la table des groupes?

En me basant sur d'autres messages SO et en parcourant Internet, j'ai essayé différentes façons de configurer le groupe:

User habtm Groups
Groups habtm Users

Les utilisateurs sont simplement instanciés via

ActiveRecord::NotNullViolation:
        Mysql2::Error: Field 'group_id' doesn't have a default value: INSERT INTO `groups_users` VALUES ()

dans les spécifications individuelles - donc rien d'excitant ici.

Cependant, pas de compagnon r comment je crée les groupes dans les usines cela ne fait aucune différence - et je suis à court d'idées - tous les pointeurs ou suggestions seront reçus avec gratitude!


2 commentaires

Cette validation ne fonctionnera pas car c'est un catch-22. Vous devez insérer l'enregistrement utilisateur dans la base de données avant de pouvoir insérer quoi que ce soit dans la table de jointure car la table de jointure nécessite un identifiant d'utilisateur (et l'enregistrement n'a pas d'identifiant tant qu'il n'est pas inséré). Vous devez repenser cela à partir de la case départ.


Merci pour votre réponse - je devrais probablement ajouter - ce n'est un problème que lors de l'exécution des tests - le code lui-même fonctionne (je peux créer des utilisateurs via l'interface utilisateur avec succès - cela fonctionne également par intermittence dans la suite de tests). Il n'y a pas de dépendance circulaire - tant que le groupe existe, l'utilisateur peut y être ajouté. Pour autant que je sache, c'est un problème avec la façon dont je crée le groupe dans l'usine et quand il persiste afin qu'il puisse être lié à travers la relation habtm.


3 Réponses :


1
votes

Je pense qu'essayer de changer l'égalité avec la concaténation pourrait fonctionner.

J'ajouterais après (: create) {| user | user.groups << create (: group)}

Passer à après (: create) est la chose principale ici car le problème auquel vous êtes confronté semble également être d'essayer d'ajouter un enregistrement de table de jointure pour un enregistrement qui n'est pas encore créé.


1 commentaires

Salut, merci pour votre suggestion. Malheureusement, cela ne fonctionne pas car il existe une validation selon laquelle un utilisateur doit appartenir à un groupe. L'appel de l'affectation du groupe dans une post-création entraîne l'échec de cette validation. NB c'est le group_id qui est nul dans le message d'erreur - comme si le groupe n'avait pas été créé avant d'essayer de le rejoindre lors de l'enregistrement de l'utilisateur ... J'ai également essayé de changer l'assignation en concaténation - mais cela n'avait pas effet :( Merci pour les suggestions!



0
votes

Je pense que cela pourrait fonctionner si vous changez comme ceci.

 from
 after(:build) {|user| user.groups = [create(:group)]}

 to
 after(:create) {|user| user.groups = [create(:group)]}

Une fois qu'un identifiant d'utilisateur est créé en exécutant "create", alors "users.groups" sera acceptable. p>


1 commentaires

Merci pour votre suggestion - malheureusement, cela ne fonctionne pas car elle est déclenchée après la création de l'utilisateur - cela entraînera l'échec de la validation selon laquelle l'utilisateur doit appartenir à au moins un groupe. J'espérais qu'en mettant un appel pour créer un groupe dans une version ultérieure, cela garantirait que l'enregistrement de groupe existe lorsque l'utilisateur est enregistré, donc il y a un enregistrement auquel se joindre lors de la création de l'utilisateur!



1
votes

J'ai réussi à localiser le problème. Après avoir placé des messages de débogage complets autour du point dans l'usine où le groupe a été créé et attribué à l'utilisateur, il est devenu clair que le message d'erreur relatif aux valeurs nulles dans la table de jointure entre celles-ci était, en fait, un hareng causé en dehors de l'usine.

Je crois que le problème a été causé par le fait que la session / connexion de l'utilisateur n'a pas été nettoyée entre les tests de Capybara.

Ajout:

config.after :each do
  Warden.test_reset!
end


0 commentaires