-
-
Save Spaceghost/25b9ff8616b3d35f8d39 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
commit 95bcc8ac6463e63001b33094ede2e21796da6c23 | |
Author: Johnneylee Jack Rollins <Johnneylee.Rollins@gmail.com> | |
Date: Mon Jun 30 07:17:59 2014 -0700 | |
Add Callable and Bindable for services/controllers | |
* Callable depends on the extending class implementing #call as an | |
instance method. Another instance method name might be preferable, I | |
don't know. I've even seen fun dynamic things like `extend | |
Callable.call_method(:execute)` | |
* Bindable handles adding listeners with #bind as well as doing too much | |
with implementing #success and #failure. These depend on any object | |
calling #bind also implementing these methods. | |
The virtues of this kind of decoupling is that there's two separate | |
minimal APIs, those being Callable and Bindable. The collaborators are | |
fully decoupled from each other and will only receive hashes of data | |
that /should/ be fit for some kind of consumption. At this point, I | |
would add view objects, but that's not important here. | |
The coupling moves from interface to data, but only temporarily until I | |
find a nice way to pass data from a controller to a kind of locator | |
object that gets view objects and injects them with data based on what I | |
assume would be hashes or a hash interface. | |
With all that said, please disregard the coupling of the actual response | |
hash. If you'd like to see what I'd do to clean that up, I'd love to | |
show you. | |
Signed-off-by: Johnneylee Jack Rollins <Johnneylee.Rollins@gmail.com> |
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
commit 8c602fce61d92189afe0b5845761c4bbba47fedb | |
Author: Johnneylee Jack Rollins <Johnneylee.Rollins@gmail.com> | |
Date: Mon Jun 30 08:33:10 2014 -0700 | |
Clean Callback interface | |
* Removing the unnecessary callback methods #successful and #failure | |
allows the controller in this example to pass blocks which are called | |
in the context of the controller closure style from within the | |
response data from the service object. | |
I included an example where the controller would call a method on some | |
objects returned within the response data, which I feel a bit unsure | |
about, but wanted to show some flexibility. | |
My goal here is to have the controller extract data useful for forming | |
the http response. Perhaps the service or application entrypoint could | |
return some kind of status, be it a 1:1 mapping to HTTP or not, and a | |
dependency on #errors. Perhaps a proper response object is in order, one | |
that implements a hash like interface as well as implements methods such | |
as #errors and #status. The rest should be passed to objects responsible | |
for rendering the rest of the data. | |
Signed-off-by: Johnneylee Jack Rollins <Johnneylee.Rollins@gmail.com> |
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
module Bindable | |
def bind(*subscribers, &block) | |
subscribers.each do |subscriber| | |
subscriber.tap(&block) | |
end | |
end | |
end | |
module Callable | |
def call(*args, **kwargs) | |
raise NotImplementedError, "#{self.inspect} must implement #call" unless self.instance_methods.include?(:call) | |
new.call(*args, **kwargs) | |
end | |
alias_method :call, :[] | |
end | |
class UserCreator | |
extend Callable | |
include Bindable | |
def call(**attributes) | |
user = User.new(attributes).save | |
if user.errors.none? | |
success(user: user) | |
else | |
failure(user: user) | |
end | |
end | |
end |
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 UsersController < ApplicationController | |
def create | |
UserCreator.call(user_params).bind(self) do |data| | |
{ head :bad_request } unless data[:orders] | |
{ redirect_to ticket_thank_you_path(invoice_id: invoice_id) } if data[:orders].any? &:free? | |
{ redirect_to checkout_orders_path, flash: { errors: data[:errors] } } if data[:errors].any? | |
end | |
end | |
private | |
def user_params | |
params.require(:user).permit(:foo, :bar) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment