Представьте, что у вас есть Site
, в котором есть одна из тех вещей, которые "берут число", где люди берут число, а затем ждут своей очереди. Допустим, каждое число является Order
. Отношение состоит в том, что у Site
есть много Orders
. В заданной точке сброса менеджер сайта проходит и заменяет вещи «возьми число» новыми бросками чисел, т. Е. Вы могу представить, что это происходит ежедневно. Тем не менее, вещи типа «взять число» изготавливаются с конечными числами, поэтому каждый бросок состоит, скажем, из 1-100, а затем начинается следующий бросок 100-999.
Я пытаюсь смоделировать описанное выше поведение, как я думал о приближении к нему:
- На родительском элементе
Site
есть атрибут start_number
. Нажатие на сброс / переключение броска приведет к сбросу start_number
на 100, т. Е. К первому номеру броска - На дочернем элементе
Order
существует обратный вызов, который присваивает номер. Если родительский номер Site
равен 100, то это означает, что это первый Order
после сброса, как описано в шаге # 1, поэтому тогда это число также равно 100. Теперь родительский элемент Site
автоматически обновляется, так что он больше не находится в состоянии сброса (например, start_number
больше не равен 100). Для будущего Orders
назначенный номер - это просто следующий номер после предыдущего заказа
Вот код:
class Site
has_many :orders
end
class Order
belongs_to :site
before_save :assign_number
def assign_number
if site.start_number == 100
self.number = 100
self.site.update_column(:start_number, nil)
else
self.number = self.site.orders.where.not(number:nil).last.number + 1
end
end
end
Но это дерьмо, потому что в отличие от реального мира «возьми число», 2 ордера могут быть обработаны одновременно, нет ограничения unique
на Order.number
, потому что числа снова используются (бросок сбрасывается). Но, очевидно, бесполезно, если после сброса 2 ордера, которые размещаются близко друг к другу, равны 100
. Вы хотите, чтобы несколько ордеров совместно использовали number
, если действительно произошло событие сброса, а не только случайное время.
Еще одна проблема в этом подходе - когда за 1 ордером следует вторая. Например, скажем, последний присвоенный номер был 415
, 2 заказа выполняются в быстрой последовательности. Первому присваивается 416
, второму так близко, что self.site.orders.where.not(number:nil).last.number
все еще возвращает 415
(т. Е. 416
еще не сохранено), и поэтому второму ордеру теперь также присваивается 416
.
Было бы здорово получить идеи о том, как лучше смоделировать желаемое поведение. Спасибо!
ОБНОВЛЕНИЕ По комментариям @ Фернана, я собираюсь go с блокировкой пессимистичности c, которую я реализую согласно примечаниям здесь . Итак, прямо сейчас код выглядит так:
def assign_number
site = self.site.lock!
if site.start_number == 100
self.number = 100
site.start_number = nil
else
last_order = self.site.orders.where.not(number:nil).last.lock!
self.number = last_order.number + 1
last_order.save! # releases lock
end
site.save! #releases lock, whether or not call number was updated to nil
end
Я не совсем уверен, как написать c, хотя ... так как написание spe c по определению упорядочено ... как вы заставить 2 приказа сохранить близко друг к другу, чтобы смоделировать это поведение?