Slide 1

Slide 1 text

Better Callbacks in Rails 5 ‛ claudiob.github.io

Slide 2

Slide 2 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 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