2016-12-06 3 views
0

Je suis mise à niveau mon application de Rails de 4,0 à 4,1 (sur mon chemin à 4.2) et des tests comme celui-ci qui échouent:Rechargement un objet activerecord dans rspec met à jour l'enregistrement de base de données au lieu de recharger l'objet de la db

describe "#restore_disabled_account" do 
    let(:username) { 'username' } 
    let(:email) { '[email protected]' } 
    let(:m3_user) { create(:user, username: username, 
            email: email, 
           archived: false, 
        propagate_in_test_mode: true) } 
    let(:m2_user) { Maestro2::User.where(UserID: m3_user.id).first } 

    before do 
    m3_user.disable_account 
    end 

    it "unarchives the account" do 
    m3_user.restore_disabled_account 
    m3_user.reload 
    expect(m3_user.archived).to be_falsey 
    end 
end 

J'ai vérifié que la base de données contient un enregistrement avec les attributs attendus au début de ce test. Lors du débogage du test et je m'arrête avant l'instruction reload, je vois que l'enregistrement db a été mis à jour comme prévu (archivé est faux et les autres attributs sont mis à jour comme prévu). Je peux également voir que l'objet m3_user a été mis à jour avec les mêmes attributs. Lorsque je fais un pas en avant pour exécuter l'étape de rechargement et interroger la base de données, je peux voir que l'enregistrement est revenu à son état d'origine, tout comme l'objet en mémoire. Le test échoue ensuite car m3_user.archived est vrai.

Quelqu'un peut-il me dire pourquoi? Tous les tests de ma suite étaient en cours avant de commencer la mise à niveau. L'application est actuellement en utilisant Ruby 2.2.4, Rails 4.1.16, 3.5.3 et rspec rspec rails 3.5.2

Pour référence, les deux appels de méthode de classe d'utilisateurs sont ci-dessous:

def disable_account 
    self.update_attributes(username: "disabled_#{id}_#{username}", 
          email: "disabled_#{id}_#{email}", 
         archived: true) 
end 

def restore_disabled_account 
    self.update_attributes(username: username.gsub(/^disabled_#{id}_/, ''), 
          email: email.gsub(/^disabled_#{id}_/, ''), 
         archived: false) 
end 
+0

Ceci n'est pas lié à la question mais '" # {nom d'utilisateur} "' est redondant. Tout ce que vous interpolez est la variable elle-même, donc il doit juste être "nom d'utilisateur: nom d'utilisateur", etc. Interpolation est pour lorsque la chaîne contient plus que du code Ruby dynamique. – sixty4bit

+0

pouvez-vous également s'il vous plaît ajouter le contenu de la méthode '# restore_disabled_account' et essayer de supprimer le bang'! 'De' let! '? – sixty4bit

+0

J'ai ajouté le code que vous avez demandé. Retrait du bang n'a pas changé les résultats, malheureusement. – Warren

Répondre

0

Le Réponse courte: Il s'avère que ActiveRecord 4.1 a changé la méthode reload pour appeler une nouvelle méthode privée appelée reset_changes. Ma classe User avait également une méthode reset_changes donc ma méthode a préséance sur ce qui aurait dû être appelé. La réponse longue: Plus je regardais cela, plus je soupçonnais quelque chose d'unique à mon modèle d'utilisateur. D'autres tests utilisant reload ont été effectués comme prévu. Je suis ensuite tombé sur une méthode reset_changes dans User. Après avoir vu ce qu'il a fait (mettre à jour l'enregistrement db avec les valeurs précédentes), j'ai laissé tomber une instruction puts pour que je puisse voir si elle était appelée. Une fois que cela a été confirmé, j'ai jeté le backtrace de l'appelant qui m'a indiqué https://github.com/rails/rails/blob/4-1-stable/activerecord/lib/active_record/attribute_methods/dirty.rb#L37

J'ai changé ma méthode de modèle d'utilisateur à undo_changes et mes spécifications sont vertes.