Using Ruby Event Store without Rails
ActiveRecord and ROM (Sequel) are supported SQL adapters out-of-the-box.
Installation
Add to your Gemfile
:
source "https://rubygems.org"
gem "ruby_event_store"
# For ActiveRecord:
gem "activerecord"
gem "rails_event_store_active_record"
# For ROM/Sequel:
gem "rom-sql"
gem "ruby_event_store-rom", require: "ruby_event_store/rom/sql"
# And one of:
gem "sqlite3"
gem "pg"
gem "mysql2"
Creating tables
ActiveRecord: As you are not using rails and its generators, please create required database tables which are equivalent to what our migration would do.
ROM/Sequel migrations
SQL schema migrations can be copied to your project using Rake tasks. (The ROM migrations use Sequel under the hood.)
Add the tasks to your Rakefile
to import them into your project:
# In your project Rakefile
require "ruby_event_store/rom/adapters/sql/rake_task"
Then run Rake tasks to get your database setup:
# Copies the migrations to your project (in db/migrate)s
bundle exec rake db:migrations:copy DATABASE_URL=postgres://localhost/database
# <= migration file created db/migrate/20180417201709_create_ruby_event_store_tables.rb
# Run the migrations in your project (in db/migrate)
bundle exec rake db:migrate DATABASE_URL=postgres://localhost/database
# <= db:migrate executed
By default, data
and metadata
are stored in text columns. You can specify the DATA_TYPE
environment variable when copying migrations to use a JSON or JSONB column in Postgres.
bundle exec rake db:migrations:copy DATABASE_URL=postgres://localhost/database DATA_TYPE=jsonb
You can run bundle exec rake -T
to get a list of all available tasks. You can also programmatically run migrations (see examples above).
NOTE: Make sure the database connection in your app doesn't try to connect and setup RES before the migrations have run.
Usage
ActiveRecord
require "active_record"
require "rails_event_store_active_record"
require "ruby_event_store"
ActiveRecord::Base.logger = Logger.new(STDOUT)
ActiveRecord::Base.establish_connection(ENV["DATABASE_URL"])
class OrderPlaced < RubyEventStore::Event
end
event_store = RubyEventStore::Client.new(repository: RailsEventStoreActiveRecord::EventRepository.new)
event_store.publish(
OrderPlaced.new(data: { order_id: 1, customer_id: 47_271, amount: BigDecimal.new("20.00") }),
stream_name: "Order-1",
)
ROM/Sequel setup
You simply need to configure your ROM container and then store it globally on RubyEventStore::ROM.env
or pass it to the repository constructor.
require "ruby_event_store/rom/sql"
# Use the `setup` helper to configure repositories and mappers.
# Then store an Env instance to get access to the ROM container.
RubyEventStore::ROM.env = RubyEventStore::ROM.setup(:sql, ENV["DATABASE_URL"])
# Use the repository the same as with ActiveRecord
client = RubyEventStore::Client.new(repository: RubyEventStore::ROM::EventRepository.new)
Advanced setup
You can use a specific ROM container per repository to customize it more extensively. This example illustrates how to get at the ROM configuration and even run the latest migrations.
require "ruby_event_store/rom/sql"
config = ROM::Configuration.new(:sql, ENV["DATABASE_URL"])
# Run migrations if you need to (optional)
config.default.run_migrations
# Use the `setup` helper to configure the ROM container
env = RubyEventStore::ROM.setup(config)
# Use the repository the same as with ActiveRecord
client = RubyEventStore::Client.new(repository: RubyEventStore::ROM::EventRepository.new(rom: env))
# P.S. Access the ROM container
container = env.container
This advanced option provides flexibility if you are using a separate database for RES or have other needs that require more granular configurations.
Unavailable features
rails_event_store
provides some features that ruby_event_store
by design cannot:
- async handlers and ActiveJob integration
You can implement and provide your own dispatcher which knows how to recognize and enqueue async handlers. Pass it as a dependency to RubyEventStore::Client
constructor.
- Request metadata such as
remote_ip
andrequest_id
won't be automatically filled in events' metadata.