From 51c06d4abb66fe0a6321e8d9f2da4262a8128595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Pacana?= Date: Wed, 19 Feb 2020 13:16:28 +0000 Subject: [PATCH] Read model -- example. --- app/assets/stylesheets/editions.scss | 3 +++ app/controllers/editions_controller.rb | 11 ++++++++ app/helpers/editions_helper.rb | 2 ++ app/models/edition_participant.rb | 16 +++++++++++ app/models/edition_status.rb | 6 +++++ app/views/editions/show.html.erb | 13 +++++++++ config/initializers/rails_event_store.rb | 24 +++++++++-------- config/routes.rb | 2 ++ .../20200219115300_create_edition_statuses.rb | 10 +++++++ ...00219115312_create_edition_participants.rb | 12 +++++++++ db/schema.rb | 18 ++++++++++++- produce.rb | 27 +++++++++++++++++++ test/controllers/editions_controller_test.rb | 7 +++++ test/fixtures/edition_participants.yml | 11 ++++++++ test/fixtures/edition_statuses.yml | 11 ++++++++ test/models/edition_participant_test.rb | 7 +++++ test/models/edition_status_test.rb | 7 +++++ workshops/lib/workshops.rb | 2 ++ 18 files changed, 177 insertions(+), 12 deletions(-) create mode 100644 app/assets/stylesheets/editions.scss create mode 100644 app/controllers/editions_controller.rb create mode 100644 app/helpers/editions_helper.rb create mode 100644 app/models/edition_participant.rb create mode 100644 app/models/edition_status.rb create mode 100644 app/views/editions/show.html.erb create mode 100644 db/migrate/20200219115300_create_edition_statuses.rb create mode 100644 db/migrate/20200219115312_create_edition_participants.rb create mode 100644 produce.rb create mode 100644 test/controllers/editions_controller_test.rb create mode 100644 test/fixtures/edition_participants.yml create mode 100644 test/fixtures/edition_statuses.yml create mode 100644 test/models/edition_participant_test.rb create mode 100644 test/models/edition_status_test.rb diff --git a/app/assets/stylesheets/editions.scss b/app/assets/stylesheets/editions.scss new file mode 100644 index 0000000..5806d6a --- /dev/null +++ b/app/assets/stylesheets/editions.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the editions controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: https://sass-lang.com/ diff --git a/app/controllers/editions_controller.rb b/app/controllers/editions_controller.rb new file mode 100644 index 0000000..5ba60ed --- /dev/null +++ b/app/controllers/editions_controller.rb @@ -0,0 +1,11 @@ +class EditionsController < ApplicationController + def show + edition_id = params[:id] + + render :show, locals: { + edition_id: edition_id, + participants: EditionParticipant.where(edition_id: edition_id), + edition_status: EditionStatus.find_by(edition_id: edition_id) + } + end +end diff --git a/app/helpers/editions_helper.rb b/app/helpers/editions_helper.rb new file mode 100644 index 0000000..959b9a1 --- /dev/null +++ b/app/helpers/editions_helper.rb @@ -0,0 +1,2 @@ +module EditionsHelper +end diff --git a/app/models/edition_participant.rb b/app/models/edition_participant.rb new file mode 100644 index 0000000..60c9540 --- /dev/null +++ b/app/models/edition_participant.rb @@ -0,0 +1,16 @@ +class EditionParticipant < ApplicationRecord + def self.handle_participant_event(event) + edition_id = event.data[:edition_id] + participant_id = event.data[:participant_id] + + case event + when Workshops::ParticipantPersonalDataProvided + where(participant_id: participant_id).update_all( + participant_name: event.data[:name], + participant_email: event.data[:email] + ) + when Workshops::ParticipantRegisteredForEdition + find_or_create_by(edition_id: edition_id, participant_id: participant_id) + end + end +end diff --git a/app/models/edition_status.rb b/app/models/edition_status.rb new file mode 100644 index 0000000..c94b39c --- /dev/null +++ b/app/models/edition_status.rb @@ -0,0 +1,6 @@ +class EditionStatus < ApplicationRecord + def self.handle_confirmed_event(e) + edition_id = e.data[:edition_id] + find_or_create_by(edition_id: edition_id).update(status: "confirmed") + end +end diff --git a/app/views/editions/show.html.erb b/app/views/editions/show.html.erb new file mode 100644 index 0000000..f9bf898 --- /dev/null +++ b/app/views/editions/show.html.erb @@ -0,0 +1,13 @@ +

Edition <%= edition_id %>: <%= edition_status.status %>

+ +

<%= participants.size %>

+ + +<% participants.each do |p| %> + + + + + +<% end %> +
<%= p.participant_id %><%= p.participant_name %><%= p.participant_email %>
diff --git a/config/initializers/rails_event_store.rb b/config/initializers/rails_event_store.rb index 054f64c..0bcd0d0 100644 --- a/config/initializers/rails_event_store.rb +++ b/config/initializers/rails_event_store.rb @@ -10,16 +10,18 @@ config.default_event_store = Rails.configuration.event_store end - # Subscribe event handlers below - # Rails.configuration.event_store.tap do |store| - # store.subscribe(InvoiceReadModel.new, to: [InvoicePrinted]) - # store.subscribe(->(event) { SendOrderConfirmation.new.call(event) }, to: [OrderSubmitted]) - # store.subscribe_to_all_events(->(event) { Rails.logger.info(event.type) }) - # end + Rails.configuration.event_store.tap do |store| + store.subscribe( + ->(e) { EditionParticipant.handle_participant_event(e) }, + to: [ + Workshops::ParticipantRegisteredForEdition, + Workshops::ParticipantPersonalDataProvided, + ]) - # Register command handlers below - # Rails.configuration.command_bus.tap do |bus| - # bus.register(PrintInvoice, Invoicing::OnPrint.new) - # bus.register(SubmitOrder, ->(cmd) { Ordering::OnSubmitOrder.new.call(cmd) }) - # end + store.subscribe( + ->(e) { EditionStatus.handle_confirmed_event(e) }, + to: [ + Workshops::EditionConfirmed, + ]) + end end diff --git a/config/routes.rb b/config/routes.rb index 96a6bd1..ad2e47d 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,6 @@ Rails.application.routes.draw do mount RailsEventStore::Browser => '/res' if Rails.env.development? # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html + + get '/editions/:id', to: 'editions#show' end diff --git a/db/migrate/20200219115300_create_edition_statuses.rb b/db/migrate/20200219115300_create_edition_statuses.rb new file mode 100644 index 0000000..d3a75d6 --- /dev/null +++ b/db/migrate/20200219115300_create_edition_statuses.rb @@ -0,0 +1,10 @@ +class CreateEditionStatuses < ActiveRecord::Migration[6.0] + def change + create_table :edition_statuses do |t| + t.string :edition_id + t.string :status + + t.timestamps + end + end +end diff --git a/db/migrate/20200219115312_create_edition_participants.rb b/db/migrate/20200219115312_create_edition_participants.rb new file mode 100644 index 0000000..cde3536 --- /dev/null +++ b/db/migrate/20200219115312_create_edition_participants.rb @@ -0,0 +1,12 @@ +class CreateEditionParticipants < ActiveRecord::Migration[6.0] + def change + create_table :edition_participants do |t| + t.string :edition_id + t.string :participant_id + t.string :participant_name + t.string :participant_email + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 18d690f..03906ed 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,23 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_02_19_002357) do +ActiveRecord::Schema.define(version: 2020_02_19_115312) do + + create_table "edition_participants", force: :cascade do |t| + t.string "edition_id" + t.string "participant_id" + t.string "participant_name" + t.string "participant_email" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end + + create_table "edition_statuses", force: :cascade do |t| + t.string "edition_id" + t.string "status" + t.datetime "created_at", precision: 6, null: false + t.datetime "updated_at", precision: 6, null: false + end create_table "event_store_events", id: :string, limit: 36, force: :cascade do |t| t.string "event_type", null: false diff --git a/produce.rb b/produce.rb new file mode 100644 index 0000000..f6bb974 --- /dev/null +++ b/produce.rb @@ -0,0 +1,27 @@ +event_store = Rails.configuration.event_store +edition_id = "smart-pension" +stream_name = "Edition$#{edition_id}" + +EditionParticipant.delete_all +EditionStatus.delete_all + +event_store.publish( + Workshops::EditionConfirmed.new(data: { edition_id: edition_id }), + stream_name: stream_name +) +event_store.publish( + Workshops::ParticipantRegisteredForEdition.new(data: { edition_id: edition_id, participant_id: pid1 = SecureRandom.uuid }), + stream_name: stream_name +) +event_store.publish( + Workshops::ParticipantRegisteredForEdition.new(data: { edition_id: edition_id, participant_id: pid2 = SecureRandom.uuid }), + stream_name: stream_name +) +event_store.publish( + Workshops::ParticipantPersonalDataProvided.new(data: { participant_id: pid1, name: 'Tom', email: 't@acme' }), + stream_name: stream_name +) +event_store.publish( + Workshops::ParticipantPersonalDataProvided.new(data: { participant_id: pid2, name: 'Jerry', email: 'j@acme' }), + stream_name: stream_name +) diff --git a/test/controllers/editions_controller_test.rb b/test/controllers/editions_controller_test.rb new file mode 100644 index 0000000..2a8d897 --- /dev/null +++ b/test/controllers/editions_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class EditionsControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end diff --git a/test/fixtures/edition_participants.yml b/test/fixtures/edition_participants.yml new file mode 100644 index 0000000..5181636 --- /dev/null +++ b/test/fixtures/edition_participants.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/fixtures/edition_statuses.yml b/test/fixtures/edition_statuses.yml new file mode 100644 index 0000000..5181636 --- /dev/null +++ b/test/fixtures/edition_statuses.yml @@ -0,0 +1,11 @@ +# Read about fixtures at https://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html + +# This model initially had no columns defined. If you add columns to the +# model remove the '{}' from the fixture names and add the columns immediately +# below each fixture, per the syntax in the comments below +# +one: {} +# column: value +# +two: {} +# column: value diff --git a/test/models/edition_participant_test.rb b/test/models/edition_participant_test.rb new file mode 100644 index 0000000..bf4abbf --- /dev/null +++ b/test/models/edition_participant_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class EditionParticipantTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/models/edition_status_test.rb b/test/models/edition_status_test.rb new file mode 100644 index 0000000..8af407c --- /dev/null +++ b/test/models/edition_status_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class EditionStatusTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/workshops/lib/workshops.rb b/workshops/lib/workshops.rb index d4e30ce..14e61cd 100644 --- a/workshops/lib/workshops.rb +++ b/workshops/lib/workshops.rb @@ -2,6 +2,8 @@ module Workshops ParticipantRegisteredForEdition = Class.new(RailsEventStore::Event) VenueBookedForEdition = Class.new(RailsEventStore::Event) TwoWeeksBeforeEditionReached = Class.new(RailsEventStore::Event) + ParticipantPersonalDataProvided = Class.new(RailsEventStore::Event) + EditionConfirmed = Class.new(RailsEventStore::Event) ConfirmEdition = Struct.new(:edition_id) CancelEdition = Struct.new(:edition_id)