Class: OnlineMigrations::DataMigrations::BackfillQuoteBuilderToIq
- Inherits:
-
OnlineMigrations::DataMigration
- Object
- OnlineMigrations::DataMigration
- OnlineMigrations::DataMigrations::BackfillQuoteBuilderToIq
- Defined in:
- lib/online_migrations/data_migrations/backfill_quote_builder_to_iq.rb
Overview
Folds the short-lived 'QuoteBuilder' reception-type literal back
into the canonical 'IQ' ("Instant Quote") value on the two
columns that carry reception type:
- opportunities.opportunity_reception_type (~195 rows since
2025-12-24) - room_configurations.reception_type (~8,552 rows)
Background: the December 2025 quote-builder rewrite started writing
'QuoteBuilder' as a new label for the same flow that had been
tagged 'IQ' since 2013 (~59,137 opportunity rows + ~13,711 room
rows). Carrying both literals confused tooling — most visibly the
AI assistant, which silently filtered to one or the other and gave
the team inconsistent quote-builder conversion stats for the same
question (chats /assistant/2475 and /assistant/2477).
The team's call: standardize on 'IQ' going forward — it has the
longer historical run, it's already what RoomConfiguration#room_prefix
branches on (legacy IQR rooms keep their IPR reference numbers
generated from reception_type == 'IQ'), it's already what
Quote::INSTANT_QUOTE = 'IQ' and the Delivery#instant_quote?
predicate hardcode, and 'Quote Builder' survives as the
user-facing feature name (URL /quote-builder, page heading,
QuoteBuilder::ProjectCreator class name) without leaking into
the database literal.
Constant Summary collapse
- BATCH_SIZE =
Batch size — small enough to keep each transaction quick on
the two reception-type tables, large enough that the ~8.7k
rows finish in reasonable time at the iteration_pause cadence. 1_000- TARGETS =
Tables and the column on each that holds the reception-type
literal. The two updates are independent. [ { model: ::Opportunity, column: :opportunity_reception_type }, { model: ::RoomConfiguration, column: :reception_type } ].freeze
Instance Method Summary collapse
-
#collection ⇒ Array<Array(Class, Symbol, Array<Integer>)>
Returns one
[model_class, column_name, ids]tuple per batch across the target tables. -
#count ⇒ Integer
Total un-migrated rows across the target tables.
-
#process(batch) ⇒ void
Switches one batch of rows from
'QuoteBuilder'to'IQ'viaupdate_all.
Instance Method Details
#collection ⇒ Array<Array(Class, Symbol, Array<Integer>)>
Returns one [model_class, column_name, ids] tuple per batch
across the target tables. process dispatches the right
update_all per tuple.
Returned eagerly as an Array (not a streaming Enumerator)
because online_migrations' MigrationJob#build_enumerator
only handles ActiveRecord::Relation, BatchEnumerator, and
Array from #collection — a plain Enumerator raises
ArgumentError before on_start runs and leaves the row
wedged at status='enqueued'. The eager pass is cheap here:
the two source tables hold ~8.7k matching rows total, which
produces only ~9 tuples at BATCH_SIZE=1_000.
65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/online_migrations/data_migrations/backfill_quote_builder_to_iq.rb', line 65 def collection batches = [] TARGETS.each do |target| target[:model] .where(target[:column] => "QuoteBuilder") .in_batches(of: BATCH_SIZE) do |batch| batches << [target[:model], target[:column], batch.ids] end end batches end |
#count ⇒ Integer
Total un-migrated rows across the target tables. Drives the
online_migrations progress bar.
95 96 97 |
# File 'lib/online_migrations/data_migrations/backfill_quote_builder_to_iq.rb', line 95 def count TARGETS.sum { |t| t[:model].where(t[:column] => "QuoteBuilder").count } end |
#process(batch) ⇒ void
This method returns an undefined value.
Switches one batch of rows from 'QuoteBuilder' to 'IQ' via
update_all. The conditional where(column => 'QuoteBuilder')
makes the write idempotent — already-migrated rows are left
alone on a re-run (no updated_at churn).
85 86 87 88 89 |
# File 'lib/online_migrations/data_migrations/backfill_quote_builder_to_iq.rb', line 85 def process(batch) model, column, ids = batch model.where(id: ids, column => "QuoteBuilder") .update_all(column => "IQ", updated_at: Time.current) end |