How to update belongs_to parent on after_update_commit

Hello,

I’m wondering if it’s possible to trigger a belongs_to relationship by calling after_update_commit.

Use case: shopping cart. Once a line_item is updated, it correctly streams to the page. Additionally, another update should take a place. There is a shopping cart icon in the navbar with a little badge to display the number of items in the cart. The cart is rendered with an @cart instance.

How can the cart be updated and streamed by solely a change in associated line_item (i.e. updating the quantity)?

class Cart
has_many :line_items
class LineItem
belongs_to :cart

after_update_commit { broadcast_replace_to "line_items" }
after_update_commit { ?? How to trigger streaming cart to update to ?? }
1 Like

Have you tried this?

class LineItem
  belongs_to :cart

  after_update_commit { broadcast_replace_to "line_items" }
  after_update_commit { broadcast_replace_to [ cart, :line_items ] }

You’ll probably need to pass in a partial (unless it’s carts/_cart) and the cart variable to it, a la:

after_update_commit { broadcast_replace_to [ cart, :line_items ], partial: "carts/badge", locals: { cart: cart } }

1 Like

Thanks for helping.

In trying what you suggested, another issue popped up that prevents me from fully testing your suggestion. I’ve just created a separate post about it, as it’s not really the same issue. Once I’m able to remove some more obstacles from the road, I’ll get back to you if it worked or not.

Do you have a partial for Cart? If so, have you considered using

belongs_to :cart, touch: true

in LineItem?

Not at all sure if this is the best approach, but by touching the Cart on any LineItem change, you could trigger the Cart partial to automatically update when a LineItem is saved/destroyed (assumes you have an after_update_commit for Cart as well).

1 Like

What I end up doing was blending both of your suggestions together. touch: true on the LineItem model works like magic combined with broadcasting on the cart model. One page now has 3 partials that are being updated by hotwire, and it’s blazing fast (without gif) :rocket: .

  1. badge (navbar icon) → through after_update_commit (Cart model )
  2. active_cart (button) → through after_update_commit (Cart model)
  3. turbo_stream stream response from the controller to change the minus, plus or add to cart btn.
class Cart 
  ...
  after_update_commit do
    broadcast_replace_to 'badge',
                         partial: 'carts/badge',
                         locals: { cart: self },
                         target: "badge_#{id}"
  end

  after_update_commit do
    broadcast_replace_to 'cart',
                         partial: 'carts/active_cart',
                         locals: { cart: self }
  end
end

Thanks for helping out @dan, @dayo.

4 Likes