From b8dc87155e6cb0d0421dac5b06d50236ea6146cb Mon Sep 17 00:00:00 2001 From: Juliano Quatrin Nunes Date: Fri, 10 Jan 2025 11:14:15 -0300 Subject: [PATCH] refactor: redesign badges using polymorphic association --- .../govquests/questing/lib/questing.rb | 3 +-- .../questing/lib/questing/commands.rb | 2 -- .../govquests/questing/lib/questing/events.rb | 2 -- .../govquests/questing/lib/questing/quest.rb | 3 +-- .../govquests/questing/lib/questing/track.rb | 7 ++---- .../read_models/questing/on_quest_created.rb | 13 +++++----- .../read_models/questing/on_track_created.rb | 16 ++++++------ .../read_models/questing/quest_read_model.rb | 8 ++---- .../read_models/questing/track_read_model.rb | 10 ++------ .../read_models/rewarding/badge_read_model.rb | 25 ++++++++----------- ...52_update_badges_table_with_polymorphic.rb | 11 ++++++++ ..._remove_badge_id_from_tracks_and_quests.rb | 9 +++++++ apps/govquests-api/rails_app/db/schema.rb | 9 +++---- apps/govquests-api/rails_app/db/seeds.rb | 4 --- 14 files changed, 58 insertions(+), 64 deletions(-) create mode 100644 apps/govquests-api/rails_app/db/migrate/20250110140752_update_badges_table_with_polymorphic.rb create mode 100644 apps/govquests-api/rails_app/db/migrate/20250110140933_remove_badge_id_from_tracks_and_quests.rb diff --git a/apps/govquests-api/govquests/questing/lib/questing.rb b/apps/govquests-api/govquests/questing/lib/questing.rb index c60f9503..99c2c628 100644 --- a/apps/govquests-api/govquests/questing/lib/questing.rb +++ b/apps/govquests-api/govquests/questing/lib/questing.rb @@ -25,7 +25,7 @@ def call(event_store, command_bus) class CommandHandler < Infra::CommandHandlerRegistry handle "Questing::CreateQuest", aggregate: Quest do |quest, cmd| - quest.create(cmd.display_data, cmd.audience, cmd.badge_id, cmd.badge_display_data) + quest.create(cmd.display_data, cmd.audience, cmd.badge_display_data) end handle "Questing::AssociateActionWithQuest", aggregate: Quest do |quest, cmd| @@ -56,7 +56,6 @@ class CommandHandler < Infra::CommandHandlerRegistry track.create( display_data: cmd.display_data, quest_ids: cmd.quest_ids, - badge_id: cmd.badge_id, badge_display_data: cmd.badge_display_data ) end diff --git a/apps/govquests-api/govquests/questing/lib/questing/commands.rb b/apps/govquests-api/govquests/questing/lib/questing/commands.rb index 070a9ccc..7109332a 100644 --- a/apps/govquests-api/govquests/questing/lib/questing/commands.rb +++ b/apps/govquests-api/govquests/questing/lib/questing/commands.rb @@ -5,7 +5,6 @@ class CreateQuest < Infra::Command attribute :quest_id, Infra::Types::UUID attribute :display_data, Infra::Types::Hash attribute :audience, Infra::Types::String - attribute :badge_id, Infra::Types::UUID attribute :badge_display_data, Infra::Types::Hash alias_method :aggregate_id, :quest_id @@ -54,7 +53,6 @@ class CreateTrack < Infra::Command attribute :track_id, Infra::Types::UUID attribute :display_data, Infra::Types::Hash attribute :quest_ids, Infra::Types::Array - attribute :badge_id, Infra::Types::UUID attribute :badge_display_data, Infra::Types::Hash alias_method :aggregate_id, :track_id diff --git a/apps/govquests-api/govquests/questing/lib/questing/events.rb b/apps/govquests-api/govquests/questing/lib/questing/events.rb index 3c776427..edca5617 100644 --- a/apps/govquests-api/govquests/questing/lib/questing/events.rb +++ b/apps/govquests-api/govquests/questing/lib/questing/events.rb @@ -3,7 +3,6 @@ class QuestCreated < Infra::Event attribute :quest_id, Infra::Types::UUID attribute :display_data, Infra::Types::Hash attribute :audience, Infra::Types::String - attribute :badge_id, Infra::Types::UUID attribute :badge_display_data, Infra::Types::Hash end @@ -42,7 +41,6 @@ class TrackCreated < Infra::Event attribute :track_id, Infra::Types::UUID attribute :display_data, Infra::Types::Hash attribute :quest_ids, Infra::Types::Array - attribute :badge_id, Infra::Types::UUID attribute :badge_display_data, Infra::Types::Hash end end diff --git a/apps/govquests-api/govquests/questing/lib/questing/quest.rb b/apps/govquests-api/govquests/questing/lib/questing/quest.rb index 135aa672..acf17ca9 100644 --- a/apps/govquests-api/govquests/questing/lib/questing/quest.rb +++ b/apps/govquests-api/govquests/questing/lib/questing/quest.rb @@ -13,14 +13,13 @@ def initialize(id) @reward_pools = {} end - def create(display_data, audience, badge_id, badge_display_data) + def create(display_data, audience, badge_display_data) display_data ||= {} apply QuestCreated.new(data: { quest_id: @id, display_data: display_data, audience: audience, - badge_id: badge_id, badge_display_data: badge_display_data }) end diff --git a/apps/govquests-api/govquests/questing/lib/questing/track.rb b/apps/govquests-api/govquests/questing/lib/questing/track.rb index 39b2a0aa..73ab3566 100644 --- a/apps/govquests-api/govquests/questing/lib/questing/track.rb +++ b/apps/govquests-api/govquests/questing/lib/questing/track.rb @@ -9,10 +9,9 @@ def initialize(id) @id = id @quests = [] @display_data = nil - @badge_id = nil end - def create(display_data:, quest_ids:, badge_id:, badge_display_data:) + def create(display_data:, quest_ids:, badge_display_data:) raise AlreadyExists if @display_data apply TrackCreated.new( @@ -20,7 +19,6 @@ def create(display_data:, quest_ids:, badge_id:, badge_display_data:) track_id: @id, display_data: display_data, quest_ids: quest_ids, - badge_id: badge_id, badge_display_data: badge_display_data } ) @@ -29,8 +27,7 @@ def create(display_data:, quest_ids:, badge_id:, badge_display_data:) on TrackCreated do |event| @display_data = event.data[:display_data] @quest_ids = event.data[:quest_ids] - @badge_id = event.data[:badge_id] - @display_data = event.data[:badge_display_data] + @badge_display_data = event.data[:badge_display_data] end end end diff --git a/apps/govquests-api/rails_app/app/read_models/questing/on_quest_created.rb b/apps/govquests-api/rails_app/app/read_models/questing/on_quest_created.rb index 17807507..f5de2a10 100644 --- a/apps/govquests-api/rails_app/app/read_models/questing/on_quest_created.rb +++ b/apps/govquests-api/rails_app/app/read_models/questing/on_quest_created.rb @@ -1,21 +1,22 @@ module Questing class OnQuestCreated def call(event) - Rewarding::BadgeReadModel.create!( - badge_id: event.data[:badge_id], - display_data: event.data[:badge_display_data] - ) - slug = event.data[:display_data][:title].downcase.tr(" ", "-") quest = QuestReadModel.create!( quest_id: event.data[:quest_id], - badge_id: event.data[:badge_id], slug: slug, audience: event.data[:audience], status: "created", display_data: event.data[:display_data] ) + + badge_id = SecureRandom.uuid + Rewarding::BadgeReadModel.create!( + badge_id: badge_id, + display_data: event.data[:badge_display_data], + badgeable: quest + ) Rails.logger.info "Quest created in read model: #{quest.quest_id}" end end diff --git a/apps/govquests-api/rails_app/app/read_models/questing/on_track_created.rb b/apps/govquests-api/rails_app/app/read_models/questing/on_track_created.rb index 7a227050..ed473e19 100644 --- a/apps/govquests-api/rails_app/app/read_models/questing/on_track_created.rb +++ b/apps/govquests-api/rails_app/app/read_models/questing/on_track_created.rb @@ -1,15 +1,17 @@ module Questing class OnTrackCreated def call(event) - Rewarding::BadgeReadModel.create!( - badge_id: event.data[:badge_id], - display_data: event.data[:badge_display_data] - ) - TrackReadModel.create!( + track = TrackReadModel.create!( track_id: event.data[:track_id], display_data: event.data[:display_data], - quest_ids: event.data[:quest_ids], - badge_id: event.data[:badge_id] + quest_ids: event.data[:quest_ids] + ) + + badge_id = SecureRandom.uuid + Rewarding::BadgeReadModel.create!( + badge_id: badge_id, + display_data: event.data[:badge_display_data], + badgeable: track ) end end diff --git a/apps/govquests-api/rails_app/app/read_models/questing/quest_read_model.rb b/apps/govquests-api/rails_app/app/read_models/questing/quest_read_model.rb index ca73275e..9e1b8fae 100644 --- a/apps/govquests-api/rails_app/app/read_models/questing/quest_read_model.rb +++ b/apps/govquests-api/rails_app/app/read_models/questing/quest_read_model.rb @@ -13,11 +13,9 @@ class QuestReadModel < ApplicationRecord validates :status, presence: true validates :display_data, presence: true - belongs_to :badge, + has_one :badge, class_name: "Rewarding::BadgeReadModel", - foreign_key: "badge_id", - primary_key: "badge_id", - optional: true + as: :badgeable end end @@ -32,11 +30,9 @@ class QuestReadModel < ApplicationRecord # status :string not null # created_at :datetime not null # updated_at :datetime not null -# badge_id :string # quest_id :string not null # # Indexes # -# index_quests_on_badge_id (badge_id) # index_quests_on_quest_id (quest_id) UNIQUE # diff --git a/apps/govquests-api/rails_app/app/read_models/questing/track_read_model.rb b/apps/govquests-api/rails_app/app/read_models/questing/track_read_model.rb index a43411c4..08d8b8b0 100644 --- a/apps/govquests-api/rails_app/app/read_models/questing/track_read_model.rb +++ b/apps/govquests-api/rails_app/app/read_models/questing/track_read_model.rb @@ -3,21 +3,17 @@ class TrackReadModel < ApplicationRecord self.table_name = "tracks" attribute :quest_ids, :jsonb, array: true - attribute :badge_id, :string validates :track_id, presence: true, uniqueness: true validates :display_data, presence: true - validates :badge_id, presence: true, allow_nil: true def quests QuestReadModel.where(quest_id: quest_ids) end - belongs_to :badge, + has_one :badge, class_name: "Rewarding::BadgeReadModel", - foreign_key: "badge_id", - primary_key: "badge_id", - optional: true + as: :badgeable end end @@ -30,11 +26,9 @@ def quests # quest_ids :jsonb is an Array # created_at :datetime not null # updated_at :datetime not null -# badge_id :string # track_id :string not null # # Indexes # -# index_tracks_on_badge_id (badge_id) # index_tracks_on_track_id (track_id) UNIQUE # diff --git a/apps/govquests-api/rails_app/app/read_models/rewarding/badge_read_model.rb b/apps/govquests-api/rails_app/app/read_models/rewarding/badge_read_model.rb index c5a909f5..e1a4ffc4 100644 --- a/apps/govquests-api/rails_app/app/read_models/rewarding/badge_read_model.rb +++ b/apps/govquests-api/rails_app/app/read_models/rewarding/badge_read_model.rb @@ -2,15 +2,7 @@ module Rewarding class BadgeReadModel < ApplicationRecord self.table_name = "badges" - has_many :tracks, - class_name: "Tracking::TrackReadModel", - foreign_key: "badge_id", - primary_key: "badge_id" - - has_many :quests, - class_name: "Questing::QuestReadModel", - foreign_key: "badge_id", - primary_key: "badge_id" + belongs_to :badgeable, polymorphic: true validates :badge_id, presence: true, uniqueness: true validates :display_data, presence: true @@ -21,13 +13,16 @@ class BadgeReadModel < ApplicationRecord # # Table name: badges # -# id :bigint not null, primary key -# display_data :jsonb not null -# created_at :datetime not null -# updated_at :datetime not null -# badge_id :string not null +# id :bigint not null, primary key +# badgeable_type :string not null +# display_data :jsonb not null +# created_at :datetime not null +# updated_at :datetime not null +# badge_id :string not null +# badgeable_id :string not null # # Indexes # -# index_badges_on_badge_id (badge_id) UNIQUE +# index_badges_on_badge_id (badge_id) UNIQUE +# index_badges_on_badgeable_type_and_badgeable_id (badgeable_type,badgeable_id) UNIQUE # diff --git a/apps/govquests-api/rails_app/db/migrate/20250110140752_update_badges_table_with_polymorphic.rb b/apps/govquests-api/rails_app/db/migrate/20250110140752_update_badges_table_with_polymorphic.rb new file mode 100644 index 00000000..f5967272 --- /dev/null +++ b/apps/govquests-api/rails_app/db/migrate/20250110140752_update_badges_table_with_polymorphic.rb @@ -0,0 +1,11 @@ +class UpdateBadgesTableWithPolymorphic < ActiveRecord::Migration[8.1] + def change + remove_column :badges, :track_id if column_exists?(:badges, :track_id) + remove_column :badges, :quest_id if column_exists?(:badges, :quest_id) + + add_column :badges, :badgeable_type, :string, null: false + add_column :badges, :badgeable_id, :string, null: false + + add_index :badges, [:badgeable_type, :badgeable_id], unique: true + end +end diff --git a/apps/govquests-api/rails_app/db/migrate/20250110140933_remove_badge_id_from_tracks_and_quests.rb b/apps/govquests-api/rails_app/db/migrate/20250110140933_remove_badge_id_from_tracks_and_quests.rb new file mode 100644 index 00000000..81f0fc2f --- /dev/null +++ b/apps/govquests-api/rails_app/db/migrate/20250110140933_remove_badge_id_from_tracks_and_quests.rb @@ -0,0 +1,9 @@ +class RemoveBadgeIdFromTracksAndQuests < ActiveRecord::Migration[8.1] + def change + remove_index :tracks, :badge_id + remove_index :quests, :badge_id + + remove_column :tracks, :badge_id + remove_column :quests, :badge_id + end +end diff --git a/apps/govquests-api/rails_app/db/schema.rb b/apps/govquests-api/rails_app/db/schema.rb index 0cbe71c4..8d7351c6 100644 --- a/apps/govquests-api/rails_app/db/schema.rb +++ b/apps/govquests-api/rails_app/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[8.1].define(version: 2025_01_07_210235) do +ActiveRecord::Schema[8.1].define(version: 2025_01_10_140933) do # These are extensions that must be enabled in order to support this database enable_extension "pg_catalog.plpgsql" @@ -47,7 +47,10 @@ t.jsonb "display_data", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.string "badgeable_type", null: false + t.string "badgeable_id", null: false t.index ["badge_id"], name: "index_badges_on_badge_id", unique: true + t.index ["badgeable_type", "badgeable_id"], name: "index_badges_on_badgeable_type_and_badgeable_id", unique: true end create_table "event_store_events", force: :cascade do |t| @@ -134,8 +137,6 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.string "slug" - t.string "badge_id" - t.index ["badge_id"], name: "index_quests_on_badge_id" t.index ["quest_id"], name: "index_quests_on_quest_id", unique: true end @@ -183,8 +184,6 @@ t.datetime "created_at", null: false t.datetime "updated_at", null: false t.jsonb "quest_ids", default: [], array: true - t.string "badge_id" - t.index ["badge_id"], name: "index_tracks_on_badge_id" t.index ["track_id"], name: "index_tracks_on_track_id", unique: true end diff --git a/apps/govquests-api/rails_app/db/seeds.rb b/apps/govquests-api/rails_app/db/seeds.rb index 8f43a030..7e19a640 100644 --- a/apps/govquests-api/rails_app/db/seeds.rb +++ b/apps/govquests-api/rails_app/db/seeds.rb @@ -17,14 +17,12 @@ def self.create_action(action_data) module QuestCreation def self.create_quest_with_rewards(quest_data) quest_id = SecureRandom.uuid - badge_id = SecureRandom.uuid Rails.configuration.command_bus.call( Questing::CreateQuest.new( quest_id: quest_id, display_data: quest_data[:display_data], audience: quest_data[:audience], - badge_id: badge_id, badge_display_data: quest_data[:badge_display_data] ) ) @@ -69,14 +67,12 @@ def self.associate_action_with_quest(quest_id, action_id, position) module TrackCreation def self.create_track_with_quests(track_data, quest_id_map) track_id = SecureRandom.uuid - badge_id = SecureRandom.uuid Rails.configuration.command_bus.call( Questing::CreateTrack.new( track_id: track_id, display_data: track_data[:display_data], quest_ids: track_data[:quests].map { |quest_title| quest_id_map[quest_title] }, - badge_id: badge_id, badge_display_data: track_data[:badge_display_data] ) )