### Install via RubyGems Source: https://railseventstore.org/docs/getting-started/install Install the library using the gem command. ```bash gem install rails_event_store ``` -------------------------------- ### Start databases with devenv up Source: https://railseventstore.org/docs/contributing/devenv_setup Starts Postgres 14 and 18, MySQL 8.4, and Redis as background processes. They listen on the same host/port pairs as support/ci/generate, so DATABASE_URL values from CI matrix cells work verbatim. MySQL 9.7 is skipped if no docker-compatible CLI is on PATH. ```bash devenv up ``` -------------------------------- ### Install and run test suites with make Source: https://railseventstore.org/docs/contributing/devenv_setup Inside the devenv shell, install gem dependencies once, then use the regular make targets. The test-ruby_event_store target needs no database, while test-ruby_event_store-active_record runs against Postgres 18 by default. ```bash make install-ruby_event_store # bundle install for that gem make test-ruby_event_store # no database needed make install-ruby_event_store-active_record # bundle install for that gem make test-ruby_event_store-active_record # against Postgres 18 by default ``` -------------------------------- ### Install in existing Rails application Source: https://railseventstore.org/docs/getting-started/install Run the template in an existing Rails application root directory. ```bash bin/rails app:template LOCATION=https://railseventstore.org/new ``` -------------------------------- ### Install SQL adapter gems Source: https://railseventstore.org/docs/advanced-topics/without-rails Choose and install one of the supported SQL adapters: SQLite3, PostgreSQL, or MySQL. ```ruby # Choose one of SQL adapters gem "sqlite3" gem "pg" gem "mysql2" ``` -------------------------------- ### Install ruby_event_store-cli Source: https://railseventstore.org/docs/core-concepts/cli Add the gem to your application's Gemfile to enable the res command. ```ruby gem "ruby_event_store-cli" ``` -------------------------------- ### Implementing a Complete Extension Class Source: https://railseventstore.org/docs/core-concepts/browser A full example of an extension class implementing views_root, assets_root, register_routes, stream_links, and nav_links. ```ruby class DeploymentsExtension def views_root File.expand_path("browser_views", __dir__) end def assets_root File.expand_path("browser_assets", __dir__) end def register_routes(router, context) router.add_route("GET", "/deployments/:name") do |params, urls| name = params.fetch("name") events = context.event_store.read.stream("Deployment$#{name}").to_a next context.not_found(urls, message: "No deployment named #{name}") if events.empty? context.render("deployments/show", urls: urls, title: "Deployment #{name}", name: name, events: events) end end def stream_links(stream_name, urls) prefix, name = stream_name.split("$") return [] unless prefix == "Deployment" [{ label: "Deployment view", url: urls.app_url_for("deployments", name) }] end def nav_links(urls) [{ label: "Deployments", url: urls.app_url_for("deployments", "production") }] end end ``` -------------------------------- ### Install custom repository with Bundler Source: https://railseventstore.org/docs/advanced-topics/custom-repository Adds the rails_event_store gem with the 'rails_event_store/all' require and a custom repository gem to the Gemfile. Run bundle install after adding these lines. ```ruby gem "rails_event_store", require: "rails_event_store/all" gem "your_custom_repository" ``` -------------------------------- ### Use custom OrderRepository Source: https://railseventstore.org/docs/core-concepts/event-sourcing Example of submitting an order using the custom OrderRepository. ```ruby repository = OrderRepository.new repository.with_order(123) do |order| order.submit end ``` -------------------------------- ### Example payload for load.repository.aggregate_root Source: https://railseventstore.org/docs/advanced-topics/instrumentation Shown under the load.repository.aggregate_root heading. The payload contains :aggregate and :stream keys. ```ruby { aggregate: #, stream: "Order$42" } ``` -------------------------------- ### Example payload for apply.aggregate_root Source: https://railseventstore.org/docs/advanced-topics/instrumentation Shown under the apply.aggregate_root heading. The payload contains :aggregate and :event keys. ```ruby { aggregate: #, event: # } ``` -------------------------------- ### Example payload for store.repository.aggregate_root Source: https://railseventstore.org/docs/advanced-topics/instrumentation Shown under the store.repository.aggregate_root heading. The payload contains :aggregate, :stream, :version, and :stored_events keys. ```ruby { aggregate: #, stream: "Order$42", version: -1, stored_events: [ #, # ] } ``` -------------------------------- ### have_published from a starting point Source: https://railseventstore.org/docs/core-concepts/rspec Specifies the reading starting point for the matcher using an event ID. ```ruby expect(event_store).to have_published(an_event(OrderExpired)).from(order_placed.event_id) ``` -------------------------------- ### Install minitest-ruby_event_store Source: https://railseventstore.org/docs/minitest.html Add the gem to your Gemfile and require it in your test helper to mix assertions into Minitest::Assertions. ```ruby group :test do gem "minitest-ruby_event_store" end ``` ```ruby require "minitest/ruby_event_store" ``` -------------------------------- ### Install Rails Event Store and Protobuf gems Source: https://railseventstore.org/docs/advanced-topics/protobuf.html Add these dependencies to your Gemfile to enable Protobuf support in Rails Event Store. ```ruby gem "google-protobuf" gem "protobuf_nested_struct" gem "rails_event_store" gem "ruby_event_store-protobuf" ``` -------------------------------- ### Publish event with custom mapper Source: https://railseventstore.org/docs/advanced-topics/mappers Example of publishing an event using the configured event store with the custom mapper. ```ruby class OrderPlaced < RubyEventStore::Event end event_store = Rails.configuration.event_store event_store.publish(OrderPlaced.new(data: { 'order_id' => 1, 'order_amount' => BigDecimal('120.55'), }), stream_name: 'Order$1') ``` -------------------------------- ### Sparse matrix configuration Source: https://railseventstore.org/docs/contributing/ci_workflows Example of using the sparse matrix DSL to limit the number of test rows while ensuring each value is exercised at least once. ```ruby sparse(ruby_version("4.0", "3.4", "3.3"), bundle_gemfile("G", "R1", "R2")) # => 5 rows, not 9: # {ruby 4.0, G} {ruby 3.4, G} {ruby 3.3, G} # ruby varies at the baseline gemfile # {ruby 4.0, R1} {ruby 4.0, R2} # gemfile varies at the baseline ruby ``` -------------------------------- ### Implement a listener with call method Source: https://railseventstore.org/docs/core-concepts/pubsub Implement a listener that responds to call and handles events by class. The example raises an error for unsupported events. ```ruby class OrderNotifier def call(event) order_id = order.data.fetch(:order_id) case event when OrderCancelled # notify someone... else raise "not supported event #{event.inspect}" end end end ``` -------------------------------- ### Setup Upcast Mapper Source: https://railseventstore.org/docs/advanced-topics/migrating-existing-events Configure the RubyEventStore::Mappers::Transformation::Upcast in your mapper pipeline by providing a hash of event types and transformation lambdas. ```ruby upcast_map = { "OrderPlaced" => lambda do |record| RubyEventStore::Record.new( event_id: record.event_id, metadata: record.metadata, timestamp: record.timestamp, valid_at: record.valid_at, event_type: record.event_type, data: record.data.merge(currency: "USD"), ) end } class MyMapper < RubyEventStore::Mappers::PipelineMapper def initialize(upcast_map) super(RubyEventStore::Mappers::Pipeline.new( RubyEventStore::Mappers::Transformation::Upcast.new(upcast_map), RubyEventStore::Mappers::Transformation::SymbolizeMetadataKeys.new, )) end end Rails.application.configure do config.to_prepare do Rails.configuration.event_store = RailsEventStore::Client.new( mapper: MyMapper.new(upcast_map) ) end end ``` -------------------------------- ### Defining an Extension Template Source: https://railseventstore.org/docs/core-concepts/browser An example of an ERB template file located in the extension's views_root directory. ```erb

Deployment <%= h(name) %>

    <% events.each do |event| -%>
  • <%= h(event.event_type) %> <%= render("_timestamp", title: "At", time: event.metadata[:timestamp], top: false) %>
  • <% end -%>
``` -------------------------------- ### Add ruby_event_store-mcp to Gemfile Source: https://railseventstore.org/docs/core-concepts/mcp Add this line to your application's Gemfile to install the res-mcp binary. The binary speaks MCP over stdio and loads config/environment.rb from your app's root. ```ruby gem "ruby_event_store-mcp" ``` -------------------------------- ### JSON symbol-to-string conversion example Source: https://railseventstore.org/docs/advanced-topics/event-serialization-formats Shows that JSON.load converts symbol keys to strings, which is a caveat when using JSON serialization. ```ruby JSON.load(JSON.dump({ foo: :bar })) # => {"foo" => "bar"} ``` -------------------------------- ### Configure ROM container and repository Source: https://railseventstore.org/docs/advanced-topics/without-rails Set up the ROM environment and initialize the Ruby Event Store client with the ROM repository. ```ruby 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) ``` -------------------------------- ### Correlate events and commands with RubyEventStore::CorrelatedCommands Source: https://railseventstore.org/docs/core-concepts/correlation-causation Wires the event store and command bus together using RubyEventStore::CorrelatedCommands in a Rails to_prepare block. This makes events automatically correlated to the commands that triggered them, provided commands respond to message_id. The example shows the setup with placeholders for registering handlers and commands. ```ruby config.to_prepare do Rails.configuration.event_store = event_store = RailsEventStore::Client.new # register handlers command_bus = Arkency::CommandBus.new # register commands... # wire event_store and command_bus together Rails.configuration.command_bus = RubyEventStore::CorrelatedCommands.new(event_store, command_bus) end ``` -------------------------------- ### Run the browser demo Source: https://railseventstore.org/docs/contributing/devenv_setup Serves the standalone browser demo, seeded with sample events, at http://localhost:9393. ```bash make -C ruby_event_store-browser dev ``` -------------------------------- ### Configure AggregateRoot::Repository Source: https://railseventstore.org/docs/core-concepts/event-sourcing Initialize the repository by passing the event store client explicitly, as there is no global default. ```ruby event_store = Rails.configuration.event_store repository = AggregateRoot::Repository.new(event_store) ``` -------------------------------- ### Handle RubyEventStore::InvalidPageStart Source: https://railseventstore.org/docs/core-concepts/client-errors Occurs when reading a stream with an invalid start parameter. ```ruby expect do client.read.stream('Order$1').from(nil).to_a end.to raise_error(InvalidPageStart) ``` -------------------------------- ### Instantiate client in config/application Source: https://railseventstore.org/docs/getting-started/install Configure the event store client within the main application configuration. ```ruby # config/application.rb module YourAppName class Application < Rails::Application config.to_prepare do Rails.configuration.event_store = RailsEventStore::Client.new # add subscribers here end end end ``` -------------------------------- ### Enter the devenv shell Source: https://railseventstore.org/docs/contributing/devenv_setup Run this from the repository root to enter a shell with the correct Ruby, bundler, and native libraries for the pg, mysql2, and sqlite3 gems. The first run builds or downloads the toolchain via Cachix. ```bash devenv shell ``` -------------------------------- ### Run migration with custom paths Source: https://railseventstore.org/docs/advanced-topics/without-rails Execute database migrations while specifying custom directory paths and database connection details. ```bash MIGRATION_DIR=migration_path DATABASE_DIR=db_dir DATABASE_URL=postgres://localhost/somedb_development bundle exec rake db:migrate ``` -------------------------------- ### Instantiate client in config/environments Source: https://railseventstore.org/docs/getting-started/install Configure the event store client within the Rails environment configuration. ```ruby # config/environments/*.rb Rails.application.configure do config.to_prepare do Rails.configuration.event_store = RailsEventStore::Client.new # add subscribers here end end ``` -------------------------------- ### Defining current_user in ApplicationController Source: https://railseventstore.org/docs/core-concepts/request-metadata A basic setup for an ApplicationController method that retrieves the currently logged-in user. ```ruby class ApplicationController < ActionController::Base def current_user # ... end end ``` -------------------------------- ### Generate outbox migration Source: https://railseventstore.org/docs/advanced-topics/outbox Run this command to create the necessary database tables for the outbox. ```bash bin/rails generate ruby_event_store:outbox:migration ``` -------------------------------- ### Instantiate client in initializer Source: https://railseventstore.org/docs/getting-started/install Configure the event store client within a dedicated initializer file. ```ruby # config/initializers/rails_event_store.rb Rails.configuration.to_prepare do Rails.configuration.event_store = RailsEventStore::Client.new # add subscribers here end ``` -------------------------------- ### Read all events backward with no limit Source: https://railseventstore.org/docs/core-concepts/read Loads all stored events in descending order, starting from the last event, with no limit applied. ```ruby client.read.backward.to_a ``` -------------------------------- ### Read all events forward with no limit Source: https://railseventstore.org/docs/core-concepts/read Loads all stored events in ascending order, starting from the first event, with no limit applied. ```ruby client.read.to_a ``` -------------------------------- ### Read stream forward from first event Source: https://railseventstore.org/docs/core-concepts/read Reads up to 40 events from a stream in ascending order, starting from the first event. ```ruby stream_name = "order_1" count = 40 client.read.stream(stream_name).limit(count).to_a ``` -------------------------------- ### Create new Rails application with template and database option Source: https://railseventstore.org/docs/getting-started/install Specify additional rails new options like database type when using the template. ```bash rails new -m https://railseventstore.org/new APP_NAME --database=postgresql ``` -------------------------------- ### Repository initialize with serializer Source: https://railseventstore.org/docs/custom_components_2_0.html The Repository's initialize method now takes a serializer argument, which is stored in an instance variable for later use. ```ruby def initialize(serializer) @serializer = serializer end ``` -------------------------------- ### Perform database migration Source: https://railseventstore.org/docs/advanced-topics/without-rails Execute the database migration using the DATABASE_URL environment variable. ```bash DATABASE_URL=postgres://localhost/somedb_development bundle exec rake db:migrate ``` -------------------------------- ### Read stream forward from a given event Source: https://railseventstore.org/docs/core-concepts/read Reads up to 40 events from a stream in ascending order, starting from a specific event identified by its event_id. ```ruby # last_read_event is any domain event read or published by rails_event_store stream_name = "order_1" start = last_read_event.event_id count = 40 client.read.stream(stream_name).from(start).limit(count).to_a ``` -------------------------------- ### Generate and run migrations for Sqlite Source: https://railseventstore.org/docs/getting-started/install Generate and run the migration for Sqlite databases. ```bash bin/rails generate ruby_event_store:active_record:migration bin/rails db:migrate ``` -------------------------------- ### Instantiate JSON client Source: https://railseventstore.org/docs/getting-started/install Use the JSONClient for optimized performance with PostgreSQL jsonb data types. ```ruby Rails.configuration.event_store = RailsEventStore::JSONClient.new ``` -------------------------------- ### Run database migration tasks Source: https://railseventstore.org/docs/advanced-topics/without-rails Use Rake tasks to copy migration files to your project and execute them to set up the database tables. ```bash # Copies the migrations to your project (in db/migrate) bundle exec rake db:migrations:copy DATABASE_URL=postgres://localhost/database # <= migration file created db/migrate/20180417201709_create_ruby_event_store_tables.rb # Runs the migrations and creates the tables bundle exec rake db:migrate DATABASE_URL=postgres://localhost/database # <= db:migrate executed ``` -------------------------------- ### Read events forward from a given event with limit Source: https://railseventstore.org/docs/core-concepts/read Reads a batch of domain events starting from any read or published event, limited to 100 events. ```ruby client.read.from(last_read_event.event_id).limit(100).to_a ``` -------------------------------- ### Configure custom repository in Rails application Source: https://railseventstore.org/docs/advanced-topics/custom-repository Sets up RailsEventStore::Client with a custom repository instance in a Rails to_prepare block. Replace YourCustomRepository with your actual repository class. ```ruby Rails.application.configure do config.to_prepare do Rails.configuration.event_store = RailsEventStore::Client.new(repository: YourCustomRepository.new) end end ``` -------------------------------- ### Read stream backward from a given event Source: https://railseventstore.org/docs/core-concepts/read Reads up to 40 events from a stream in descending order, starting from a specific event. Append .backward before .each as shown. ```ruby stream_name = "order_1" start = last_read_event.event_id count = 40 client.read.backward.stream(stream_name).from(start).limit(count).to_a ``` -------------------------------- ### Create new Rails application with template Source: https://railseventstore.org/docs/getting-started/install Use the Rails template to automatically configure RailsEventStore in a new application. ```bash rails new -m https://railseventstore.org/new APP_NAME ``` -------------------------------- ### Narrow projection scope with from on a single stream Source: https://railseventstore.org/docs/core-concepts/projections Runs the same account_balance projection but starts from a specific event using client.read.stream(stream_name).from(custom_event.event_id), returning {total: -5}. ```ruby account_balance.call(client.read.stream(stream_name).from(custom_event.event_id)) # => {total: -5} ``` -------------------------------- ### Copy migration file Source: https://railseventstore.org/docs/advanced-topics/without-rails Run the rake task to generate the necessary database migration file. ```bash DATA_TYPE=jsonb DATABASE_URL=postgres://localhost/somedb_development bundle exec rake db:migrations:copy ``` -------------------------------- ### Configure Protobuf mapper Source: https://railseventstore.org/docs/advanced-topics/protobuf.html Initialize the Rails Event Store client with the Protobuf mapper within your Rails configuration. ```ruby require "ruby_event_store/protobuf" Rails.application.configure do config.to_prepare do Rails.configuration.event_store = RailsEventStore::Client.new(mapper: RubyEventStore::Mappers::Protobuf.new) end end ``` -------------------------------- ### Handle exceptions in synchronous handlers Source: https://railseventstore.org/docs/core-concepts/subscribe Synchronous handlers that raise exceptions can cause transaction rollbacks. This example shows how to wrap the handler logic in a rescue block to prevent bubbling. ```ruby class SyncHandler def call(event) # ... rescue => e ExceptionTracker.notify(e) end end ``` -------------------------------- ### Subscribe an object handler with within and subscribe Source: https://railseventstore.org/docs/core-concepts/pubsub Subscribe an object responding to call as an event handler. The example shows subscribing a listener to OrderCancelled events within a block that calls cancel_order. ```ruby cancel_order = CancelOrder.new event_store = Rails.configuration.event_store listener = OrderNotifier.new event_store.within { cancel_order.call(order_id, user_id) }.subscribe(listener, to: [OrderCancelled]).call ``` -------------------------------- ### Copy migration file with custom path Source: https://railseventstore.org/docs/advanced-topics/without-rails Generate the migration file using a custom path configuration. ```bash DATA_TYPE=jsonb MIGRATION_PATH=database/migrations bundle exec rake db:migrations:copy ``` -------------------------------- ### Set environment variables manually for a CI cell Source: https://railseventstore.org/docs/contributing/devenv_setup Alternative to res-cell: set DATABASE_URL and DATA_TYPE by hand before running the make target. The example uses the Postgres 14 URL and jsonb data type. ```bash DATABASE_URL=postgres://postgres:secret@localhost:10014/rails_event_store \ DATA_TYPE=jsonb make test-ruby_event_store-active_record ``` -------------------------------- ### Initialize Client with Custom Scheduler Source: https://railseventstore.org/docs/core-concepts/subscribe Configure the RailsEventStore::Client to use an asynchronous dispatcher with a custom scheduler. ```ruby event_store = RailsEventStore::Client.new( message_broker: RubyEventStore::Broker.new( dispatcher: RailsEventStore::AfterCommitDispatcher.new(scheduler: CustomScheduler.new), ), ) ``` -------------------------------- ### Mounting Browser in Rack config.ru Source: https://railseventstore.org/docs/core-concepts/browser Configure the browser in your Rack application by providing an event store locator to the app. ```ruby # e.g. config.ru require "ruby_event_store/browser/app" # Example RES client you might configure event_store = RubyEventStore::Client.new(repository: RubyEventStore::InMemoryRepository.new) run RubyEventStore::Browser::App.for(event_store_locator: -> { event_store }) ``` -------------------------------- ### Correlate an event with a command using correlate_with Source: https://railseventstore.org/docs/core-concepts/correlation-causation Correlates an event with a command by calling correlate_with on the event. The command must respond to correlation_id (can be nil) and message_id. The example creates an ApproveOrder command and an OrderApproved event, then correlates them. ```ruby class ApproveOrder < Struct.new(:order_id, :message_id, :correlation_id) end command = ApproveOrder.new("KTXBN123", SecureRandom.uuid, nil) event = OrderApproved.new(data: { foo: "bar" }) event.correlate_with(command) ``` -------------------------------- ### Implement a Custom Scheduler Source: https://railseventstore.org/docs/core-concepts/subscribe Create a custom scheduler by implementing call and verify methods to define how subscribers are scheduled. ```ruby class CustomScheduler # method doing actual schedule; record is a RubyEventStore::Record def call(klass, record) klass.perform_async(record.serialize(RubyEventStore::Serializers::YAML).to_h) end # method which is checking whether given subscriber is correct for this scheduler def verify(subscriber) Class === subscriber && subscriber.respond_to?(:perform_async) end end ``` -------------------------------- ### Custom event adapter to preserve symbol keys Source: https://railseventstore.org/docs/advanced-topics/event-serialization-formats Defines a custom event class that wraps data in ActiveSupport::HashWithIndifferentAccess to shield from symbol-to-string conversion. Includes usage example showing both symbol and string access work. ```ruby class MyEvent < RubyEventStore::Event def data ActiveSupport::HashWithIndifferentAccess.new(super) end end OrderPlaced = Class.new(MyEvent) ``` ```ruby event_store.publish(OrderPlaced.new(event_id: 'e34fc19a-a92f-4c21-8932-a10f6fb2602b', data: { foo: :bar })) event = event_store.read.event('e34fc19a-a92f-4c21-8932-a10f6fb2602b') event.data[:foo] # => "bar" event.data['foo'] # => "bar" ``` -------------------------------- ### Correlate commands with events using CorrelableCommand module Source: https://railseventstore.org/docs/core-concepts/correlation-causation Defines a CorrelableCommand module that adds correlation_id and causation_id attributes and a correlate_with method. Commands including this module can be correlated to events that triggered them inside sync handlers. The AddProductCommand example includes the module and initializes with a generated message_id. ```ruby module CorrelableCommand attr_accessor :correlation_id, :causation_id def correlate_with(other_message) self.correlation_id = other_message.correlation_id || other_message.message_id self.causation_id = other_message.message_id end end class AddProductCommand < Struct.new(:message_id, :product_id) include CorrelableCommand def initialize(product_id:, message_id: SecureRandom.uuid) super(message_id, product_id) end end ``` -------------------------------- ### Generate bounded context folders Source: https://railseventstore.org/docs/getting-started/introduction Use the bounded_context generator to initialize the folder structure for a new domain model. ```bash rails generate rails_event_store:bounded_context YOUR-BOUNDED-CONTEXT-NAME ``` -------------------------------- ### Use an alternative Ruby version with res-ruby-3.4 Source: https://railseventstore.org/docs/contributing/devenv_setup Prefix a command with res-ruby-3.4 to reproduce a 3.4 cell. Each version keeps its own gem home so native extensions never clash. ```bash res-ruby-3.4 make test-ruby_event_store-active_record ``` -------------------------------- ### Configure global event subscribers in config/application.rb Source: https://railseventstore.org/docs/core-concepts/pubsub Configure global event subscribers in config/application.rb. The event store is created and a listener is subscribed to OrderCancelled events during the to_prepare hook. ```ruby # config/application.rb module YourAppName class Application < Rails::Application config.to_prepare do Rails.configuration.event_store = event_store = RailsEventStore::Client.new event_store.subscribe(OrderNotifier.new, to: [OrderCancelled]) end end end ``` -------------------------------- ### Registering a Browser Extension Source: https://railseventstore.org/docs/core-concepts/browser Register an extension by passing an instance to the extensions array in the RubyEventStore::Browser::App configuration. ```ruby run RubyEventStore::Browser::App.for( event_store_locator: -> { event_store }, extensions: [DeploymentsExtension.new], ) ``` -------------------------------- ### Implement InMemoryEncryptionKeyRepository interface Source: https://railseventstore.org/docs/advanced-topics/gdpr Reference implementation of a key repository with methods key_of, create, and forget. Uses aes-256-cbc cipher and generates random keys. This interface must be implemented for production use. ```ruby class InMemoryEncryptionKeyRepository DEFAULT_CIPHER = "aes-256-cbc".freeze def initialize @keys = {} end def key_of(identifier, cipher: DEFAULT_CIPHER) @keys[[identifier, cipher]] end def create(identifier, cipher: DEFAULT_CIPHER) @keys[[identifier, cipher]] = RubyEventStore::Mappers::EncryptionKey.new(cipher: cipher, key: random_key(cipher)) end def forget(identifier) @keys = @keys.reject { |(id, _)| id.eql?(identifier) } end private def random_key(cipher) crypto = OpenSSL::Cipher.new(cipher) crypto.encrypt crypto.random_key end end ``` -------------------------------- ### Configuring command bus with to_prepare Source: https://railseventstore.org/docs/advanced-topics/command-bus Uses the Rails to_prepare callback to re-register commands, ensuring the command bus works correctly after code reloads. ```ruby config.to_prepare do config.command_bus = Arkency::CommandBus.new register = command_bus.method(:register) { FooCommand => FooService.new(event_store: event_store).method(:foo), BarCommand => BarService.new }.map(®ister) end ``` -------------------------------- ### Configure event store with Outbox SidekiqScheduler Source: https://railseventstore.org/docs/advanced-topics/outbox Update your event store client configuration to use the ImmediateDispatcher with the SidekiqScheduler. ```ruby RailsEventStore::Client.new( message_broker: RubyEventStore::Broker.new( dispatcher: RubyEventStore::ComposedDispatcher.new( RubyEventStore::ImmediateDispatcher.new(scheduler: RubyEventStore::Outbox::SidekiqScheduler.new), RubyEventStore::SyncScheduler.new, ), ), ) ``` -------------------------------- ### Building URLs with app_url_for Source: https://railseventstore.org/docs/core-concepts/browser Use the urls.app_url_for helper to generate paths relative to the browser mount point, avoiding hardcoded paths. ```ruby urls.app_url_for("deployments", name) urls.app_url_for("deployments", query: [["env[]", "production"]]) ``` -------------------------------- ### Create a custom OrderRepository Source: https://railseventstore.org/docs/core-concepts/event-sourcing Encapsulate repository logic in a custom class to simplify aggregate interactions. ```ruby class OrderRepository def initialize(event_store = Rails.configuration.event_store) @repository = AggregateRoot::Repository.new(event_store) end def with_order(order_id, &block) stream_name = "Order$#{order_id}" repository.with_aggregate(Order.new, stream_name, &block) end private attr_reader :repository end ``` -------------------------------- ### Implement apply_strategy with Hash lookup Source: https://railseventstore.org/docs/core-concepts/event-sourcing Shows an alternative implementation of apply_strategy using a Hash to map event types to methods. ```ruby def apply_strategy ->(aggregate, event) do { 'OrderExpired' => method(:order_has_expired), 'OrderSubmitted' => method(:order_has_been_submitted), }.fetch(event.event_type, ->(event) { raise }).call(event) end end def order_has_been_submitted(event) @state = :submitted end def order_has_expired(event) @state = :expired end ``` -------------------------------- ### Run the res_outbox process Source: https://railseventstore.org/docs/advanced-topics/outbox Execute the outbox process to drain the database table to Redis. ```bash res_outbox \ --database-url="mysql2://root@0.0.0.0:3306/my_database" \ --redis-url="redis://localhost:6379/0" \ --log-level=info \ --split-keys=sidekiq_queue1,sidekiq_queue2 ``` -------------------------------- ### Manual stream matching Source: https://railseventstore.org/docs/core-concepts/rspec A verbose approach using 'match' instead of 'have_published' for custom requirements. ```ruby expect(event_store.read.stream("OrderAuditLog$42").limit(2).to_a).to match( [an_event(OrderPlaced), an_event(OrderExpired)], ) ``` -------------------------------- ### Run res_outbox with metrics Source: https://railseventstore.org/docs/advanced-topics/outbox Execute the outbox process with an InfluxDB metrics URL configured. ```bash res_outbox --database-url="mysql2://root@0.0.0.0:3306/my_database" \ --redis-url="redis://localhost:6379/0" \ --log-level=info \ --split-keys=sidekiq_queue1,sidekiq_queue2 \ --metrics-url=http://user:password@localhost:8086/dbname ``` -------------------------------- ### Add SQL adapter gems to Gemfile Source: https://railseventstore.org/docs/advanced-topics/without-rails Include the required SQL adapter gem for your database choice. ```ruby # Gemfile # ... gem "sqlite3" gem "pg" gem "mysql2" ``` -------------------------------- ### CLI event show command Source: https://railseventstore.org/docs/core-concepts/cli Displays full details for a single event, including data and metadata, using the event ID. ```bash $ bundle exec res event show 59588873-00fa-423f-89d1-03d7c3b0ab35 Event ID: 59588873-00fa-423f-89d1-03d7c3b0ab35 Type: OrderPlaced Timestamp: 2026-03-24T17:45:03.891Z Valid at: 2026-03-24T17:45:03.891Z Data: { "order_id": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "customer_id": "c-1024", "total": "149.00" } Metadata: { "correlation_id": "452fd6f0-e3a2-4716-bc8a-43bbcf2cae61", "causation_id": "452fd6f0-e3a2-4716-bc8a-43bbcf2cae61" } ``` -------------------------------- ### Configure RES client in config/application.rb Source: https://railseventstore.org/docs/core-concepts/pubsub Configure the Rails Event Store client in the application's config/application.rb file. The client is assigned to Rails.configuration.event_store during the to_prepare hook. ```ruby # config/application.rb module YourAppName class Application < Rails::Application config.to_prepare { Rails.configuration.event_store = RailsEventStore::Client.new } end end ``` -------------------------------- ### Using the convenience alias Source: https://railseventstore.org/docs/advanced-topics/command-bus Requires the alias file to enable the use of the top-level CommandBus constant. ```ruby require "arkency/command_bus/alias" ``` -------------------------------- ### Read first 100 events forward Source: https://railseventstore.org/docs/core-concepts/read Loads the first 100 domain events stored in the event store in ascending order. ```ruby client.read.limit(100).to_a ``` -------------------------------- ### CLI search command Source: https://railseventstore.org/docs/core-concepts/cli Searches across the entire event store using filters like --type, --after, --before, and --limit, with an optional --stream scope. ```bash $ bundle exec res search --type OrderPlaced --after 2026-03-01T00:00:00Z EVENT ID TYPE TIMESTAMP ------------------------------------------------------------------------------------------ 59588873-00fa-423f-89d1-03d7c3b0ab35 OrderPlaced 2026-03-24T17:45:03.891Z 8b1f2c3d-1a2b-4c3d-9e8f-7a6b5c4d3e2f OrderPlaced 2026-03-22T09:13:55.620Z 2 event(s) ``` -------------------------------- ### Generate and run migrations for PostgreSQL Source: https://railseventstore.org/docs/getting-started/install Generate and run the migration for PostgreSQL using the jsonb data type. ```bash bin/rails generate ruby_event_store:active_record:migration --data-type=jsonb bin/rails db:migrate ```