Advanced » Explicit Setup
Block style setup is suitable for simple, quick'n'dirty scripts that need to access databases, in a typical application setup, you want to break down individual component definitions, like relations or commands, into separate files and define them as explicit classes.
ROM & Frameworks
Framework integrations take care of the setup for you. If you want to use ROM with a framework, please refer to specific instructions under Getting Started section
Setup
To do setup in flat style, create a ROM::Configuration
object. This is the
same object that gets yielded into your block in block-style setup, so the API
is identical.
configuration = ROM::Configuration.new(:memory, 'memory://test')
configuration.relation(:users)
# ... etc
When you’re finished configuring, pass the configuration object to
ROM.container
to generate the finalized container. There are no differences in
the internal semantics between block-style and flat-style setup.
Registering Components
ROM components need to be registered with the ROM configuration in order to be used.
configuration = ROM::Configuration.new(:memory, 'memory://test')
# Declare Relations, Commands, and Mappers here
If you prefer to create explicit classes for your components you must register them with the configuration directly:
configuration = ROM::Configuration.new(:memory, 'memory://test')
configuration.register_relation(OneOfMyRelations)
configuration.register_relation(AnotherOfMyRelations)
configuration.register_command(User::CreateCommand)
configuration.register_mapper(User::UserMapper)
You can pass multiple components to each register
call, as a list of arguments.
Auto-registration
ROM provides auto_registration
as a convenience method for automatically
require
-ing and registering components that are not declared with the DSL. At
a minimum, auto_registration
requires a base directory. By default, it will
load relations from <base>/relations
, commands from <base>/commands
, and
mappers from <base>/mappers
.
Namespaces inferred from directory structure
By default, auto-registration assumes that the directory structure reflects your module/class organization, for example:
# lib/persistence/relations/users.rb
module Persistence
module Relations
class Users < ROM::Relation[:sql]
schema(:users, infer: true)
end
end
end
Then to set up auto-registration simply provide the root path to your components directory:
configuration = ROM::Configuration.new(:memory)
configuration.auto_registration('/path/to/lib')
container = ROM.container(configuration)
Explicit namespace name
If your directory structure doesn't reflect module/class organization but you do namespace components,
then you can set up auto-registration via :namespace
option:
# lib/relations/users.rb
module Persistence
module Relations
class Users < ROM::Relation[:sql]
schema(infer: true)
end
end
end
Since we use Persistence
as our namespace, we need to set it explicitly:
configuration = ROM::Configuration.new(:memory)
configuration.auto_registration('/path/to/lib', namespace: 'Persistence')
container = ROM.container(configuration)
Turning namespace off
If you keep all components under {path}/(relations|commands|mappers)
directories and don't
namespace them, then you can simply turn namespacing off:
# lib/relations/users.rb
class Users < ROM::Relation[:sql]
schema(infer: true)
end
configuration = ROM::Configuration.new(:memory)
configuration.auto_registration('/path/to/lib', namespace: false)
container = ROM.container(configuration)
Relations
Relations can be defined with a class extending ROM::Relation
from the appropriate adapter.
# Defines a Users relation for the SQL adapter
class Users < ROM::Relation[:sql]
end
# Defines a Posts relation for the HTTP adapter
class Posts < ROM::Relation[:http]
end
Relations can declare the specific gateway and dataset it takes data from, as well as the registered name of the relation. The following example sets the default options explicitly:
class Users < ROM::Relation[:sql]
register_as :users # the registered name; eg. for use in Repository’s relations(...) method
gateway :default # the gateway name, as defined in setup
dataset :users # eg. in sql, this is the table name
end
Commands
Just like Relations, Commands can be defined as explicit classes:
class CreateUser < ROM::Commands::Create[:memory]
end
Commands have three settings: their relation, which takes the registered name of
a relation; their result type, either :one
or :many
; and their registered
name.
class CreateUser < ROM::Commands::Create[:memory]
register_as :create
relation :users
result :one
end
Typically, you're going to use repository command interface and changesets; custom command classes are useful when the built-in command support in repositories doesn't meet your requirements