Rails: Association Callbacks
31 Mar 2026TIL has_many associations have life cycle events you can define callbacks on.
Available callbacks:
before_addafter_addbefore_removeafter_remove
They are added on the association (like with dependent: :destroy or counter_cache: true).
class Author < ApplicationRecord
has_many :books, before_add: :check_limit
private
def check_limit(_book)
if books.count >= 5
errors.add(:base, "Cannot add more than 5 books for this author")
throw(:abort)
end
end
end
If a before_add callback throws :abort, the object does not get added to the collection.
If a before_remove callback throws :abort, the object does not get removed from the collection.
You can make the value an Array to run multiple:
class Author < ApplicationRecord
has_many :books, before_add: [:check_limit, :calculate_shipping_charges]
# ...
end
Rails passes the object being added or removed to the callback for you to use.
class Author < ApplicationRecord
has_many :books, before_add: [:check_limit, :calculate_shipping_charges]
# book will be the new book being created
def calculate_shipping_charges(book)
weight_in_pounds = book.weight_in_pounds || 1
shipping_charges = weight_in_pounds * 2
shipping_charges
end
end
These callbacks are called only when the associated objects are added or removed through the association collection.
# Triggers `before_add` callback
author.books << book
author.books = [book, book2]
# Does not trigger the `before_add` callback
book.update(author_id: 1)
This makes it more niche than regular model callbacks but it’s still pretty neat.