Search code examples
ruby-on-railsrubyvalidationuniqueminitest

Why is the "uniqueness: true" validation not working in my test (Rails)?


In my Rails app, I am trying to save MAC addresses for devices belonging to different users. Each MAC address must be unique, so I included the uniqueness validation. The validation itself seems to be working, since duplicate records were rejected when I tried using the Rails Console (ActiveRecord::RecordNotUnique). However, my test to check that only unique records can be saved is failing.

So my questions are:

  1. Why is my test failing and how can I fix it?
  2. I read elsewhere that the uniqueness validation alone is not a reliable way to assure uniqueness. Should I use other methods, such as before_save callbacks?

This is the error message I'm getting for the test:

Expected #<MacAddress id: nil, user_id: nil, address: "MACADD123", created_at: nil, updated_at: nil> to be nil or false

Setup in my model files:

# app/models/mac_address.rb

class MacAddress < ApplicationRecord
  validates :address, uniqueness: true
  belongs_to :user
end
# app/models/user.rb

class User < ApplicationRecord
  has_many :mac_addresses, dependent: :destroy
end

Test to check for uniqueness:

class MacAddressTest < ActiveSupport::TestCase
test 'mac address must be unique' do
    new_mac = 'MACADD123'
    assert MacAddress.create(user: User.first, address: new_mac)
    assert MacAddress.all.pluck(:address).include?(new_mac)

    # The 'assert_not' below is failing.
    assert_not MacAddress.create(user: User.second, address: new_mac)
  end
end

Thanks for any help in advance.


Solution

  • As per the documentation on create:

    Notice there's no id for that record. It hasn't been persisted. Check for errors with .errors.full_messages to see the uniqueness validation failure.

    The resulting object is returned whether the object was saved successfully to the database or not.

    You should assert that it's saved, like:

    mac_address = MacAddress.create(...)
    assert !mac_address.new_record?
    

    Where that tells you if it's been saved or not. Alternatively you can use create! which will raise ActiveRecord::RecordInvalid if it failed.