Understanding Active Record Callbacks
Tags: rails, ruby, activerecord
Published: 2020-07-23 13:29:34

---
title: Understanding Active Record Callbacks
published: true
date: 2020-07-07 13:41:00 UTC
tags: rails, ruby, activerecord,
canonical_url: https://web-crunch.com/posts/understanding-active-record-callbacks
---

{% youtube 1-31AlGv96Y %}

Callbacks are methods that get called at certain moments of an object's life cycle. We can use callbacks as a means to manipulate objects further with built-in functionality that Ruby on Rails ships with.

This guide is an overview of Active Record Callbacks and how they can enhance your Ruby on Rails app with seemingly little effort.

To learn even more about Active Record Callbacks I recommend you visit and [review the documentation](https://guides.rubyonrails.org/active_record_callbacks.html) around it.

### The available callbacks

Rails ships with a number of callbacks baked in. We can use these methods as a means to perform more logic during, after, before, or around the manipulation of active record objects.

### Creating an Object

- `before_validation`
- `after_validation`
- `before_save`
- `around_save`
- `before_create`
- `around_create`
- `after_create`
- `after_save`
- `after_commit/after_rollback`

### Updating an Object

- `before_validation`
- `after_validation`
- `before_save`
- `around_save`
- `before_update`
- `around_update`
- `after_update`
- `after_save`
- `after_commit/after_rollback`

### Destroying an Object

- `before_destroy`
- `around_destroy`
- `after_destroy`
- `after_commit/after_rollback`

### Registering a callback

A basic example of a callback is as follows. These take place in your models in a given Ruby on Rails application.

Here we register the callback `before_validation` and reference a Symbol (another method) that will run when a user tries to log in.

```ruby
class User < ApplicationRecord
  validates :login, :email, presence: true

  before_validation :ensure_login_has_value

  private

    def ensure_login_has_a_value
      if login.nil?
        self.login = email unless email.blank?
      end
    end
end

```

### Passing a block

Sometimes your code is short enough to be a one-liner. You can optionally pass a block in the callback instead of referencing another method.

```ruby
class User < ApplicationRecord
  validates :login, :email, presence: true

  before_create do
    self.name = login.capitalize if name.blank?
  end
end
```

### Dictate when the callback fires

Extending callbacks with `on:` allows you to pass one or more lifecycle events dictating when a callback executes. This is really handy!

```ruby
class User < ApplicationRecord
  before_validation :normalize_name, on: :create

  # :on takes an array as well
  after_validation :set_location, on: [:create, :update]

  private
    def normalize_name
      self.name = name.downcase.titleize
    end

    def set_location
      self.location = LocationService.query(self)
    end
end
```

### When callbacks get fired

Active Record already gives us a number of methods to transform data via objects. When we run these, callbacks can actually be called.

Some examples

```
User.destroy_all

# The following methods trigger callbacks:

  # create
  # create!
  # destroy
  # destroy!
  # destroy_all
  # save
  # save!
  # save(validate: false)
  # toggle!
  # touch
  # update_attribute
  # update
  # update!
  # valid?

## Additionally, the after_find callback is triggered by the following finder methods:

User.all

  # all
  # first
  # find
  # find_by
  # find_by_*
  # find_by_*!
  # find_by_sql
  # last
```

### Relational Callbacks

Much like Active Record relations, callbacks can be performed when related objects are changed. A common example of this might be if you destroy a record and have `dependent: :destroy` enabled. This proceeds to destroy and orphaned data associated with the parent class. What's great is that you can additionally use a callback to perform more operations if necessary.

```ruby
class User < ApplicationRecord
  has_many :articles, dependent: :destroy
end

class Article < ApplicationRecord
  after_destroy :log_destroy_action

  def log_destroy_action
    puts 'Article destroyed'
  end
end

>> user = User.first
=> #<User id: 1>
>> user.articles.create!
=> #<Article id: 1, user_id: 1>
>> user.destroy
Article destroyed
=> #<User id: 1>
```

Here, a `User` has many articles. If a user account is deleted, and `dependent: :destroy` is in place, you can see the `after_destroy` callback fire.

### Conditional callbacks

Often times you might need to conditionally render logic much as you would elsewhere in a Rails app. Luckily, Active Record Callbacks make this quite easy.

You can accomplish conditional callbacks in a few ways. The first is with `:if` or `:unless` as a Symbol. This approach makes for quite legible code.

```ruby
# Using :if and :unless with a Symbol
class Order < ApplicationRecord
  before_save :normalize_card_number, if: :paid_with_card?

  paid_with_card?
   # ...
  end
end
```

If you have multiple conditions or callbacks you can opt for more logic but the readability gets more complicated.

```ruby
class Comment < ApplicationRecord
  after_create :send_email_to_author, if: :author_wants_emails?,
    unless: Proc.new { |comment| comment.article.ignore_comments? }
end
```

If there's a bunch of logic to account for it might make sense to extract it to a new Ruby class.

```ruby
class PictureFileCallbacks
  def self.after_destroy(picture_file)
    if File.exist?(picture_file.filepath)
      File.delete(picture_file.filepath)
    end
  end
end

class PictureFile < ApplicationRecord
  after_destroy PictureFileCallbacks
end
```

Hopefully, this guide opened your eyes a bit to how Active Record Callbacks can enhance your toolkit. I find myself using many of these with conditional logic around background jobs, authentication, and more. The possibilities are endless here. I'd aim to use callbacks sparingly where possible. Having too much logic transpiring when modifying objects can get tedious and sometimes slow down your app.

If you enjoyed this guide you might also like:

- [Understanding Active Record Associations](https://web-crunch.com/posts/understanding-active-record-associations)
- [Understanding the Asset Pipeline in Ruby on Rails](https://web-crunch.com/posts/understanding-asset-pipeline-ruby-on-rails)
- [Understanding Active Record Migrations](https://web-crunch.com/posts/understanding-active-record-migrations)
- [Understanding Ruby on Rails ActiveRecord Validations](https://web-crunch.com/posts/understanding-active-record-migrations)
- [Understanding the Ruby on Rails CLI](https://web-crunch.com/posts/understanding-the-ruby-on-rails-cli)

or more from our [Ruby on Rails collection](https://web-crunch.com/collections/ruby-on-rails)