Last active
August 29, 2015 13:56
-
-
Save adamcooper/9262267 to your computer and use it in GitHub Desktop.
Sample Service Base Class and Result Class
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 UserController < ActionController::Base | |
def new | |
@user = User.new | |
end | |
def create | |
result = SignupUser.call(params[:user]) | |
if result.successful? | |
redirect_to root_url, notice: "A welcome e-mail is on it's way!" | |
else | |
@user = result.user | |
render | |
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 SignupUser < Service::Call | |
attribute :name, String | |
attribute :email, String | |
attribute :wants_email, Boolean, default: ->(signup_user, attribute) { true } | |
class Result < Service::Result | |
attribute :user, User | |
end | |
def call | |
user = User.new(name: name, email: email, accepts_email: wants_email) | |
result.user = user | |
if user.save | |
UserMailer.welcome_email(user.email).deliver | |
result.successful! | |
else | |
result.add_errors(user) | |
end | |
result | |
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 Service::Call | |
include Virtus.model | |
attribute :result, Service::Result, default: ->(service,_) { service.build_result } | |
def self.call(*args) | |
new(*args).call | |
end | |
protected | |
def build_result | |
klass = self.class.const_get("Result") rescue Service::Result | |
klass.new | |
end | |
def with_exception_catching | |
begin | |
yield | |
rescue StandardError => exception | |
result.exception = exception | |
result.add_errors(exception.record) if exception.respond_to?(:record) | |
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 Service::Result | |
include Virtus.model | |
attribute :status, String, default: Status::ERROR | |
attribute :errors, Object, default: ->(sr,_) { ActiveModel::Errors.new(sr) } | |
attribute :exception, StandardError | |
module Status | |
SUCCESSFUL = 'successful' | |
ERROR = 'error' | |
end | |
def successful!; self.status = Status::SUCCESSFUL; self; end | |
def successful?; self.status == Status::SUCCESSFUL; end | |
def error!; self.status = Status::ERROR; self; end | |
def error?; self.status == Status::ERROR; end | |
def add_error_message(message) | |
errors.add(:base, message) | |
end | |
def add_errors(obj_with_errors) | |
Array(obj_with_errors).each do |obj| | |
self.errors.messages.merge!(obj.errors) unless obj.errors.empty? | |
end | |
end | |
def add_errors_or_be_successful!(obj_with_errors) | |
add_errors(obj_with_errors) | |
successful! if errors.empty? | |
self | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey Adam,
Just FYI, I had to have Service::Result extend ActiveModel::Translation in Rails 4.x in order for stuff like add_errors to work properly. I was getting "undefined method `human_attribute_name'". Just thought I'd add that here in case it helps someone out.