Understanding Active Record Callbacks

As we’ve seen over the last couple of weeks, Active Record objects have a lot of power and responsibility within a Ruby on Rails project.

You will often find that a lot of the business logic of the application is attracted to your Active Record objects.

A common aspect of business logic is that something should happen on a certain action.

For example, whenever an object is created, updated, or destroyed, something should happen as a consequence of that action.

Active Record provides callbacks that allow you to hook into the lifecycle of the object. This means you can take an action whenever one of the lifecycle events occurs.

In today’s tutorial we will be looking at Active Record Callbacks.

What are Active Record Callbacks?

An Active Record callback is basically just a way to trigger logic before or after a change to the object’s state. This allows you to run any arbitrary code automatically whenever that event occurs.

Active Record has a lot of lifecycle events that are triggered around creating, updating, and destroying objects. There are also events that are triggered when using Active Record to query the database.

You can hook onto events that will be run before, during, or after these triggers.

Registering Active Record Callbacks

There are two different ways in which you can register Active Record Callbacks.

Again, as with the macro style registration of callbacks, it’s up to your discretion as to which version you use, but it’s probably better to only use a Proc if the check is really short and concise.

Creating Callback Classes

Sometimes you might want to extract a callback into it’s own class for reuse or for isolation. For example, perhaps whenever a new user is created we want to set a timestamp to expire their trial for the application:

class User < ActiveRecord::Base
after_create SetTrialExpiresAt
end

You can then deal with the callback in it’s own class:

class SetTrialExpiresAt
def self.after_create(user)
# Set the timestamp
end
end

By abstracting the callback into it’s own class it also makes it really easy to reuse callbacks across different models.

When should you avoid Callbacks?

Callbacks can be great as a way to run code on certain actions of the Active Record lifecycle.

However, Callbacks can also turn into a nightmare!

Callback logic can often get really complicated as more and more callbacks are added to the model.

Callbacks are also not always guaranteed to run. If a developer implements a certain bit of functionality that skips the callback for whatever reason, important business logic might be circumvented.

The scope of what should happen as a consequence of a callback should also be thought about a lot. Whilst callbacks are good for certain actions such as modifying data on the object, it’s probably not a good idea to start using them to automatically send emails, or add the user to an external service! There are much better ways to deal with these types of events than shoehorning it into the model.

I would try and keep your usage of callbacks to a minimum, make it obvious as to what will happen on certain actions and don’t let yourself get sucked into callback hell.