From 45137fe00d57df6078478496cf2569a6393d5d9e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 07:13:00 +0000 Subject: [PATCH 1/4] Initial plan From e1c9988710c32b74a0a48140ac2ddcdb5c08fa15 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 07:17:05 +0000 Subject: [PATCH 2/4] Changes before error encountered Co-authored-by: maebeale <7607813+maebeale@users.noreply.github.com> --- app/models/quote.rb | 2 +- app/models/report.rb | 8 +------ app/models/workshop.rb | 3 +-- .../20260215071524_add_quotable_to_quotes.rb | 5 +++++ ..._migrate_quotable_item_quotes_to_quotes.rb | 22 +++++++++++++++++++ 5 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 db/migrate/20260215071524_add_quotable_to_quotes.rb create mode 100644 db/migrate/20260215071525_migrate_quotable_item_quotes_to_quotes.rb diff --git a/app/models/quote.rb b/app/models/quote.rb index d3601ef70..15b8f32ca 100644 --- a/app/models/quote.rb +++ b/app/models/quote.rb @@ -2,8 +2,8 @@ class Quote < ApplicationRecord include Publishable, TagFilterable, Trendable, WindowsTypeFilterable belongs_to :workshop, optional: true + belongs_to :quotable, polymorphic: true, optional: true has_many :bookmarks, as: :bookmarkable, dependent: :destroy - has_many :quotable_item_quotes, dependent: :destroy has_many :categorizable_items, dependent: :destroy, inverse_of: :categorizable, as: :categorizable has_many :sectorable_items, dependent: :destroy, inverse_of: :sectorable, as: :sectorable # Asset associations diff --git a/app/models/report.rb b/app/models/report.rb index 98e76dc25..0b64dbd95 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -7,7 +7,7 @@ class Report < ApplicationRecord has_one :form, as: :owner has_many :bookmarks, as: :bookmarkable, dependent: :destroy has_many :notifications, as: :noticeable, dependent: :destroy - has_many :quotable_item_quotes, as: :quotable, dependent: :nullify, inverse_of: :quotable + has_many :quotes, as: :quotable, dependent: :destroy has_many :report_form_field_answers, foreign_key: :report_id, inverse_of: :report, dependent: :destroy @@ -25,12 +25,6 @@ class Report < ApplicationRecord # has_many through has_many :form_fields, through: :form - has_many :all_quotable_item_quotes, - ->(wl) { where(quotable_id: wl.id, - quotable_type: %w[WorkshopLog Report]) }, # needed bc some are stored w type Report - class_name: "QuotableItemQuote", - inverse_of: :quotable - has_many :quotes, through: :all_quotable_item_quotes, dependent: :nullify has_many :sectors, through: :sectorable_items, dependent: :destroy # Nested attributes diff --git a/app/models/workshop.rb b/app/models/workshop.rb index 106eb5975..16b7f9bb7 100644 --- a/app/models/workshop.rb +++ b/app/models/workshop.rb @@ -27,7 +27,7 @@ def self.mentionable_rich_text_fields has_many :bookmarks, as: :bookmarkable, dependent: :destroy has_many :categorizable_items, dependent: :destroy, inverse_of: :categorizable, as: :categorizable - has_many :quotable_item_quotes, as: :quotable, dependent: :destroy + has_many :quotes, as: :quotable, dependent: :destroy has_many :associated_resources, class_name: "Resource", foreign_key: "workshop_id", dependent: :restrict_with_error has_many :sectorable_items, dependent: :destroy, inverse_of: :sectorable, as: :sectorable has_many :workshop_logs, dependent: :destroy, as: :owner @@ -51,7 +51,6 @@ def self.mentionable_rich_text_fields has_many :categories, through: :categorizable_items has_many :category_types, through: :categories has_many :organizations, through: :user - has_many :quotes, through: :quotable_item_quotes has_many :resources, through: :workshop_resources, source: :resource has_many :sectors, through: :sectorable_items diff --git a/db/migrate/20260215071524_add_quotable_to_quotes.rb b/db/migrate/20260215071524_add_quotable_to_quotes.rb new file mode 100644 index 000000000..91ee2d8bc --- /dev/null +++ b/db/migrate/20260215071524_add_quotable_to_quotes.rb @@ -0,0 +1,5 @@ +class AddQuotableToQuotes < ActiveRecord::Migration[8.1] + def change + add_reference :quotes, :quotable, polymorphic: true, index: true + end +end diff --git a/db/migrate/20260215071525_migrate_quotable_item_quotes_to_quotes.rb b/db/migrate/20260215071525_migrate_quotable_item_quotes_to_quotes.rb new file mode 100644 index 000000000..455d9c1e3 --- /dev/null +++ b/db/migrate/20260215071525_migrate_quotable_item_quotes_to_quotes.rb @@ -0,0 +1,22 @@ +class MigrateQuotableItemQuotesToQuotes < ActiveRecord::Migration[8.1] + def up + # Copy quotable associations from quotable_item_quotes to quotes + execute <<-SQL.squish + UPDATE quotes + INNER JOIN quotable_item_quotes ON quotes.id = quotable_item_quotes.quote_id + SET quotes.quotable_id = quotable_item_quotes.quotable_id, + quotes.quotable_type = quotable_item_quotes.quotable_type + SQL + end + + def down + # Rollback: clear quotable associations from quotes + # Note: This doesn't restore the quotable_item_quotes records + # as they should still exist for rollback purposes + execute <<-SQL.squish + UPDATE quotes + SET quotes.quotable_id = NULL, + quotes.quotable_type = NULL + SQL + end +end From 6622b665104d926bfcf54b5e3974bd8dd6d7df5a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 15 Feb 2026 21:48:25 +0000 Subject: [PATCH 3/4] Complete conversion from quotable_item_quotes to direct quotes relationship Co-authored-by: maebeale <7607813+maebeale@users.noreply.github.com> --- app/controllers/workshop_logs_controller.rb | 20 ++--------- app/decorators/quote_decorator.rb | 2 +- app/models/report.rb | 3 +- app/views/quotes/index.html.erb | 10 +++--- app/views/quotes/show.html.erb | 8 ++--- app/views/workshop_logs/_form.html.erb | 6 ++-- .../workshop_logs/_quote_fields.html.erb | 35 +++++++++++++++++++ spec/models/quote_spec.rb | 6 ++-- spec/models/report_spec.rb | 5 ++- spec/models/workshop_spec.rb | 3 +- 10 files changed, 56 insertions(+), 42 deletions(-) create mode 100644 app/views/workshop_logs/_quote_fields.html.erb diff --git a/app/controllers/workshop_logs_controller.rb b/app/controllers/workshop_logs_controller.rb index 4a4952bc6..af4f919eb 100644 --- a/app/controllers/workshop_logs_controller.rb +++ b/app/controllers/workshop_logs_controller.rb @@ -143,17 +143,8 @@ def set_form_variables .order(title: :asc) # Build one blank quote if none exists - @workshop_log.quotable_item_quotes.each do |qiq| - qiq.build_quote unless qiq.quote - qiq.quotable = @workshop_log - end - - # Always build at least one new blank quotable_item_quote - if @workshop_log.quotable_item_quotes.empty? - qiq = @workshop_log.quotable_item_quotes.build - qiq.build_quote - qiq.quotable = @workshop_log - end + # Always build at least one new blank quote + @workshop_log.quotes.build if @workshop_log.quotes.empty? # @sectors = Sector.published.map{ |si| [ si.id, si.name ] } # @files = MediaFile.where(["workshop_log_id = ?", @workshop_log.id]) @@ -199,12 +190,7 @@ def workshop_log_params :children_ongoing, :children_first_time, :teens_ongoing, :teens_first_time, :adults_ongoing, :adults_first_time, :owner_id, :owner_type, :user_id, :organization_id, :date, :workshop_name, :workshop_id, :windows_type_id, :other_description, :external_workshop_title, # :user, - quotable_item_quotes_attributes: [ - :id, :quotable_type, :quotable_id, :_destroy, - quote_attributes: [ :id, :quote, :age, :workshop_id, :_destroy ] ], - all_quotable_item_quotes_attributes: [ - :id, :quotable_type, :quotable_id, :_destroy, - quote_attributes: [ :id, :quote, :age, :workshop_id, :_destroy ] ], + quotes_attributes: [ :id, :quote, :age, :speaker_name, :workshop_id, :_destroy ], report_form_field_answers_attributes: [ :id, :form_field_id, :answer_option_id, :answer, :report_id, :_destroy ], gallery_assets_attributes: [ :id, :file, :_destroy ]) diff --git a/app/decorators/quote_decorator.rb b/app/decorators/quote_decorator.rb index a7903aebb..8cce05d79 100644 --- a/app/decorators/quote_decorator.rb +++ b/app/decorators/quote_decorator.rb @@ -9,7 +9,7 @@ def detail(length: nil) end def created_by # TODO - add to model and quote creation - object.quotable_item_quotes.last&.quotable&.decorate&.created_by + object.quotable&.decorate&.created_by end def quote diff --git a/app/models/report.rb b/app/models/report.rb index 0b64dbd95..21c07227d 100644 --- a/app/models/report.rb +++ b/app/models/report.rb @@ -31,8 +31,7 @@ class Report < ApplicationRecord accepts_nested_attributes_for :media_files, allow_destroy: true, reject_if: :all_blank accepts_nested_attributes_for :primary_asset, allow_destroy: true, reject_if: :all_blank accepts_nested_attributes_for :gallery_assets, allow_destroy: true, reject_if: :all_blank - accepts_nested_attributes_for :all_quotable_item_quotes, allow_destroy: true, reject_if: :all_blank - accepts_nested_attributes_for :quotable_item_quotes, allow_destroy: true, reject_if: :all_blank + accepts_nested_attributes_for :quotes, allow_destroy: true, reject_if: :all_blank accepts_nested_attributes_for :report_form_field_answers, reject_if: proc { |object| object["_create"].to_i == 0 && object["answer"].nil? } diff --git a/app/views/quotes/index.html.erb b/app/views/quotes/index.html.erb index 02200f6e4..9dc81bbc1 100644 --- a/app/views/quotes/index.html.erb +++ b/app/views/quotes/index.html.erb @@ -57,12 +57,10 @@ <%= "@ " + quote.created_at.strftime("%m-%d-%-Y") %> <%= ("re " + link_to(quote.workshop.title, workshop_path(quote.workshop), class: "hover:underline") if quote.workshop).to_s.html_safe %> - <% quote.quotable_item_quotes.each do |qiq| %> - <% if qiq.quotable %> - from: <%= link_to qiq.quotable.title, - polymorphic_path(qiq.quotable), - class: "hover:underline" %> - <% end %> + <% if quote.quotable %> + from: <%= link_to quote.quotable.title, + polymorphic_path(quote.quotable), + class: "hover:underline" %> <% end %> diff --git a/app/views/quotes/show.html.erb b/app/views/quotes/show.html.erb index 6d00355c4..af6badb9b 100644 --- a/app/views/quotes/show.html.erb +++ b/app/views/quotes/show.html.erb @@ -72,11 +72,11 @@ <% end %>