При обновлении отдельной дочерней записи запускается обновление до родительского, и дочерние записи могут обновляться одновременно, как управлять эффективностью - PullRequest
0 голосов
/ 10 апреля 2020

У меня есть родитель 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 способ сделать это.

Спасибо!

...