У меня есть родитель Order
, у которого много детей Item
с. Существует атрибут status
как для родительского, так и для дочернего элементов, и статусы взаимодействуют. Например, только когда все Item
s равны complete
, родительский элемент Order
может быть полным.
Думайте об этом, как о ресторане, где политика состоит в том, чтобы выпустить всю еду в данном Order
сразу. Каждая еда Item
проходит через такие состояния, как in_prep
, being_cooked
, et c. на complete
и когда все Items
равны complete
, тогда Order
равно complete
, и затем его можно вывести, после чего все Item
и родительский Order
могут иметь статус из enjoyed_by_customer
Расширяя этот пример, скажем, у различных линейных поваров в каждой части кухни есть планшет, где они могут обновлять статусы спецификаций c Items
и только те Items
в своих сфере компетенции. Шеф-повар, однако, может просматривать весь Order
и вносить обновления в любой отдельный статус Item
, потому что шеф-повар ходит, настраивает, пробует и вносит изменения, с творческой способностью изменять любые Item
по желанию , Например, возможно, повар говорит, что Item salad
- это complete
, но шеф-повар пробует его на вкус, говорит, что ему нужно больше дрессировки, и устанавливает его на in_prep
.
Сначала я построил панель управления. для линейных поваров отметить c Items
в их компетенции. Например, линейный повар, готовящий салаты, должен иметь возможность просматривать все салаты из всех Orders
, которые не являются complete
, и выполнять пакетные обновления для всех из них. Например, последний шаг может быть garni sh, поэтому они могут garni sh дюжину тарелок за раз, а затем установить все эти салаты на complete
. Это означало, что я подумал сделать обратный вызов для модели Item
, которая вызывала метод set_status
для родительского Order
:
class Item
after_update :set_order_status
# after_update so we know that the status on this Item is valid
def set_order_status
if self.status.changed?
self.order.set_status
end
end
end
class Order
def set_status
new_status = calculated_somehow_from_item_statuses # eg if all items are 'complete', this returns 'complete'
self.update_attributes(status: new_status)
end
end
Во-вторых, я создал общую панель управления Order
для шеф-повар, где он может снова изменить статусы любого Item
, а также другие атрибуты самого Order
. Например, может быть, шеф хочет пометить Order
специальной скидкой или чем-то еще. Ради эффективности я настроил панель инструментов Order
для обновления всего Order
сразу, используя вложенные атрибуты. Другими словами, представленные параметры имеют вид:
{
"discount": "true",
"items_attributes": [
{"id"=>"1","status"=>"complete"},
{"id"=>"2","status"=>"in_prep"},
]
}
# this way it's easy to just do:
@order.update_attributes(params)
Однако, конечно, из-за того, как были настроены панели управления отдельной линии повара, @order.update_attributes
фактически вызывается один раз для @order
а затем еще раз после каждого ребенка item
обновлений. Другими словами, существует избыточность, вызванная тем фактом, что дочерние элементы могут обновляться как 1) по отдельности, так и 2) массово, где в любом случае родительский порядок должен обновляться в конце на основе всех дочерних элементов в совокупности .
Моя единственная мысль при пересмотре этого - отрегулировать обратный вызов set_order_status
для дочернего элемента, он не срабатывает, если шеф-повар выполняет обновление элемента на уровне Order
. Другими словами:
class Item
after_update :set_order_status
attr_accessor: changed_by_chef
def set_order_status
if self.status.changed? && self.changed_by_chef == false
self.order.set_status
end
end
end
# where updates from the chef's dashboard, rather than individual line cooks, will have changed_by_chef in params
{
"discount": "true",
"items_attributes": [
{"id"=>"1","status"=>"complete", "changed_by_chef"=>"true"},
{"id"=>"2","status"=>"in_prep", "changed_by_chef"=>"true"},
]
}
@order.assign_attributes(params) # assign statuses to child items and run validations
@order.set_status # this method calculates appropriate order level status based on validated child item statuses, and calls the final update_attributes to save everything
Таким образом, @order.update_attributes
фактически вызывается один раз. Тем не менее, это также кажется мне немного хакерским, и мне интересно, есть ли более обычный Railsy способ сделать это.
Спасибо!