Rails: "has already been taken" error on update

Viewed 70

The app finds or initializes by an attribute:

booking = Booking.where(deal_id: params["id"]).first_or_initialize

Then updates some additional attributes

    if booking.update!(
        guests: guests,
        names: names,
        time: time)

This code gives me the error

Validation failed: Deal has already been taken

The validation code is

  validates_uniqueness_of :deal_id, allow_blank: true, scope: [:experience_id, :time], unless: -> {deal_id.zero? }

Why is it giving a "has already been taken" error when first it does first_or_initialize?

Thanks

3 Answers

try to run without update method without ! to see where validation has failed

result = booking.update(
        guests: guests,
        names: names,
        time: time)
result.errors # <= see related errors here

It means you already have Booking with same deal_id in scope of experience_id, time

This could happen if you already had records in the database at the time when you added this uniqueness validation to model

But this is not necessary at all. Your first_or_initialize with just deal_id doesn't prevent of combination deal_id, experience_id and time

Besides, it doesn't protect you from race condition

You can check such records count with debug before updating:

Booking.where(
  deal_id: booking.deal_id,
  experience_id: booking.experience_id,
  time: time,
).count
# This implies the first record

booking = Booking.find_by(deal_id: params["id"])

# Update the attributes you want

# This will update the record in the database

booking.save!
Related