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
endNow 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:
before_validation→ validations →after_validationbefore_save→before_create→ INSERT →after_create→after_saveafter_commit(hereafter_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
endRails 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.
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.
Which runs first when a new book is saved?
Where should "show a book's average rating" live?
Why send emails from after_create_commit rather than after_save?
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.
