Vinícius B. Alonso

Vinícius B. Alonso

Developer

© 2019

Back

Rails Association Callbacks

This is the third blog post in a series explaining the topics of my talk Don’t Rewrite your framework at TropitalRails.

Let’s imagine a common situation: you are developing the e-commerce of the previous blog posts and you have a Cart model and an Item.

class Cart < ApplicationRecord
  has_many :items
end

class Item < ApplicationRecord
  belongs_to :cart
end

Now, you need to calculate the total price of the cart and save it in a field called total_price:

class Cart < ApplicationRecord
  has_many :items

  def update_total_price
    total_price = items.map(&:total_price).sum
    update(total_price: total_price)
  end
end

Every time a new product is added or removed from the cart, you iterate over all items to recalculate the total price. But what if we could make this process more efficient? Active Record provides association callbacks to handle this automatically.

class Cart < ApplicationRecord
  has_many :items,
    after_add: :increment_total_price,
    after_remove: :decrement_total_price

  def increment_total_price(item)
    self.total_price = item.total_price + total_price
  end

  def decrement_total_price(item)
    self.total_price =  total_price - item.total_price
  end
end

This change in the code will make the total price calculation dynamic. Of course, some may argue that this approach introduces side effects. That’s true, but remember—everything in programming involves trade-offs.

References