lundi 25 janvier 2021

Rails 6 ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR when testing

In a Rails 6 backend API, I have a typical User model, with email, fullname, username and so on, and also an index on the email column (however, I do not think it has anything to do with my error). I also have a sessions controller, which until now, only responds to post requests, which basically create a log in session for the user and return a JWT to the client.

It works fine, but when it comes to testing (an integration test for the sessions controller), the following error keeps occuring randomly (like in 75% of the cases):

ActiveRecord::RecordNotUnique: PG::UniqueViolation: ERROR: duplicate key value violates unique constraint "users_pkey" DETAIL: Key (id)=(732175191) already exists.

Sometimes, this error does not occur and tests work fine, but that's in the minority of the cases.

This is the integration tests file for the session controller:

class SessionsTest < ActionDispatch::IntegrationTest
  def setup
    @alex1 = User.new(full_name: "Alex Robert", email: "rob@example.com", date_of_birth: "2000-02-02", city: 'Cluj', country: 'Romania', username: 'alex', password: User.get_digest('alex1234'))
  end

  test "log in attempt with invalid parameters respond with status 401" do
    post sessions_path, params: {
      user: {
        email: " ",
        password: " "
      }
    }
    json_response = JSON.parse(response.body)
    assert_equal 401, json_response["status"]
  end

  test "log in attempt with invalid password respond with status 401" do
    post sessions_path, params: {
      user: {
        email: @alex1.email,
        password: "alabala"
      }
    }
    json_response = JSON.parse(response.body)
    assert_equal 401, json_response["status"]
  end
end

This is the User model:

class User < ApplicationRecord
    attr_accessor :remember_token

    VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

    before_save { self.email = email.downcase }

    validates :full_name, presence: true, length: { maximum: 255 }
    validates :email, presence: true, length: { maximum: 255 }, format: { with: VALID_EMAIL_REGEX }
    validates_uniqueness_of :email, :case_sensitive => false
    validates :date_of_birth, presence: true
    validates :country, presence: true
    validates :city, presence: true
    validates :username, presence: true, length: { maximum: 50 }
    validates :password, presence: true, length: { minimum: 6 }
    validates :password_confirmation, presence: true, length: { minimum: 6 }
    
    has_secure_password
    
    def self.get_digest(string)
        cost = ActiveModel::SecurePassword.min_cost ? BCrypt::Engine::MIN_COST : BCrypt::Engine.cost
        BCrypt::Password.create(string, cost: cost)
    end

    def self.encode_jwt(payload)
        JWT.encode(payload, 'secret')
    end

    def self.decode_jwt(jwt)
        JWT.decode(jwt, 'secret', true, algorithm: 'HS256')
    end
end

I have looked up my issue on at least 10 Stack Overflow threads, but the suggestions did not work out for me. Some suggested to reset the db (drop and recreate it) or reset the sequence id, with the following task:

namespace :database do desc "Correction of sequences id" task correction_seq_id: :environment do ActiveRecord::Base.connection.tables.each do |t| ActiveRecord::Base.connection.reset_pk_sequence!(t) end end end

However, I found that most people were having a slightly different error, that was connected to the uniqueness of the email. My error seems a more weird one, because it's about the duplication the primary key constraint. As seen in the error message I posted above, the test runner complains that: (id)=(732175191) already exists.

Aucun commentaire:

Enregistrer un commentaire