Ruby on Rails ActiveRecord Callbacks
Tags: rails, activerecord, ruby, callbacks
Published: 2022-07-05 23:54:48

Callbacks are a way that ActiveRecord gives us to intervene in an object's life cycle.
It's almost like it pauses before or after key moments in its internal processes, to check in with you to see if you have code customization that you'd like to run before it continues. It allows you then to run code automatically before or after an Active Record object is created, saved, updated, deleted, validated, or loaded from the database.

We could use this callbacks to perform various tasks:

- Set values for the current record
- Create, update or destroy other records
- Perform cleanup and housekeeping tasks
- Log information
- Send an email or make an API call

**The order of callbacks is `before`, `around`, `after`.**

**`before`**: happens before the action happens

**`around`**: can have logic before and after the action being run. The code before yield is invoked before the action and the code after is called after the action

example:

```ruby
around_create :method_name

def method_name
  logger.info('Before action code')
  yield
  logger.info('After action this will run')
end
```

**`after`** : runs after an action is complete 

**Here is a list of Rails inbuilt Active Record Callback methods:**

### Creating an Object

- `before_validation`  Defines a callback that will get called right before validation.
- `after_validation`  Defines a callback that will get called right after validation.
- `before_save`  Registers a callback to be called before a record is saved.
- `around_save`  Registers a callback to be called around the save of a record.
- `before_create`  Registers a callback to be called before a record is created.
- `around_create`  Registers a callback to be called around the creation of a record.
- `after_create`  Registers a callback to be called after a record is created.
- `after_save`  Registers a callback to be called after a record is saved.
- `after_commit`  This callback is called after a record has been created, updated, or destroyed. Example: `after_commit :do_baz, on: :destroy`  `after_commit :do_bar_baz, on: [:update, :destroy]`
    - `after_create_commit`: Shortcut for `after_commit :hook, on: :create`
    - `after_destroy_commit`: Shortcut for `after_commit :hook, on: :destroy`
    - `after_save_commit`:  Shortcut for `after_commit :hook, on: [ :create, :update ]`
    - `after_update_commit`: Shortcut for `after_commit :hook, on: :update`
- `after_rollback`  This callback is called after a create, update, or destroy are rolled back. Note that all options of `after_commit` works for `after_rollback` too.

### Updating an Object

- `before_validation`
- `after_validation`
- `before_save`
- `around_save`
- `before_update`  Registers a callback to be called before a record is updated.
- `around_update`  Registers a callback to be called around the update of a record.
- `after_update`  Registers a callback to be called after a record is updated.
- `after_save`
- `after_commit` / `after_rollback`

### Destroying an Object

- `before_destroy`  Registers a callback to be called before a record is destroyed.
- `around_destroy`  Registers a callback to be called around the destruction of a record.
- `after_destroy`  Registers a callback to be called after a record is destroyed.
- `after_commit` / `after_rollback`

## Use Callbacks to Automate Actions

In order to use the available callbacks, you need to register them. You can implement the callbacks as ordinary methods and use a macro-style class method to register them as callbacks:

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

  before_validation :ensure_login_has_a_value

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

The macro-style class methods can also receive a block. Consider using this style if the code inside your block is so short that it fits in a single line:

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

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

Callbacks can also be registered to only fire on certain life cycle events:

```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
```

## Conditional Callbacks

By default callbacks will run all the time at the point at which you've registered them to execute. But we can also execute callbacks conditionally. You can tell your model to execute callback methods only when a particular condition is met.

We can do this by using the following options:

- `:if`
- `:unless`

Here are few examples:

```ruby
class User < ApplicationRecord
  validates :name, presence: true, if: :admin?

  def admin?
    conditional here that returns boolean value
  end
end
```

```ruby
# For negative conditional you can use unless
class User < ApplicationRecord
  validates :first_name, presence: true, unless: Proc.new { |user| user.last_name.present? }
end
```

```ruby
# You can also pass a string, which will be executed via instance_eval
class User < ApplicationRecord
  validates :first_name, presence: true, if: 'last_name.blank?'
end
```

## Skipping Callbacks

Every now and then it's useful to be able to skip callbacks specially when we just have to update . 

The first way is that if you have an instance of an object and you want to update it, you can call `update_column` or `update_columns`, or if you want to get rid of an object without having any callbacks, you can call `delete`. Normally the method we use is destroy. Destroy does activate our callbacks, but delete does not. The reason these three methods skip our callbacks is because all three of them, construct SQL to submit directly to the database.
**Usage:**

```ruby
instance.update_column(name, value)
instance.update_columns(name => value, name => value)
instance.delete
```

The other way we skip callback is if we have an ActiveRecord relation. We can either call **update_all** or **delete_all** on those relations.

**Usage:**

```ruby
relation.update_all
# example:
Product.where("modified_at < ?", 2.years.ago).update_all(active: false)

relation.delete_all
# example:
Product.where("created_at < ?", 5.years.ago).delete_all
```

**Note:** You can also use conditional callbacks to skip a callback for part of the business logic of your application.

> Thanks For Reading, Follow Me For More
> Share your suggestions, doubts and feedback in the comments section!