thoughtbot / shoulda-matchers

Simple one-liner tests for common Rails functionality
https://matchers.shoulda.io
MIT License
3.49k stars 910 forks source link

validate_absence_of an enum attribute error #1439

Closed nickbayley closed 2 years ago

nickbayley commented 3 years ago

I stumbled across this closed issue #1327 and it seems to me that the question was never properly understood. I hope you don't mind me submitting a new issue on it.

Take the following setup:

Model:

class Car < ApplicationRecord
  enum make: [:ford, :vauxhall]
  enum colour: { red: 0, blue: 10 }

  validates :model, presence: true
  validates :make, absence: true
  validates :colour, absence: true
end

Model Spec:

require 'rails_helper'

RSpec.describe Car, type: :model do
  subject(:car) { described_class.new }

  it { is_expected.to validate_presence_of(:model) }
  it { is_expected.to validate_absence_of(:make) }
  it { is_expected.to validate_absence_of(:colour) }
end

Spec results:

Car
  is expected to validate that :name cannot be empty/falsy
  is expected to validate that :make is empty/falsy
  is expected to validate that :colour is empty/falsy (FAILED - 1)

Failures:

  1) Car is expected to validate that :colour is empty/falsy
     Failure/Error: it { is_expected.to validate_absence_of(:colour) }

     ArgumentError:
       '1' is not a valid colour

I understand the error and where it comes from. But my question is:

Thanks.

mcmire commented 3 years ago

Hi @nickbayley. It seems like this issue is a bit different than the one you linked to, since there is no condition. My question to you is, if your attribute can't be set to anything, then does it make sense to be an enum?

nickbayley commented 3 years ago

Hi @mcmire! You are right that this example is pointless and silly :) I was trying to make it as simple as possible to illustrate the problem I am having.

My actual use case is something like this:

Model:

class Task < ApplicationRecord
  enum status: { open: 0, closed: 10 }
  enum closure_code: { complete: 0, duplicate: 10, non_applicable: 20 }

  validates :closure_code, absence: true, unless: :closed?
end

Spec:

RSpec.describe Task, type: :model do
  context 'when in a status of open' do
    subject(:task) { build_stubbed :task, status: :open }

    it { is_expected.to validate_absence_of(:closure_code) }
  end  

  context 'when in a status of closed' do
    subject(:task) { build_stubbed :task, status: :closed}

    it { is_expected.not_to validate_absence_of(:closure_code) }
  end  
end