0

Imagine that you have a context that handles money transfers between user's accounts.

class Account < ActiveRecord::Base
  belongs_to :user
end

class MoneySender < SimpleDelegator

  class NotEnoughBalanceError < StandardError ; ; end

  def initialize(account)
    super(account)
  end

  def send_money(destination_account, amount)
    raise NotEnoughBalanceError unless can_send?(amount)
    self.transaction do
      self.balance -= amount
      destination_account.balance += amount
    end
    self.balance
  end

  def can_send?(amount)
    self.balance >= amount
  end

end

class HandleMoneyTransferContext

  def initialize(source, destination, amount)
    @source = source
    @destination = destination
    @amount = amount
  end

  def transfer
    sender = MoneySender.new(@source
    sender.send_money(@destination, @amount)
  end

end

And money transfers are triggered by a web application and the rails controller that handle that operations does something like this

class AccountsController < AplicationController

  def transfer
    source = Account.find(params[:id])
    destination = Account.find(params[:destination_account])
    HandleMoneyTransferContext.new(source, destination, params[:amount]).transfer
    render 'success_page'
  rescue MoneySender::NotEnoughBalanceError => e
    flash[:error] = t(accounts.transfer.not_enough_money)
    render 'error_page', status: 400
  end

end

So my question is, Is it OK for a context to raise exceptions? Should I catch the Role exception in the context and raise a context exception? (Context users should not know which roles are being used), Is there a better solution?

Thanks

GuidoMB
  • 2,191
  • 3
  • 25
  • 40

1 Answers1

0

A context is just an object (yes there are constraints so not all objects are contexts) and within an operation of an object some exceptions are in order. Eg an ArgumentNil could be valid if what should have been a RolePlayer is nil instead. So to answer your question. So yes a context can throw exceptions if they are related to the system operation(s) the context encapsulates.

That said I don't see much DCI in your example code. Eg there no role methods in the context and it would seem the actual behavior belongs to a class and neither a role or an object. There's a money transfer example on fulloo.info as well as one of the examples for the maroon gem. You can read more on using maroon to do DCI in ruby (Though the syntax has been simplified since the writing of that article together with the examples it should still be a good starting point)

Rune FS
  • 21,497
  • 7
  • 62
  • 96