-
Notifications
You must be signed in to change notification settings - Fork 2
Service Objects
cavalle edited this page Dec 23, 2012
·
28 revisions
http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/
class UserAuthenticator
def initialize(user)
@user = user
end
def authenticate(unencrypted_password)
return false unless @user
if BCrypt::Password.new(@user.password_digest) == unencrypted_password
@user
else
false
end
end
endclass SessionsController < ApplicationController
def create
user = User.where(email: params[:email]).first
if UserAuthenticator.new(user).authenticate(params[:password])
self.current_user = user
redirect_to dashboard_path
else
flash[:alert] = "Login failed."
render "new"
end
end
endhttp://jamesgolick.com/2010/3/14/crazy-heretical-and-awesome-the-way-i-write-rails-apps.html
class UserCreationService
def initialize(user_klass = User, log_klass = Log)
@user_klass = user_klass
@log_klass = log_klass
end
def create(params)
@user_klass.create(params).tap do |u|
@log_klass.new_user(u)
end
end
enddescribe UserCreationService do
before do
@user = stub("User")
@user_klass = stub("Class:User", :create => @user)
@log_klass = stub("Class:Log", :new_user => nil)
@service = UserCreationService.new(@user_klass, @log_klass)
@params = {:name => "Matz", :hobby => "Being Nice"}
@service.create(@params)
end
it "creates the user with the supplied parameters" do
@user_klass.should have_received(:create).with(@params)
end
it "logs the creation of the user" do
@log_klass.should have_received(:new_user).with(@user)
end
endclass User < ActiveRecord::Base
after_create :log_creation
protected
def log_creation
Log.new_user(self)
end
endhttp://www.naildrivin5.com/blog/2012/06/10/single-responsibility-principle-and-rails.html
class ApplicationUserCreator
def initialize(welcome_mailer=nil)
@welcome_mailer = welcome_mailer
end
def create_new_user(params)
User.create(params).tap { |new_user|
if new_user.valid?
self.welcome_mailer.deliver_welcome_email(new_user)
end
}
end
private
def welcome_mailer
@welcome_mailer ||= UserMailer
end
endclass AdminUsersController < ApplicationController
def create
@user = ApplicationUserCreator.new(AdminUserMailer).create_new_user(params[:user])
end
endclass UsersController < ApplicationController
def create
@user = User.new(params[:user])
respond_to do |format|
if @user.save
UserMailer.deliver_welcome_email(@user)
end
end
end
endhttp://slides.jcoglan.com/di-eurucamp
class Github::Client
def initialize(http_client)
@http = http_client
end
def get_user(name)
data = @http.get("/users/#{name}").json_data
Github::User.new(data)
end
end(Service layer)
http://slides.jcoglan.com/di-eurucamp
class Services::ConcertsClient
def initialize(http_client)
@http = http_client
end
def find(id)
data = @http.get("/concerts/#{id}").json_data
Models::Concert.new(data)
end
endclass Models::Concert
def initialize(data)
@json_data = data
end
def name
@json_data['name']
end
def headliners
@json_data['performances'].
select { |p| p['billing'] == 'headline' }.
map { |p| Models::Artist.new(p['artist']) }
end
endmodule Services
def self.concerts
@concerts ||= begin
uri = 'http://concerts-service'
http = HTTPClient.new(uri)
ConcertsClient.new(http)
end
end
endconcert = Services.concerts.find(params[:id])- https://speakerdeck.com/seenmyfate/4-steps-to-faster-rails-tests
- http://confreaks.com/videos/641-gogaruco2011-fast-rails-tests
class DiscountCalculator
def total_discount(items)
items.collect(&:discount).inject(:+)
end
endclass Basket < ActiveRecord::Base
has_many :basket_items
def total_discount
DiscountCalculator.new.total_discount(basket_items)
end
end(Use case objects)
https://gist.github.com/2838490
class PostComment
def initialize(user, entry, attributes)
@user = user
@entry = entry
@attributes = attributes
end
def post
@comment = @user.comments.new
@comment.assign_attributes(@attributes)
@comment.entry = @entry
@comment.save!
LanguageDetector.new(@comment).set_language
SpamChecker.new(@comment).check_spam
CommentMailer.new(@comment).send_mail
post_to_twitter if @comment.share_on_twitter?
post_to_facebook if @comment.share_on_facebook?
@comment
end
private
def post_to_twitter
PostToTwitter.new(@user, @comment).post
end
def post_to_facebook
PostToFacebook.new(@user, @comment).action(:comment)
end
end