Obromios
Obromios

Reputation: 16403

Validation error on has_many association not preventing save

I have a model eclub, which has many invites, and I want to limit the number of invites that can be added. My model looks like this

class Eclub < ActiveRecord::Base
    has_many :invites, dependent: :destroy
    validates :invites, length: {maximum: 50, message: 'The maximum number of invites have been sent' }

which according to this SO answer should work provided I am not concerned about invites marked for destruction. My rspec test first creates an eclub and successfully adds 50 invites to it. Then

  invite = Invite.new(name: 'Too Many', email: '[email protected]')
  eclub.invites << invite
  expect(eclub).to be_invalid
  expect(eclub.errors[:invites].first).to include 'maximum number'
  expect(eclub.reload.invites.size).to eq 50

The first two expectations pass, but the last fails with

Failure/Error: expect(eclub.reload.invites.size).to eq 50

       expected: 50
            got: 51

How do I prevent the extra invite from being added to the collection?

Upvotes: 2

Views: 1219

Answers (3)

Jagdeep Singh
Jagdeep Singh

Reputation: 4920

The best place to add this validation is not in Eclub but Invite model. Try this:

class Invite < ActiveRecord::Base
  belongs_to :eclub
  validate :check_invite_count!, on: :create

  private

  def check_invite_count!
    return if eclub.nil?
    if eclub.invites.count > 50
      errors.add(:base, 'Cannot add more than 50 invites for an Eclub')
    end
  end
end

Also, this code validates :invites, length: {maximum: 50, message: 'The maximum number of invites have been sent' } won't work because it assumes invites to be a string.

Upvotes: 4

Taryn East
Taryn East

Reputation: 27747

validates length is intended to measure the length of a string, and probably doesn't work well with integers.

What you probably want to try is validates :numericality => {:maximum => 50}

EDIT yeah, what I have here probably wont' work either as it's the count of invites (not the invites association itself) that is what we need to validate, so here's a custom validator that should do what you want:

validate :invite_count_is_ok

private

def invite_count_is_ok
  return unless invites.present?
  errors.add(:base, "You may only have up to 50 invites at a time") unless invites.count <= 50
end

Upvotes: -1

bk chovatiya
bk chovatiya

Reputation: 223

validates(
  :invites,
  numericality: {
    greater_than_or_equal_to: 0,
    less_than_or_equal_to: 50
  }
)

Upvotes: -2

Related Questions