“...I've been working since 2008 with Ruby / Ruby on Rails, love a bit of Elixir / Phoenix and learning Rust. I also poke through other people's code and make PRs for OpenSource Ruby projects that sometimes make it. Currently working for InPay...”

Rob Lacey (contact@robl.me)
Senior Software Engineer, Brighton, UK

ActiveSupport.halt_callback_chains_on_return_false = false

Finally getting to upgrading to Rails 5.1 and there are lots of cases where we use before_* callbacks to block behaviour, most often in before_destroy to prevent a record being deleted when some conditions are met / not met. Previously Rails 5.1 allowed you to just return false in a callback to halt the callback chain. Now you must use throw(:abort).

The behaviour change was turned off by default in Rails 5.0

ActiveSupport.halt_callback_chains_on_return_false = true

So you can implement the change sooner by changing that setting in an initializer.

class Thing < ApplicationRecord
  before_create do
    throw(:abort)
  end

  before_destroy do
    throw(:abort)
  end
end

I thought initially this would result in having to cope with exceptions raised from throwing that abort rather than say checking if object.destroy returned false. However, it seems it’s just a clarification of behaviour to avoid accidental blocking.

2.3.0 :006 > Thing.create.persisted?
   (0.1ms)  BEGIN
   (0.1ms)  ROLLBACK
 => false 
2.3.0 :007 > reload!
Reloading...
 => true 
2.3.0 :008 > Thing.create.persisted?
   (0.1ms)  BEGIN
  SQL (0.3ms)  INSERT INTO `things` (`created_at`, `updated_at`) VALUES ('2019-01-17 08:38:24', '2019-01-17 08:38:24')
   (0.5ms)  COMMIT
 => true 
2.3.0 :009 > Thing.last.destroy
  Thing Load (0.3ms)  SELECT  `things`.* FROM `things` ORDER BY `things`.`id` DESC LIMIT 1
   (0.1ms)  BEGIN
   (0.1ms)  ROLLBACK
 => false 
2.3.0 :010 > reload!
Reloading...
 => true 
2.3.0 :011 > Thing.create.persisted?
   (0.1ms)  BEGIN
  SQL (0.2ms)  INSERT INTO `things` (`created_at`, `updated_at`) VALUES ('2019-01-17 08:39:29', '2019-01-17 08:39:29')
   (21.0ms)  COMMIT
 => true 
2.3.0 :010 > reload!
Reloading...
2.3.0 :014 > Thing.last.destroy
  Thing Load (0.1ms)  SELECT  `things`.* FROM `things` ORDER BY `things`.`id` DESC LIMIT 1
   (0.1ms)  BEGIN
  SQL (0.2ms)  DELETE FROM `things` WHERE `things`.`id` = 2
   (0.6ms)  COMMIT
 => #<Thing id: 2, created_at: "2019-01-17 08:39:29", updated_at: "2019-01-17 08:39:29">

Hopefully this won’t be too painful an exercise.