---
title: "Rails 5 doesn't halt callback chain if false is returned"
description:
  "Preferred way of halting callback chain in Rails 5 is now using throw(:abort)
  instead of returning false."
canonical_url: "https://www.bigbinary.com/blog/rails-5-does-not-halt-callback-chain-when-false-is-returned"
markdown_url: "https://www.bigbinary.com/blog/rails-5-does-not-halt-callback-chain-when-false-is-returned.md"
---

# Rails 5 doesn't halt callback chain if false is returned

Preferred way of halting callback chain in Rails 5 is now using throw(:abort)
instead of returning false.

- Author: Abhishek Jain
- Published: February 13, 2016
- Categories: Rails 5, Rails

Before Rails 5, returning `false` from any `before_` callback in `ActiveModel`
or `ActiveModel::Validations`, `ActiveRecord` and `ActiveSupport` resulted in
halting of callback chain.

```ruby

class Order < ActiveRecord::Base

  before_save :set_eligibility_for_rebate
  before_save :ensure_credit_card_is_on_file

  def set_eligibility_for_rebate
    self.eligibility_for_rebate ||= false
  end

  def ensure_credit_card_is_on_file
    puts "check if credit card is on file"
  end
end

Order.create!
=> ActiveRecord::RecordNotSaved: ActiveRecord::RecordNotSaved

```

In this case the code is attempting to set the value of `eligibility_for_rebate`
to false. However the side effect of the way Rails callbacks work is that the
callback chain will be halted simply because one of the callbacks returned
`false`.

Right now, to fix this we need to return `true` from `before_` callbacks, so
that callbacks are not halted.

## Improvements in Rails 5

Rails 5 fixed this issue [by adding](https://github.com/rails/rails/pull/17227)
`throw(:abort)` to explicitly halt callbacks.

Now, if any `before_` callback returns `false` then callback chain is not
halted.

```ruby

class Order < ActiveRecord::Base

  before_save :set_eligibility_for_rebate
  before_save :ensure_credit_card_is_on_file

  def set_eligibility_for_rebate
    self.eligibility_for_rebate ||= false
  end

  def ensure_credit_card_is_on_file
    puts "check if credit card is on file"
  end

end

Order.create!
=> check if credit card is on file
=> <Order id: 4, eligibility_for_rebate: false>

```

To explicitly halt the callback chain, we need to use `throw(:abort)`.

```ruby

class Order < ActiveRecord::Base

  before_save :set_eligibility_for_rebate
  before_save :ensure_credit_card_is_on_file

  def set_eligibility_for_rebate
    self.eligibility_for_rebate ||= false
    throw(:abort)
  end

  def ensure_credit_card_is_on_file
    puts "check if credit card is on file"
  end

end

Order.create!
=> ActiveRecord::RecordNotSaved: Failed to save the record

```

## Opting out of this behavior

The new Rails 5 application comes up with initializer named
`callback_terminator.rb`.

`ActiveSupport.halt_callback_chains_on_return_false = false`

By default the value is to set to `false`.

We can turn off this default behavior by changing this configuration to `true`.
However then Rails shows deprecation warning when `false` is returned from
callback.

```ruby

ActiveSupport.halt_callback_chains_on_return_false = true

class Order < ApplicationRecord
  before_save :set_eligibility_for_rebate
  before_save :ensure_credit_card_is_on_file

  def set_eligibility_for_rebate
    self.eligibility_for_rebate ||= false
  end

  def ensure_credit_card_is_on_file
    puts "check if credit card is on file"
  end
end

=> DEPRECATION WARNING: Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in the next release of Rails. To explicitly halt the callback chain, please use `throw :abort` instead.
ActiveRecord::RecordNotSaved: Failed to save the record

```

## How older applications will work with this change?

The initializer configuration will be present only in newly generated Rails 5
apps.

If you are upgrading from an older version of Rails, you can add this
initializer yourself to enable this change for entire application.

This is a welcome change in Rails 5 which will help prevent accidental halting
of the callbacks.

## Links

- [Human page](https://www.bigbinary.com/blog/rails-5-does-not-halt-callback-chain-when-false-is-returned)
