Slides: https://speakerdeck.com/davydovanton/hanami-architecture
Telegram channel (russian): https://t.me/pepegramming
Ссылки на конкретные посты: http://telegra.ph/Pepegramming-Contents-07-16
module Platform | |
module Types | |
include Dry::Types.module | |
include ROM::Types | |
include ROM::SQL::Types | |
include ROM::SQL::Types::PG | |
# ... | |
Phone = String |
require 'hanami/interactor' | |
require 'dry-matcher' | |
module Hanami::Interactor | |
module Matcher | |
SUCCESS_CASE = Dry::Matcher::Case.new( | |
match: -> result { result.successful? }, | |
resolve: -> result { result.value } | |
) |
Slides: https://speakerdeck.com/davydovanton/hanami-architecture
Telegram channel (russian): https://t.me/pepegramming
Ссылки на конкретные посты: http://telegra.ph/Pepegramming-Contents-07-16
class Service | |
include Dry::Matcher.for(:call, with: Dry::Matcher::EitherMatcher) | |
include Dry::Monads::Either::Mixin | |
def call(payload) | |
# ... | |
Right(payload) | |
end | |
end |
Пример из pepegramming канала
Есть экшен в рельсе, который создает инвойс:
def create
invoice = Invoice.new(params[:invoice])
if invoice.save
require 'hanami/events' | |
events = Hanami::Events.build(:memory) | |
events.subscribe('user.created') { |payload| puts "Create user: #{payload}" } | |
events.subscribe('user.created') { |payload| puts "Send notification to user: #{payload}" } | |
events.subscribe('user.deleted') { |payload| puts "Delete user: #{payload}" } | |
events.broadcast('user.created', user_id: 1) |
# dry-validation (0.10.7) | |
# dry-types (0.10.3) | |
require 'dry/types' | |
require 'dry/validation' | |
module Types | |
include Dry::Types.module | |
Phone = String.constrained(format: /\A([\d]{10}|)\z/) | |
end |
Опять рассмотрим tasks#create
экшен.
В экшене 3 разных логики, которые выполняются последовательно:
Поэтому напишем нашу транзакцию. Так же мы будем использовать Either монаду для возвращения статуса шага транзакции. Right
для успешного, Left
- не успешного:
Рассмотрим tasks#create
экшен. Из названия понятно, что он сохраняет новые таски. Если посмотреть на код, возникает подсознательное недоверие к коду из-за его количества.
Во первых, видно, что мешается логика экшена (authenticated?
) и логика сохранения, валидирования, вызова тасков в сайдкик. А так же, видно лишний метод #task_params
который приводит данные с экшена в данные, которые будут скормлены нашей модели.
Для начала, давайте сделаем прсотой интерактор CreateTask
:
require 'hanami/interactor'
У нас есть либа, которая заруливает отправку всех нотификаций. Выглядит это следующим образом. Есть глобальный класс, который ты вызываешь с юзером (и его настройками) и с параметрами Notify.new.call(account, title: 'bla bla')
. У этого класса есть куча стратегий (text, email, push, etc) которые вызываются все для каждого юзера. Но в каждой стратегии указывается условие, при котором эту стратегию нужно выполнять, т.е.:
class TestStrategy
# ...
def allow?(preferences)
preferences.allow_email
end
end