Dealing with Service Objects

Dealing with Service Objects

Conversation starter about working with service objects in Rails, given at Ruby/Rails Sofia meetup

7a0e72a6f55811246bb5d9a946fd2e49?s=128

Radoslav Stankov

November 24, 2016
Tweet

Transcript

  1. Dealing with Service Objects Radoslav Stankov 23/11/2016

  2. Radoslav Stankov @rstankov http://rstankov.com http://github.com/rstankov

  3. https://www.youtube.com/watch?v=p5EIrSM8dCA

  4. None
  5. None
  6. None
  7. None
  8. None
  9. https://www.youtube.com/watch?v=v6UhbI84nmA

  10. None
  11. None
  12. None
  13. None
  14. None
  15. ActiveRecord Objects

  16. ActiveRecord Objects Other
 Objects Other
 Objects Other
 Objects Other
 Objects

    Other
 Objects Other
 Objects Other
 Objects
  17. Service Objects

  18. UseCase Objects

  19. Interactors Objects

  20. Operation Objects

  21. module DoStuff extend self def call(...) ... end private ...

    end
  22. module UserDeactivator extend self def call(user, active: active) return if

    user.active == active user.update! active: active user.posts.update_all active: active user.votes.update_all active: active user.comments.update_all active: active user.following_association.update_all active: active user.followers_association.update_all active: active end end
  23. Validations?

  24. module SendPrivateMessage extend self def call(message, recipient, sender) return :invalid

    unless recipient.present? return :invalid unless recipient.receive_private_messages? message = Message.new message, sender, recipient return :not_saved unless message.save MessageMailer.user_message(message).deliver_later Metrics.track_create message, by: sender :success end end
  25. Forms?

  26. class RegistrationController < ApplicationController def create @user = User.new(user_params) @user.account

    = Account.new(account_params) @user.account.owner = @user if @user.valid? && @user.account.valid? @user.save! @user.account.save! AccountWasCreated.perform_later(account) redirect_to user_path(@user) else render :new end end end
  27. class RegistrationController < ApplicationController def create @registration = RegistrationForm.new(registration_params) if

    @registration.save redirect_to user_path(@registration.user) else render :new end end end
  28. class RegistrationController < ApplicationController def create @registration = RegistrationForm.new(registration_params) @registration.save

    respond_with @registration end end
  29. class RegistrationForm include ActiveModel::Model attr_reader :user, :account attr_accessor :first_name, :last_name,

    :email, :name, :plan, :te # user validation validates :first_name, presence: true validates :last_name, presence: true validates :email, presence: true, email: true # account validation validates :account_name, presence: true # form custom validation validates :plan, inclusion: {in AccountPlan::VALUES} validates :terms_of_service, acceptance: true # ensure uniqueness
  30. validates :account_name, presence: true # form custom validation validates :plan,

    inclusion: {in AccountPlan::VALUES} validates :terms_of_service, acceptance: true # ensure uniqueness validate :ensure_unique_user_email validate :ensure_unique_account_name def initialize @user = User.new @account = Account.new owner: @user end def update(attributes) attributes.each do |name, value| public_send "#{name}=", value end if valid? & user.update(user_attributes) && account.update(acco account.users << user AccountWasCreated.perform_later(account) else
  31. def update(attributes) attributes.each do |name, value| public_send "#{name}=", value end

    if valid? & user.update(user_attributes) && account.update(acco account.users << user AccountWasCreated.perform_later(account) else false end end private def ensure_unique_user_email errors.add :email, 'already taken' if User.where(email: email). end def ensure_unique_account_name errors.add :name, 'already taken' if Account.where(name: name). end
  32. else false end end private def ensure_unique_user_email errors.add :email, 'already

    taken' if User.where(email: email). end def ensure_unique_account_name errors.add :name, 'already taken' if Account.where(name: name). end def user_attributes {first_name: first_name, last_name: last_name, email: email} end def account_attributes {plan: plan, name: name} end end
  33. https://github.com/RStankov/MiniForm

  34. class RegistrationForm include MiniForm::Model model :user, attributes: %i(first_name last_name email),

    save: t model :account, attributes: %i(name plan), save: true attributes :terms_of_service validates :plan, inclusion: {in AccountPlan::VALUES} validates :terms_of_service, acceptance: true def initialize @user = User.new @account = Account.new owner: @user end def perform account.users << user AccountWasCreated.perform_later(account) end end
  35. Readability?

  36. Authorization?

  37. Pipelines?

  38. Trailbrazer? http://trailblazer.to/gems/operation/2.0/

  39. None