Еще не тестировал, но у меня есть идея.Он пришел ко мне после того, как он прокомментировал с coorasse его ответ об индексах базы данных.
Если была другая модель для записи, когда дата и время были заполнены, тогда before_save
с помощью Reservation
я мог бы создать эту записьи база данных позаботится об уникальности.
Миграция для новой модели и таблицы:
class CreateFullReservationTimes < ActiveRecord::Migration[5.0]
def change
create_table :full_reservation_times do |t|
t.date :date
t.datetime :arrival_time
t.index [:date, :arrival_time], unique: true
t.timestamps
end
end
end
Добавьте before_save
к модели Reservation
:
class Reservation < ApplicationRecord
before_save :add_full_reservation_time, if: :arrival_time_will_be_full?
def add_full_reservation_time
begin
FullReservationTime.create!(date: date, arrival_time: arrival_time)
rescue ActiveRecord::RecordNotUnique
errors.add(:arrival_time, "This time is not available")
throw :abort
end
end
def arrival_time_will_be_full?
Reservation.one_or_none_left_at?(date, arrival_time)
end
end
Таким образом, если осталось одно (или нет) резервирования before save
ing, оно пытается create
a FullReservationTime
(и если есть условие гонки для двух одновременных «последних резервирований», только одно будет успешным из-за ActiveRecord::RecordNotUniqe
ОБНОВЛЕНИЕ
Я проверяю это, используя несколько потоков, чтобы попытаться сохранить несколько записей одновременно.
Если я начну с одного оставленного резервирования, тест проходит и сохраняется только одно резервирование!
Если я начну с двух оставленных резервирований и запустю 3 одновременных потока, не пройдёт , потому что все они сохраняются раньшеесть время проверить, есть лиили ничего не осталось.
Я попробовал метод из ответа Макса (завершение транзакции, выполнение проверки после сохранения и повышение ActiveRecord::Rollback
, если проверка не пройдена, и тест не прошел.Все темы успешно сохраняют запись ...