Let's assume some basic AR stuff:
class Invitation < ActiveRecord::Base
scope :templates, where(template: true)
end
Then we could set up some Pavlov operations, one interactor and some queries and commands:
module Invitations
class CreateFromTemplate < Interactor
attribute :template_id
def authorized?
context.current_user.can? :create_invitations
end
def execute
template = backend.crud.find_template(template_id)
attributes = template.attributes.slice(:name, :content)
invitation = backend.invitations.create(attributes)
backend.notification.email(invitation)
invitation
end
end
class Crud < Pavlov::Ops
def find_template(id); Invitation.templates.find(id) end
def create(attributes); Invitation.create!(attributes); end
end
class Notifications < Pavlov::Ops
def email(invitation)
sendgrid.send(InvitationToEmail.new(invitation).as_email)
end
handle_asynchronously :email # standard DelayedJob
end
end
To run this, we need an execution context (obviously, everywhere you see Pavlov::
, you could also have your own class):
# these would be done on application initialization
invitations = Pavlov::Backend.for(Invitations, sendgrid: Sendgrid.new(ENV["SENDGRID_API_KEY"]))
router = Pavlov::Router.new('invitations' => invitations)
# these would be done for each web request, somewhere in a before_filter or so
context = Pavlov::Context.new(current_user: @user)
cortex = Pavlov::Cortex.new(context, router)
Then a controller can do:
class InvitationController
def create
cortex.invitations.create_from_template(template_id: params[:invitation][:id])
end
end
Invitations
is self-contained, although all interactors know about the cortex through which they were invoked, and can call out to other modules through that. But that makes it easy to find out which modules depend on which.- Obviously, wherever I reference
Pavlov::SomeClass
, you can imagine we provide a generator that creates a wrapper inside the application instead. - A router is simply an object that responds to
invitations
, and passes the cortex along. If the standard router doesn't suffice, build your own.