-
Notifications
You must be signed in to change notification settings - Fork 15
Refactoring examples
Benjamin Roth edited this page Nov 16, 2016
·
1 revision
- https://gist.github.com/apneadiving/b1e9d30f08411e24eae6
- https://gist.github.com/apneadiving/f1de3517a727e7596564
Lets check with the following example, with many different outcomes, which code is not that obvious to follow:
def submit_application
if current_user.confirmed?
if params[:terms_of_service]
application = current_user.build_application
if application.save
render json: { ok: true }
else
render_errors application.errors.full_messages
end
else
render_errors 'You must accept the terms'
end
else
render_errors 'You need to confirm your account first'
end
end
def render_error(errors)
render json: { errors: Array(errors) }, status: 422
end
Waterfall lets you write it this way:
def accept_group_terms
Wf.new
.when_falsy { current_user.confirmed? }
.dam { 'You need to confirm your account first' }
.when_falsy { params[:terms_of_service] }
.dam { 'You must accept the terms' }
.chain { @application = current_user.build_application }
.when_falsy { @application.save }
.dam { @application.errors.full_messages }
.chain { render json: { ok: true } }
.on_dam { |errors| render json: { errors: Array(errors) }, status: 422 }
end
This is maybe just fancy, but the real power of waterfall is: you can chain waterfalls, and this is where it begins to be great.
class AcceptInvitation
include Waterfall
include ActiveModel::Validations
attr_reader :token, :referrer
validates :referrer, presence: true
def initialize(referrer_id, token)
@referrer_id, @token = referrer_id, token
end
def call
self
.chain { @referrer = User.find_by(id: @referrer_id) }
.when_falsy { valid? }
.dam { errors }
.chain(invitee: :authenticated_user) { AuthenticateFromInvitationToken.new(token) }
.chain { |outflow| referrer.complete_affiliation_for(outflow[:invitee]) }
end
end
class AuthenticateFromInvitationToken
include Waterfall
include ActiveModel::Validations
attr_reader :token, :user
validates :user, presence: true
def initialize(token)
@token = token
end
def call
self
.chain { @user = User.from_invitation_token(token) }
.when_falsy { valid? }
.dam { errors }
.chain(:authenticated_user) { user }
end
end
# in controller
def accept_invitation
Wf.new
.chain(invitee: :invitee) { AcceptInvitation.new(params[:referrer_id], params[:token]) }
.chain do |outflow|
@invitee = outflow[:invitee]
render :invitation_form
end
.on_dam do |errors|
errors.full_messages.each {|error| flash[:error] = error }
redirect_to root_path
end
end