Goal

You’ll be able to use ActiveRecord callbacks correctly, and understand the genuine risk of overusing them — a real design tension worth knowing before reaching for a callback as a default habit.

Learn

Callbacks let you hook custom code into specific points in a model’s lifecycle:

class Order < ApplicationRecord
  before_save :calculate_total
  after_create :send_confirmation_email

  private

  def calculate_total
    self.total = items.sum(&:price)
  end

  def send_confirmation_email
    OrderMailer.confirmation(self).deliver_later
  end
end

before_save runs immediately before a record is saved (whether created or updated); after_create runs specifically after a new record is successfully created. Several other callback points exist too (before_validation, after_update, before_destroy, and more), each hooking into a specific, named moment in a record’s lifecycle.

Here’s a genuinely important design tension worth understanding: callbacks are convenient, but overusing them — especially for logic unrelated to the model’s own core data integrity — can make an application’s actual behavior genuinely hard to trace. If saving an Order silently triggers an email send, a separate inventory update, AND a notification, all buried inside different callbacks across the model, a developer reading the controller’s simple-looking order.save call has no visible indication of everything that actually happens as a result.

A reasonable guideline: callbacks are well-suited for logic genuinely about the model’s own data (like calculating a derived value before saving); logic with broader side effects (sending emails, notifying other systems) is often more transparent and maintainable when handled explicitly in the controller or a dedicated service object, where it’s directly visible rather than hidden inside the model.

Decision Task

A model has five different callbacks (before_save, after_create, after_update, before_destroy, after_destroy) each doing something with genuinely broad side effects like sending emails or notifying external systems. Before reading on: what real problem does this create for a developer trying to understand what happens when order.save is called?

Show Answer

The developer reading order.save in a controller has no visible indication of everything that actually happens as a result — five separate hidden behaviors are triggered invisibly, spread across the model rather than visible at the call site. This makes the actual behavior genuinely hard to trace, understand, and safely modify later, exactly the design tension this lesson raises about overusing callbacks for broad side effects.

Common Mistake

Reaching for a callback as the default way to trigger any side effect connected to a model, even when that side effect has broad implications (emails, external system notifications) unrelated to the model’s own core data integrity. This can make application behavior genuinely opaque, hiding significant side effects behind a deceptively simple-looking method call like save.

Practice Questions

1. Write a before_save callback on a Product model that automatically sets a slug attribute based on the name.

Show Answer

before_save :set_slug\n\nprivate\n\ndef set_slug\n self.slug = name.parameterize\nend

2. What’s the difference between before_save and after_create?

Show Answer

before_save runs immediately before any save (whether creating or updating); after_create runs specifically after a new record is successfully created, not on updates.

3. Why might sending a confirmation email specifically be a case where a callback is genuinely questionable, according to this lesson’s reasoning?

Show Answer

Email sending is a broad side effect unrelated to the model’s own core data integrity, and hiding it inside a callback makes it invisible to a developer looking at a simple order.save call, unlike logic that’s genuinely about maintaining the model’s own correct data.

4. True or False: callbacks are generally well-suited for calculating a derived value that’s genuinely part of the model’s own data, like a total based on associated items.

Show Answer

True — this kind of data-integrity-focused logic is a genuinely good fit for callbacks, unlike broader side effects like emails or external notifications.

5. What alternative does this lesson suggest for logic with broad side effects, instead of a model callback?

Show Answer

Handling it explicitly in the controller or a dedicated service object, where it’s directly visible rather than hidden inside the model.

Try It Yourself

Without looking back, explain in your own words the genuine risk of putting an “after_create: notify_external_api” callback on a model, connecting it to this lesson’s core reasoning about hidden behavior.

Show Answer

This buries a broad, external side effect (notifying an external API) inside the model, invisible to anyone reading a simple record.save call elsewhere in the codebase — exactly the “hard to trace actual behavior” problem this lesson warns about, since this kind of broad side effect is arguably better handled explicitly and visibly, not hidden inside a model callback.

Quick Check

1. What do callbacks let you do?

Show Answer

Hook custom code into specific points in a model’s lifecycle, like before or after saving.

2. When does before_save run?

Show Answer

Immediately before a record is saved, whether created or updated.

3. When does after_create run, specifically?

Show Answer

After a new record is successfully created, not on updates.

4. What’s the genuine risk of overusing callbacks for broad side effects?

Show Answer

It can make an application’s actual behavior hard to trace, since significant side effects become invisible at the call site.

5. What kind of logic is callbacks generally well-suited for, according to this lesson?

Show Answer

Logic genuinely about the model’s own data integrity, like calculating a derived value before saving.

تحميل هذا الباب / Download this Chapterنسخة كاملة للدراسة بدون إنترنت، مع الأسئلة والإجابات والصور المتاحة.