Skip to content

Instantly share code, notes, and snippets.

@ntl
Last active August 29, 2015 13:57
Show Gist options
  • Save ntl/9469917 to your computer and use it in GitHub Desktop.
Save ntl/9469917 to your computer and use it in GitHub Desktop.
In my usage so far, an "Event" doesn't get its own type; it's an object that transports attributes. The listeners also use a class method to route events to methods on the object. In this way, you can test event handlers as you would any other ruby method.
# app/commands/receive_bonus_command.rb
# Commands look like ActiveModel+virtus "ish" objects
class ReceiveBonusCommand < Command
attribute :income_source_id, String
attribute :bonus_amount, Integer
attribute :effective_date, Date
validates :account_id, presence: true
def validate
unless effective_date > Date.current
errors[:effective_date] << "must be in the future"
end
end
def apply
# Email the user congratulations; we wouldn't want to resend this
# email if we replay the :received_bonus event.
CongratulationsMailer.deliver(self)
# Because Command's initialize method asks for an event_store, IoC
# container (ruse) injected it in for us.
event_store.fire(
:received_bonus,
payload: {
income_source_id: income_source_id,
bonus_amount: bonus_amount,
effective_date: effective_date,
}
)
end
end
# app/models/income_source.rb
class IncomeSource < Entity
attribute :compensation_changes, Array[CompensationChange]
# In practice, since the event's payload has a property called
# income_source_id, and the name of this aggregate root is
# IncomeSource, listen can automatically fetch an instance from
# the repo. Here, the .listen class macro is actually wired up
# to glue code between the Entity class and the EventStore.
listen received_bonus: 'handle_received_bonus',
instantiate: ->(event) { repository.find(event.payload.income_source_id) }
def handle_received_bonus(event)
comp_change = CompensationChange.new(
date: event.effective_date,
amount: event.bonus_amount,
)
self.compensation_changes << comp_change
repository.store self
end
end
@ntl
Copy link
Author

ntl commented Mar 10, 2014

The use of Entity.listen in IncomeSource is explicitly telling the framework how to fetch the particular IncomeSource instance that wants to listen on the :received_bonus event. In practice, I can omit passing the proc via instantiate since I followed the convention of naming the id after the model. I wanted to be explicit in this example, so you can follow how everything is intended to work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment