Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
Models  ›  Capstone Project

Model Callbacks and Model Methods

Callbacks 15 minModel methods put behaviour next to the data it uses, and callbacks such as before_validation, before_save and after_create_commit run code automatically at fixed points in a record's life.

Model Callbacks and Model Methods

Models are not just rows. A book can tell you its average rating; a review can tidy its own text before it is checked. Model methods hold that behaviour. Callbacks are a special kind: methods Rails calls for you at fixed moments, such as just before saving.

The rule

Ask the model, not the controller; hook the moment, not every save.

Model methods are ordinary Ruby methods:

class Book < ApplicationRecord
  has_many :reviews, dependent: :destroy

  def average_rating
    reviews.average(:rating)&.round(1)       # nil when there are no reviews
  end

  def long?
    pages.to_i > 500
  end

  def self.by(author)                       # class method: Book.by("Le Guin")
    where(author: author)
  end
end

Now views and controllers say @book.average_rating instead of repeating the calculation.

Callbacks run at points in the life of a record. For a new record that is saved, the order is:

  1. before_validation → validations → after_validation
  2. before_save → before_create → INSERT → after_create → after_save
  3. after_commit (here after_create_commit) — once the transaction is really done

Updates use before_update / after_update; deletes use before_destroy / after_destroy.

class Book < ApplicationRecord
  before_validation :tidy_title
  after_create_commit :notify_followers

  private

  def tidy_title
    self.title = title.to_s.squish
  end

  def notify_followers
    NewBookMailer.with(book: self).announce.deliver_later
  end
end

Rails 7.1 added a neater way for the first job: normalizes :title, with: -> title { title.squish }.

To stop a save from a before_ callback, call throw :abort.

The shortcut

Ask "is it tied to a moment in saving?" No → a plain method. Yes → pick the moment: must happen before checks → before_validation; changes what gets written → before_save; talks to the outside world → an after_*_commit callback, so it only fires if the data truly exists.

Where to send the "new book" emailStep 1 of 4
  1. Tied to saving?

    Yes: it should happen when a book is created.

The trap is stuffing business processes into callbacks. If code should run only in one situation — say, when an admin imports books — call it explicitly there instead.

Drills

Answer fast — trust the rule.

quick drill

Which runs first when a new book is saved?

quick drill

Where should "show a book's average rating" live?

quick drill

Why send emails from after_create_commit rather than after_save?

quick drill

How does a before_save callback cancel the save?

Remember

  • Ask the model, not the controller; hook the moment, not every save.
  • Shortcut: not tied to saving → method; before checks → before_validation; outside world → after_commit.
  • Trap: hiding one-off processes in callbacks that run on every save.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainCallback or plain method?

Bookclub needs to (1) strip spaces from a book's title before it is checked, (2) show a book's average rating, and (3) email the author's followers after a new book is saved. Choose a model method or a callback for each, name the callback, and explain your choice for the email.