Skip to content

Instantly share code, notes, and snippets.

@nicholasjhenry
Last active January 3, 2016 14:29
Show Gist options
  • Save nicholasjhenry/8476503 to your computer and use it in GitHub Desktop.
Save nicholasjhenry/8476503 to your computer and use it in GitHub Desktop.
Refactoring of a Policy example from DAS
# session_controller.rb
class SessionsController
def create
user = log_user_in
AccountStandingPolicy.new(@user).enforce!
end
end
# account_standing_policy.rb
class AccountStandingPolicy
def initialize(user)
@user = user
end
def valid?
@user.all_cards_invalid?
end
def enforce!
if valid?
@user.disable!
send_disable_notification!
end
end
def send_disable_notification!
# ...
end
end
# user.rb
class User
has_many :cards
def disable!
update_attribute(:enabled, false)
end
end
# session_controller.rb
class SessionsController
def create
authorize_user = AuthorizeUser.new
authorize_user.add_listener(
EnforceAccountStandingPolicy.new(
AccountStandingPolicy.new
DisableUser.new
)
)
end
end
# enforce_account_standing_policy.rb
class EnforceAccountStandingPolicy
def initialize(policy, service)
@policy, @service = policy, service
end
def login_successful(user)
enforce!(user)
end
private
def enforce!(user)
return if @policy.comply?(user)
@service.call(user)
end
end
# account_standing_policy.rb
class AccountStandingPolicy
def comply?(user)
user.all_cards_invalid?
end
end
# disable_user.rb
class DisableUser
def call(user)
disable_user!(user)
send_disable_notification!(user)
end
def disable_user!(user)
user.disable!
end
def send_disable_notification!(user)
#...
end
end
# controllers/session_controller.rb
class SessionsController < ApplicationController
def create
authorize_user = AuthorizeUser.new
authorize_user.add_listener(
EnforceAccountStandingPolicyService.build
)
end
end
# Services encapsulate application logic
#
# services/enforce_account_standing_policy_service.rb
class EnforceAccountStandingPolicyService < Service
# Factory method to setup dependencies
#
def build
self.new(
DisableUser.new(
AccountStandingPolicy.new
)
)
end
# TODO: can we inject multiple commands?
#
def initialize(command)
@command = command
end
def login_successful(user)
call(user)
end
private
def call(user)
@command.call(user)
send_disable_notification
end
def send_disable_notification!(user)
#...
end
end
# Commands encapsulate domain logic
#
# commands/disable_user.rb
class DisableUser
def initialize(policy)
@policy = policy
end
def call(user)
return if @policy.comply?(user)
user.disable!
end
end
# Policies reify business rules
#
# policies/account_standing_policy.rb
class AccountStandingPolicy
def comply?(user)
user.all_cards_invalid?
end
end
# Active record objects are treated as Row Data Gateway
#
# data/user.rb
class User < ActiveRecord::Base
def disable!
update(enable: false)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment