"meet rom_rb & dry_rb" by piotr solnica
TRANSCRIPT
![Page 1: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/1.jpg)
MEET ROM-RB & DRY-RBPIOTR SOLNICA
![Page 2: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/2.jpg)
HI PIVORAK!
I’M SOLNIC :)
![Page 3: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/3.jpg)
mojotech.com
rom-rb.org dry-rb.org
![Page 4: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/4.jpg)
THE STORY
![Page 5: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/5.jpg)
DATAMAPPER 2010
![Page 6: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/6.jpg)
DATAMAPPER
▸ Active Record ORM with explicit model property definitions
▸ Advanced query API in 2009 already (lazy queries, lazy properties, advanced query operators etc.)
▸ Custom data types for properties
▸ Database-agnostic through adapters
![Page 7: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/7.jpg)
VIRTUS 2011
![Page 8: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/8.jpg)
VIRTUS
▸ Typed attribute definitions in PORO extracted from DataMapper
▸ Advanced coercion mechanism
▸ Fully configurable and flexible
▸ Form objects, data objects (ie loaded from JSON), coercion backends etc.
▸ For some reason people loved it…
![Page 9: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/9.jpg)
DATAMAPPER 2 2012
![Page 10: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/10.jpg)
DATAMAPPER 2
▸ Active Record => Data Mapper (patterns)
▸ Adapters based on pure relational algebra backend
▸ Advanced Session with Unit of Work for state tracking and data synchronization
▸ Didn’t really work out ¯\_(⊙_ʖ⊙)_/¯
▸ However…
![Page 11: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/11.jpg)
EXPERIMENTATION BEHIND DM2 HAS BEEN FRUITFUL!
![Page 12: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/12.jpg)
RESULTS OF THE DATAMAPPER 2 EXPERIMENT
▸ Immutability-oriented object design!
▸ Focus on simpler, foundational abstractions
▸ Embracing small, composable libraries
▸ Lots of interesting new patterns in Ruby
![Page 13: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/13.jpg)
ROM-RB 2013->2014
![Page 14: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/14.jpg)
ROM-RB 2013->2014
▸ DataMapper 2 renamed to rom-rb (Ruby Object Mapper) in 2013
▸ More work has been put into its relational algebra backend and optimizing sql queries
▸ Prototype of Session with Unit of Work
▸ Still not production ready ¯\_(⊙_ʖ⊙)_/¯
![Page 15: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/15.jpg)
( ಠ ಠ)
![Page 16: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/16.jpg)
“ORM is one of the most complex things that you can ever touch…and we chose it over and over again, without thinking at all, because everybody is doing it”
Rich Hickey
![Page 17: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/17.jpg)
ROM-RB 2014+
![Page 18: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/18.jpg)
ROM-RB
![Page 19: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/19.jpg)
PERSISTENCE & MAPPING TOOLKIT FOR RUBY
![Page 20: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/20.jpg)
NO COMPLEX & LEAKY ABSTRACTIONS
![Page 21: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/21.jpg)
REDUCES GLOBAL STATE TO THE MINIMUM
![Page 22: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/22.jpg)
FIGHTS WITH MUTABLE STATE
![Page 23: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/23.jpg)
MIXES FP WITH OO
![Page 24: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/24.jpg)
CORE CONCEPTS
▸ Configuration
▸ Relations
▸ Pipelines
▸ Commands
![Page 25: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/25.jpg)
CONFIGURATION
![Page 26: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/26.jpg)
require 'rom'
config = ROM::Configuration.new( :sql, 'postgres://localhost/rom_repository')
rom = ROM.container(config)
rom.gateways[:default]# #<ROM::SQL::Gateway:0x007fde7a087158>
![Page 27: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/27.jpg)
RELATIONS
![Page 28: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/28.jpg)
class Users < ROM::Relation[:sql] def sorted order(:name) endend
JUST DATA
QUERY LOGIC
rom.relations[:users].sorted# [{:id=>1, :name=>"Jane"}
![Page 29: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/29.jpg)
RELATIONS ARE CALLABLE
![Page 30: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/30.jpg)
rom.relations[:users].call# [{:id=>1, :name=>"Jane"}]
rom.relations[:users].where(name: 'Jane').call# [{:id=>1, :name=>"Jane"}]
rom.relations[:users].where(name: 'Joe').call# []
![Page 31: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/31.jpg)
PIPELINE
![Page 32: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/32.jpg)
map_names = -> users { users.map { |user| user[:name] } }
user_names = rom.relations[:users] >> map_names
user_names.call# ["Jane"]
PIPELINE OPERATOR
![Page 33: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/33.jpg)
COMMANDS
![Page 34: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/34.jpg)
class CreateUser < ROM::Commands::Create[:sql] relation :users register_as :create result :oneend
create_user = rom.commands[:users][:create]
create_user.call(name: 'Joe')# [{:id=>2, :name=>"Joe"}
![Page 35: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/35.jpg)
ROM-REPOSITORY
![Page 36: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/36.jpg)
class UserRepo < ROM::Repository relations :users
def all users.select(:name).to_a endend
![Page 37: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/37.jpg)
user_repo = UserRepo.new(rom)
user_repo.all# [#<ROM::Struct name="Jane">, #<ROM::Struct name="Joe">]
![Page 38: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/38.jpg)
UPCOMING COMMAND SUPPORT
![Page 39: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/39.jpg)
class UserRepo < ROM::Repository[:users] commands :create, update: :by_idend
user = user_repo.create(name: "Jane", email: "[email protected]")
user_repo.update(user.id, name: "Jane Doe")
![Page 40: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/40.jpg)
ROM 2.0 IS AROUND THE CORNER!!!
![Page 41: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/41.jpg)
ROM 2.0 + ROM-SQL + ROM-REPOSITORY UPDATES
▸ type-safe and flexible relation schema DSL
▸ association support in schemas
▸ simplified, automatic eager-loading based on association definitions
▸ simplified interface for returning aggregate objects in repositories
▸ support for persisting nested data into multiple relations
![Page 42: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/42.jpg)
DRY-RB
![Page 43: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/43.jpg)
![Page 44: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/44.jpg)
‣Low level building blocks ‣High-level abstractions
![Page 45: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/45.jpg)
DRY-CONTAINER
![Page 46: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/46.jpg)
LIGHTWEIGHT IOC
![Page 47: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/47.jpg)
require 'dry-container'
class MyContainer extend Dry::Container::Mixinend
# register a singletonMyContainer.register(:user_repo, UserRepo.new)
# or resolve as a new objectMyContainer.register(:user_repo) { UserRepo.new }
# simply access your registered objectsMyContainer[:user_repo]
![Page 48: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/48.jpg)
class PersistUser attr_reader :user_repo
def initialize(user_repo) @user_repo = user_repo end
def call(user) user_repo.create(user) endend
PersistUser.new(MyContainer[:user_repo])
![Page 49: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/49.jpg)
MyContainer.register(:persist_user) do PersistUser.new(MyContainer[:user_repo])end
MyContainer[:persist_user].call(user_data)
![Page 50: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/50.jpg)
DRY-AUTO_INJECT
![Page 51: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/51.jpg)
CONSTRUCTOR INJECTION MIXIN
![Page 52: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/52.jpg)
require 'dry-auto_inject'
Inject = Dry::AutoInject(MyContainer)
![Page 53: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/53.jpg)
class PersistUser include Inject[:user_repo]
def call(user) user_repo.create(user) endend
![Page 54: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/54.jpg)
MyContainer.register(:persist_user) do PersistUser.newend
![Page 55: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/55.jpg)
DRY-COMPONENT
![Page 56: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/56.jpg)
MANAGING STATE
![Page 57: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/57.jpg)
require 'dry/component/container'
class Application < Dry::Component::Container configure do |config| config.root = Pathname.new('./my/app') endend
# now you can register a loggerrequire 'logger'Application.register('utils.logger', Logger.new($stdout))
# and access itApplication['utils.logger']
![Page 58: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/58.jpg)
AUTO-REGISTRATION
![Page 59: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/59.jpg)
require 'dry/component/container'
class Application < Dry::Component::Container configure do |config| config.root = '/my/app'
config.auto_register = 'lib' end
load_paths!('lib')end
![Page 60: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/60.jpg)
# under /my/app/lib/logger.rb we putclass Logger # some neat logger implementationend
# we can finalize the container which triggers auto-registrationApplication.finalize!
# the logger becomes availableApplication[‘logger']
![Page 61: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/61.jpg)
BOOTING 3RD-PARTY DEPS
![Page 62: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/62.jpg)
Application.finalize(:persistence) do require '3rd-party/database'
container.register('database') do # some code which initializes this thing endend
![Page 63: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/63.jpg)
class Application < Dry::Component::Container configure do |config| config.root = '/my/app' endend
# requires needed files and boots your persistence componentApplication.boot!(:persistence)
# and now `database` becomes availableApplication['database']
![Page 64: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/64.jpg)
DRY-TYPES
![Page 65: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/65.jpg)
A TYPE SYSTEM FOR RUBY WITH COERCIONS AND CONSTRAINTS
![Page 66: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/66.jpg)
DRY-TYPES TURNS RUBY INTO HASKELL
![Page 67: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/67.jpg)
![Page 68: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/68.jpg)
NOT REALLY :)
![Page 69: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/69.jpg)
BUT TYPE-SAFETY MATTERS
![Page 70: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/70.jpg)
require 'dry-types'
module Types include Dry::Types.moduleend
Types::Coercible::String[1] # => "1"
Types::Form::Nil[""] # => nilTypes::Form::Float["1.23"] # 1.23
![Page 71: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/71.jpg)
NilOrString = Types::Strict::Nil | Types::Strict::String
NilOrString[nil] # nilNilOrString["foo"] # "foo"
![Page 72: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/72.jpg)
DefaultAge = Types::Strict::Int.default(33)
DefaultAge[nil] # 33Default[35] # 35
DefaultAge["35"]# Dry::Types::ConstraintError: "35" violates constraints (type?(Integer) failed)
![Page 73: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/73.jpg)
UserAge = Types::Strict::Int.constrained(gt: 18)
UserAge[19]# 19
UserAge[18]# Dry::Types::ConstraintError: 17 violates constraints (gt?(18) failed)
![Page 74: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/74.jpg)
class User < Dry::Types::Struct attribute :id, Types::Strict::Int attribute :name, Types::Strict::Stringend
User.new(id: 1, name: "Jane")
![Page 75: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/75.jpg)
0.8.0 IS AROUND THE CORNER
![Page 76: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/76.jpg)
DRY-VALIDATION
![Page 77: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/77.jpg)
FAST, POWERFUL VALIDATION WITH TYPE-SAFETY & SAFE COERCIONS
![Page 78: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/78.jpg)
VALIDATION SCHEMAS
![Page 79: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/79.jpg)
require 'dry-validation'
UserSchema = Dry::Validation.Schema do required(:login).filled(:str?, size?: 2..64) required(:age).maybe(:int?, gt?: 18)end
![Page 80: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/80.jpg)
UserSchema.(login: "j", age: 19).messages# {:login=>["length must be within 2 - 64"]}
UserSchema.(login: "jane", age: nil).messages# {}
![Page 81: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/81.jpg)
SCHEMAS WITH COERCIONS
![Page 82: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/82.jpg)
require 'dry-validation'
UserSchema = Dry::Validation.Form do required(:login).filled(:str?, size?: 2..64) required(:age).maybe(:int?, gt?: 18)end
![Page 83: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/83.jpg)
UserSchema.(login: "jane", age: '19').to_h# {:login=>"jane", :age=>19}
UserSchema.(login: "jane", age: '').to_h# {:login=>"jane", :age=>nil}
UserSchema.(login: "j", age: '19').messages# {:login=>["length must be within 2 - 64"]}
UserSchema.(login: "j", age: 'oops').messages# {:age=>["must be an integer", "must be greater than 18"]}
UserSchema.(login: "jane", age: '').messages# {}
![Page 84: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/84.jpg)
UserSchema.(login: "j", age: 'oops').messages# {:age=>["must be an integer", "must be greater than 18"]}
VALIDATION HINT
VALIDATION ERROR
![Page 85: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/85.jpg)
0.8.0 IS AROUND THE CORNER
![Page 86: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/86.jpg)
OMG MORE DRY-RB GEMS!
▸ dry-transaction
▸ dry-monads
▸ dry-initializer
▸ dry-web
▸ dry-web-roda (we plan to add support for more!)
▸ more gems are planned!
![Page 90: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/90.jpg)
dry-rb.org/resources/reddotrubyconf-2016/
More resources!
![Page 91: "Meet rom_rb & dry_rb" by Piotr Solnica](https://reader033.vdocuments.pub/reader033/viewer/2022042723/58735d311a28abe7648b4d77/html5/thumbnails/91.jpg)
THANK YOU :)