TL;DR
class User < ActiveRecord::Base
before_save { |u| u.admin ||= false }
end
User.create!
#=> ActiveRecord::RecordNotSaved
Rails 4
User.create!
#=> true
Rails 5
2/18
Slide 3
Slide 3 text
Halting the chain
3/18
class User < ActiveRecord::Base
before_save :set_default_values
def set_default_values
self.admin ||= false
end
end
Slide 4
Slide 4 text
Halting the chain
class User < ActiveRecord::Base
before_save :set_default_values
def set_default_values
self.admin ||= false
# return true || false => true
end
end
User.create!(admin: true)
#=> true
4/18
Slide 5
Slide 5 text
Halting the chain
class User < ActiveRecord::Base
before_save :set_default_values
def set_default_values
self.admin ||= false
# return nil || false => false
end
end
User.create! # Rails 4
#=> ActiveRecord::RecordNotSaved
5/18
Slide 6
Slide 6 text
Rails 4: implicit
If a before_* callback returns false,
all the later callbacks and the
associated action are cancelled.
If an after_* callback returns false,
all the later callbacks are cancelled.
‛ Rails 4.2 API doc
6/18
Slide 7
Slide 7 text
Rails 5: explicit
If a before_* callback throws :abort,
all the later callbacks and the
associated action are cancelled.
‛ PR #17227
7/18
Slide 8
Slide 8 text
Rails 5: explicit
class User < ActiveRecord::Base
before_save :set_default_values
def set_default_values
self.admin ||= false
# returned value DOES NOT MATTER
end
end
User.create! # Rails 5
#=> true
8/18
Slide 9
Slide 9 text
Rails 5: explicit
class User < ActiveRecord::Base
before_save :ensure_admin
def ensure_admin
throw(:abort) unless self.admin
# returned value DOES NOT MATTER
end
end
User.create! # Rails 5
#=> ActiveRecord::RecordNotSaved
9/18
Slide 10
Slide 10 text
Deprecation policy
If a before_* callback returns false
✦ Rails 4: the chain halts
✦ Rails 4 apps ported to Rails 5:
the chain halts with a warning
✦ Rails 5: the chain is unaffected
10/18
Slide 11
Slide 11 text
Deprecation policy
✦ Rails 4: the chain halts
✦ Rails 4 apps ported to Rails 5:
the chain halts with a warning
✦ Rails 5: the chain is unaffected
11/18
If a before_* callback returns false
Slide 12
Slide 12 text
Deprecation policy
User.create! # Rails 4 app ported to 5
# DEPRECATION WARNING: Returning `false`in a
callback will not implicitly halt a callback chain
in the next release of Rails. To explicitly halt a
callback chain, please use `throw :abort` instead.
#=> ActiveRecord::RecordNotSaved
12/18
class User < ActiveRecord::Base
before_save { |u| u.admin ||= false }
end
Slide 13
Slide 13 text
Deprecation policy
# config/initializers/callback_terminator.rb
ActiveSupport.halt_callback_chains_on_retu
rn_false = false
13/18
class User < ActiveRecord::Base
before_save { |u| u.admin ||= false }
end
User.create!
#=> true
Slide 14
Slide 14 text
TL;DR
class User < ActiveRecord::Base
before_save { |u| u.admin ||= false }
end
User.create!
#=> ActiveRecord::RecordNotSaved
Rails 4
User.create!
#=> true
Rails 5
14/18
Slide 15
Slide 15 text
Extra: even better!
class MeController < ApplicationController
skip_before_action :unknown_method
end
User.create!
#=> ActiveRecord::RecordNotSaved
15/18
‛ PR #19029
GET "/me" at 2015-04-21 15:00:00 -0500
#=> ArgumentError
Before process_action callback
:unknown_method has not been defined
Slide 16
Slide 16 text
Extra: even better!
class MeController < ApplicationController
skip_action_callback :authenticate
end
User.create!
#=> ActiveRecord::RecordNotSaved
16/18
‛ PR #19060
GET "/me" at 2015-04-21 15:00:00 -0500
#=> DEPRECATION WARNING
skip_action_callback is deprecated and
will be removed in the next major version
Slide 17
Slide 17 text
Extra: even better!
class User < ActiveRecord::Base
after_commit { raise StandardError }
end
User.create!
#=> ActiveRecord::RecordNotSaved
17/18
‛ PR #18325
User.create!
# DEPRECATION WARNING: Currently, Active Record
suppresses errors raised within after_commit. You
can opt into the new behavior by setting...
#=> StandardError
Slide 18
Slide 18 text
‛ speakerdeck.com/claudiob
Backs
BETTER
CALL
in Rails 5