Created
October 24, 2015 20:21
-
-
Save bestie/c640208979e469e67acb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ApplicationController | |
private | |
def core_application | |
CoreApplication.new | |
end | |
def adapter | |
RailsAdapter.new(self) | |
end | |
def current_user_id | |
session["user_id"] | |
end | |
def not_found | |
# render a custom page or override and handle polymorphically | |
end | |
end | |
class FollowsController < ApplicationController | |
def create | |
core_application.create_follow(adapter) | |
end | |
def render(args) | |
# For legacy reasons the same template for Javascript is rendered for all | |
# follow operations. This is a good example of customizing delivery | |
# mechanism concerns on a controller by controller basis. | |
super(args.merge(file: "update_follow_link")) | |
end | |
end | |
require "forwardable" | |
class RailsAdapter | |
extend Forwardable | |
def initialize(controller) | |
@controller = controller | |
end | |
attr_reader :controller | |
private :controller | |
def_delegators :params, :fetch | |
def_delegators :controller, :not_found, :current_user_id | |
def params | |
@params ||= controller.params.to_hash | |
end | |
# Here we handle our app's legacy response concerns: | |
# Sometimes we wish to perform a straight render for objects that we can show | |
# on a dedicated page. | |
def success_and_show(payload) | |
controller.render(locals: payload) | |
end | |
# For objects without dedicated pages, likes and follows for example, we | |
# either redirect back or update the page with some JavaScript depending on | |
# the client's capability. | |
def success_and_stay(payload) | |
controller.respond_to do |format| | |
format.html { controller.redirect_back } | |
format.js { controller.render(locals: payload) } | |
end | |
end | |
end | |
class CoreApplication | |
def create_follow(delivery) | |
with_user(delivery.current_user_id, not_found: not_found(delivery)) { |follower| | |
with_user(delivery.fetch("followed_id"), not_found: not_found(delivery)) { |followed| | |
# Here we take advantage of blocks and lexical scoping to layer up | |
# multiple find operations, unburdening the use case object from | |
# finding its two users. | |
CreateFollowing.new( | |
follower: follower, | |
followed: followed, | |
responder: delivery, | |
).call | |
} | |
} | |
end | |
private | |
def not_found(delivery) | |
delivery.method(:not_found) | |
end | |
# This application is still using ActiveRecord and has no repository layer. | |
# Defining a few methods like this will work for a while until repositories | |
# are extracted. | |
def with_user(id, not_found:, &success) | |
user = User.find_by_id(id) | |
if user | |
success.call(user) | |
else | |
not_found.call | |
end | |
end | |
end | |
class CreateFollowing | |
def initialize(follower:, followed:, responder:) | |
@follower = follower | |
@followed = followed | |
@responder = responder | |
end | |
attr_reader :follower, :followed, :responder, :follow | |
private :follower, :followed, :responder, :follow | |
def call | |
# We are sure that we have two users here so not too much can go wrong | |
create_follow | |
respond_successfully | |
end | |
private | |
def create_follow | |
@follow ||= follower.follow(followed) | |
end | |
def respond_successfully | |
responder.success_and_stay(follow: follow) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment