Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How I Learned to Stop Worrying and Love the Command Pattern
# looks like command to Create/Update/Delete(Publish, Reject and etc) and Query object
class Post < ActiveRecord::Base
before_validate :build_from_template # if update don't run
before_create :check_content_uniq # extremely long time also don't run on update
after_update :send_notification # sometimes don't run
after_create :add_editor # sometimes don't run, can touch another record that has callbacks too :D
after_save :broadcast # sometimes don't run
after_create :run_indexing # sometimes don't run
private
def build_from_template
# ...
end
def check_content_uniq
# ...
end
def send_notification
# ...
end
def add_editor
# ...
# update another record, that run callbacks too :D
end
def broadcast
# ...
end
def run_indexing
# ...
end
end
# this variant even better than fat model
class Post < ActiveRecord::Base
end
Class OrderController < ApplicationController
def edit
# many lines of code there
end
def create
# many lines of code there
end
def publish
# many lines of code there
end
def reject
# many lines of code there
end
end
class EntityController < ApplicationController
def create
op = EntityOperation::Create.new(params, current_user)
op.process
if op.success?
render json: op.result, status: :created
else
render json: { errors: op.result.errors }, status: :unprocessable_entity
end
end
end
module EntityOperation
class Create < EventSequence::Sequence
class SequenceSerializer < EventSequence::Serializer
RECORD_FIELDS = %i(id name order_id).freeze
end
def build_record(params)
params
end
class ChecPermissionsEvent < EventSequence::Event
def process(record)
end
def should?
true
end
end
def create_order(record)
record.save && record
end
def refetch_order(record)
record.reload
end
def on_fail(e)
puts "FailEvent #{e}"
end
class BroadcastSequence < EventSequence::Sequence::Low
def broadcast(props)
BroadcastService.new(props).process
end
end
class NotifySequence < EventSequence::Sequence::Low
def notify(props)
NotificationService.new(props).process
end
end
class FeedSequece < EventSequence::Sequence::Low
def populate_feed(props)
ActivityFeedService.new(props).create
end
end
class AfterAllSequence < EventSequence::Sequence::Low
def call_me_after_all(props)
puts "#{call_me_after_all} props"
end
def on_fail_after_all(e)
puts "After all fail #{e}"
end
sequence({
events: [:call_me_after_all],
fail: [:on_fail_after_all],
wait: [BroadcastSequence, FeedSequece, NotifySequence]
})
end
sequence({
events: [
:build_record,
ChecPermissionsEvent,
:create_order,
:refetch_order,
BroadcastSequence,
FeedSequece,
NotifySequence,
AfterAllSequence,
],
serializer: SequenceSerializer,
fail: [:on_fail]
})
end
end
module Api
class OrdersController < ApiController
def create
if Order::Create.new(@order, current_user, order_params).process
render json: @order, status: :created
else
render json: { errors: @order.errors }, status: :unprocessable_entity
end
end
end
end
module Order
class Create < Operations::Create
class Runner < Operationable::Runners::Separate
def initialize_callbacks
push_to_queue(:broadcast, :notify, :populate_feed, queue: :low)
push_to_queue(:notify, queue: :high)
end
end
class Callback < ::Operations::Callback
def broadcast
BroadcastService.new(props).process
end
def notify
NotificationService.new(props).process
end
def populate_feed
ActivityFeedService.new(props).process
end
end
class Serializer < ::Operations::Serializer
RECORD_FIELDS = %i(id).freeze
end
end
end
# How can somebody understand what is happend, and insure that circular calls not happens.
class One
include Pubsub
def make_something
# make something
if success?
publish(:one_finished, result)
else
publish(:one_failed, e)
end
end
end
One.subscribe(Two)
class Two
include Pubsub
def one_finished
# execute some code, and call another domain
publish(:call_three, result)
end
def one_failed
# execute some code, and call another domain
publish(:call_four, result)
end
end
Two.subscribe(Three, Four)
class Three
include Pubsub
def call_three
# may be publish for One?
end
end
class Four
include Pubsub
def call_four
# may be publish for Two?
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.