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