Module: LtreePaths

Defined in:
app/constants/ltree_paths.rb

Overview

Hardcoded ltree paths for common product categories and product lines.
These eliminate the need for database lookups when filtering by known hierarchies.

IMPORTANT: These use SLUG-BASED paths (e.g., 'floor_heating.tempzone') NOT ID-based paths.
Slug paths are more readable and stable than IDs which can change if records are deleted/recreated.

Usage in scopes:
where('pc_path_slugs <@ ?', LtreePaths::PC_GOODS)
where('primary_pl_path_slugs <@ ?', LtreePaths::PL_FLOOR_HEATING)

For Item queries, use the slug columns on items table:
Item.where('pc_path_slugs <@ ?', LtreePaths::PC_HEATING_ELEMENTS)

IMPORTANT: If the hierarchy structure changes (parent reassignment or rename), these paths
must be updated. Run rails runner "LtreePaths.verify_all" to check validity.

Constant Summary collapse

PC_GOODS =

===========================================================================
Product Category paths (use pc_path_slugs column)
Format: category_name.subcategory_name (underscored slugs)

'goods'
PC_SERVICES =
'services'
PC_SHIPPING =
'shipping'
PC_SHIPPING_AND_HANDLING =
'shipping_and_handling'
PC_HEATING_ELEMENTS =
'goods.heating_elements'
PC_HEATING_ELEMENTS_HEATING_CABLES =
'goods.heating_elements.heating_cables'
PC_HEATING_ELEMENTS_CUSTOM_MATS =
'goods.heating_elements.heating_custom_mats'
PC_HEATING_ELEMENTS_COUNTERTOP =
'goods.heating_elements.countertop_heaters'
PC_CONTROLS =
'goods.controls'
PC_CONTROLS_THERMOSTATS =
'goods.controls.thermostats'
PC_ACCESSORIES =
'goods.accessories'
PC_ACCESSORIES_INSULATIONS =
'goods.accessories.insulations'
PC_ACCESSORIES_MEMBRANES =
'goods.accessories.membranes'
PC_SPARE_PARTS =
'goods.spare_parts'
PC_SPARE_PARTS_COLD_LEADS =
'goods.spare_parts.cold_leads'
PC_TOOLS =
'goods.tools'
PC_POWER =
'goods.power'
PC_POWER_RELAY_PANELS =
'goods.power.relay_panels'
PC_POWER_MODULES =
'goods.power.modules'
PC_SENSORS =
'goods.sensors'
PC_TOWEL_WARMERS =
'goods.towel_warmers'
PC_TOWEL_WARMERS_PLUG_IN =
'goods.towel_warmers.plug_in'
PC_TOWEL_WARMERS_HARDWIRED =
'goods.towel_warmers.hardwired'
PC_TOWEL_WARMERS_DUAL_CONNECTION =
'goods.towel_warmers.dual_connection'
PC_MIRROR_DEFOGGERS =
'goods.mirror_defoggers'
PC_MIRRORS =
'goods.mirrors'
PC_RADIANT_PANELS =
'goods.radiant_panels'
PC_RADIANT_PANELS_PLUG_IN =
'goods.radiant_panels.plug_in'
PC_RADIANT_PANELS_HARDWIRED =
'goods.radiant_panels.hardwired'
PC_UPGRADES =
'goods.upgrades'
PC_PUBLICATIONS =
'goods.publications'
PC_PUBLICATIONS_INSTALLATION =
'goods.publications.installation'
PL_FLOOR_HEATING =

===========================================================================
Product Line paths (use primary_pl_path_slugs column)
Format: product_line_name.child_name (underscored slugs)

'floor_heating'
PL_FLOOR_HEATING_TEMPZONE =
'floor_heating.tempzone'
PL_FLOOR_HEATING_TEMPZONE_FLEX_ROLL =
'floor_heating.tempzone.flex_roll'
PL_FLOOR_HEATING_TEMPZONE_EASY_MAT =
'floor_heating.tempzone.easy_mat'
PL_FLOOR_HEATING_TEMPZONE_CABLE =
'floor_heating.tempzone.cable'
PL_FLOOR_HEATING_TEMPZONE_THIN_CABLE =
'floor_heating.tempzone.thin_cable'
PL_FLOOR_HEATING_TEMPZONE_RULER_CABLE =
'floor_heating.tempzone.ruler_cable'
PL_FLOOR_HEATING_TEMPZONE_SHOWER_MAT =
'floor_heating.tempzone.shower_mat'
PL_FLOOR_HEATING_TEMPZONE_INSTALLATION_KITS =
'floor_heating.tempzone.installation_kits'
PL_FLOOR_HEATING_TEMPZONE_CUSTOM_MAT =
'floor_heating.tempzone.custom_mat'
PL_FLOOR_HEATING_TEMPZONE_EASY_MAT_TWIN =
'floor_heating.tempzone.easy_mat.twin_conductor'
PL_FLOOR_HEATING_TEMPZONE_FLEX_ROLL_TWIN_120V =
'floor_heating.tempzone.flex_roll.twin_conductor.120_v'
PL_FLOOR_HEATING_TEMPZONE_FLEX_ROLL_TWIN_240V =
'floor_heating.tempzone.flex_roll.twin_conductor.240_v'
PL_FLOOR_HEATING_ROUGH_IN_KITS =
'floor_heating.rough_in_kits'
PL_FLOOR_HEATING_ENVIRON =
'floor_heating.environ'
PL_FLOOR_HEATING_ENVIRON_FLEX_ROLL =
'floor_heating.environ.flex_roll'
PL_FLOOR_HEATING_ENVIRON_EASY_MAT =
'floor_heating.environ.easy_mat'
PL_FLOOR_HEATING_SLAB_HEAT =
'floor_heating.slab_heat'
PL_FLOOR_HEATING_SLAB_HEAT_MAT =
'floor_heating.slab_heat.mat'
PL_FLOOR_HEATING_SLAB_HEAT_CABLE =
'floor_heating.slab_heat.cable'
PL_FLOOR_HEATING_UNDERLAYMENT =
'floor_heating.underlayment'
PL_FLOOR_HEATING_UNDERLAYMENT_CORK =
'floor_heating.underlayment.cork'
PL_FLOOR_HEATING_UNDERLAYMENT_CERAZORB =
'floor_heating.underlayment.cerazorb'
PL_FLOOR_HEATING_UNDERLAYMENT_THERMALSHEET =
'floor_heating.underlayment.thermalsheet'
PL_FLOOR_HEATING_UNDERLAYMENT_PRODESO =
'floor_heating.underlayment.prodeso'
PL_LED_MIRROR_MADE_TO_ORDER =
'led_mirror.made_to_order'
PL_FLOOR_HEATING_CONTROL =
'floor_heating.control'
PL_FLOOR_HEATING_CONTROL_SMARTSTAT =
'floor_heating.control.smartstat'
PL_FLOOR_HEATING_CONTROL_EASYSTAT =
'floor_heating.control.easystat'
PL_FLOOR_HEATING_CONTROL_INTEGRATION =
'floor_heating.control.integration'
PL_FLOOR_HEATING_CONTROL_NSPIRE_TOUCH =
'floor_heating.control.nspire_touch'
PL_FLOOR_HEATING_CONTROL_NSPIRE_TOUCH_WIFI =
'floor_heating.control.nspire_touch_wifi'
PL_FLOOR_HEATING_CONTROL_NJOY_WIFI =
'floor_heating.control.njoy_wifi'
PL_FLOOR_HEATING_CONTROL_NHANCE =
'floor_heating.control.nhance'
PL_FLOOR_HEATING_CONTROL_NTRUST =
'floor_heating.control.ntrust'
PL_FLOOR_HEATING_CONTROL_NTRUST2 =
'floor_heating.control.ntrust2'
PL_OJ_PROGRAMMABLE_TSTAT_LINES =

OJ Programmable Thermostat product lines (nSpire, nJoy, nHance, nTrust series)

[
  PL_FLOOR_HEATING_CONTROL_NSPIRE_TOUCH,
  PL_FLOOR_HEATING_CONTROL_NSPIRE_TOUCH_WIFI,
  PL_FLOOR_HEATING_CONTROL_NJOY_WIFI,
  PL_FLOOR_HEATING_CONTROL_NHANCE,
  PL_FLOOR_HEATING_CONTROL_NTRUST,
  PL_FLOOR_HEATING_CONTROL_NTRUST2
].freeze
PL_SNOW_MELTING =
'snow_melting'
PL_SNOW_MELTING_MAT =
'snow_melting.mat'
PL_SNOW_MELTING_CABLE =
'snow_melting.cable'
PL_SNOW_MELTING_CONTROL =
'snow_melting.control'
PL_ROOF_GUTTER_DEICING =
'roof_gutter_deicing'
PL_ROOF_GUTTER_DEICING_CONTROL =
'roof_gutter_deicing.self_regulating_cut_to_length_cable.control'
PL_PIPE_FREEZE_PROTECTION =
'pipe_freeze_protection'
PL_PIPE_FREEZE_PROTECTION_SELF_REG =
'pipe_freeze_protection.self_regulating_cable'
PL_PIPE_FREEZE_PROTECTION_CONTROL =
'pipe_freeze_protection.self_regulating_cable.pipe_freeze_control'
PL_ROOF_GUTTER_DEICING_SELF_REG =
'roof_gutter_deicing.self_regulating_cut_to_length_cable'
PL_RADIANT_PANEL =
'radiant_panel'
PL_RADIANT_PANEL_CONTROL =
'radiant_panel.control'
PL_TOWEL_WARMER_CONTROL =
'towel_warmer.control'
PL_COUNTERTOP_HEATER_CONTROL =
'countertop_heater.control'
PL_ALL_CONTROLS =

All control product lines (for electrical plan controls)

[
  PL_FLOOR_HEATING_CONTROL,
  PL_SNOW_MELTING_CONTROL,
  PL_ROOF_GUTTER_DEICING_CONTROL,
  PL_PIPE_FREEZE_PROTECTION_CONTROL,
  PL_RADIANT_PANEL_CONTROL,
  PL_TOWEL_WARMER_CONTROL,
  PL_COUNTERTOP_HEATER_CONTROL
].freeze
PL_RADIANT_PANEL_LAVA =
'radiant_panel.lava'
PL_TOWEL_WARMER =
'towel_warmer'
PL_TOWEL_WARMER_CLASSIC =
'towel_warmer.classic'
PL_TOWEL_WARMER_CLASSIC_TAHOE =
'towel_warmer.classic.tahoe'
PL_TOWEL_WARMER_COSMOPOLITAN =
'towel_warmer.cosmopolitan'
PL_TOWEL_WARMER_CRYSTAL_ACCESSORIES =
'towel_warmer.crystal_accessories'
PL_LED_MIRROR =
'led_mirror'
PL_SERVICES =
'services'
PL_SERVICES_SMARTFIT =
'services.smartfit'
PL_SERVICES_SMARTINSTALL =
'services.smartinstall'
PL_SERVICES_SMARTFIX =
'services.smartfix'
PL_SERVICES_SMARTGUIDE =
'services.smartguide'
PC_URL_TO_PATH =

===========================================================================
URL to Slug Path mappings (for dynamic lookups)

{
  'goods' => PC_GOODS,
  'services' => PC_SERVICES,
  'goods-heating-elements' => PC_HEATING_ELEMENTS,
  'goods-heating-elements-heating-cables' => 'goods.heating_elements.heating_cables',
  'goods-heating-elements-heating-mats' => 'goods.heating_elements.heating_mats',
  'goods-heating-elements-heating-rolls' => 'goods.heating_elements.heating_rolls',
  'goods-heating-elements-countertop-heater' => 'goods.heating_elements.countertop_heaters',
  'goods-controls' => PC_CONTROLS,
  'goods-controls-thermostats' => PC_CONTROLS_THERMOSTATS,
  'goods-accessories' => PC_ACCESSORIES,
  'goods-accessories-insulations' => PC_ACCESSORIES_INSULATIONS,
  'goods-accessories-membranes' => PC_ACCESSORIES_MEMBRANES,
  'goods-accessories-installation-kits' => 'goods.accessories.installation_kits',
  'goods-spare-parts' => PC_SPARE_PARTS,
  'goods-spare-parts-cold-leads' => PC_SPARE_PARTS_COLD_LEADS,
  'goods-tools' => PC_TOOLS,
  'goods-power' => PC_POWER,
  'goods-power-relay-panels' => PC_POWER_RELAY_PANELS,
  'goods-power-modules' => PC_POWER_MODULES,
  'goods-sensors' => PC_SENSORS,
  'goods-towel-warmers' => PC_TOWEL_WARMERS,
  'goods-towel-warmers-plug-in' => PC_TOWEL_WARMERS_PLUG_IN,
  'goods-towel-warmers-hardwired' => PC_TOWEL_WARMERS_HARDWIRED,
  'goods-towel-warmers-dual-connection' => PC_TOWEL_WARMERS_DUAL_CONNECTION,
  'goods-mirror-defoggers' => PC_MIRROR_DEFOGGERS,
  'goods-mirrors' => PC_MIRRORS,
  'goods-radiant-panels' => PC_RADIANT_PANELS,
  'goods-radiant-panels-plug-in' => PC_RADIANT_PANELS_PLUG_IN,
  'goods-radiant-panels-hardwired' => PC_RADIANT_PANELS_HARDWIRED,
  'goods-upgrades' => PC_UPGRADES,
  'goods-publications' => PC_PUBLICATIONS,
  'goods-publications-installation' => 'goods.publications.installation',
  'goods-publications-brochures' => 'goods.publications.brochures',
  'goods-publications-catalogs' => 'goods.publications.catalogs',
  'goods-publications-sell-sheets' => 'goods.publications.sell_sheets',
  'goods-publications-technical-specifications' => 'goods.publications.technical_specifications',
  'goods-publications-technical-information' => 'goods.publications.technical_information',
  'goods-publications-warranties' => 'goods.publications.warranties',
  'goods-publications-wiring-diagrams' => 'goods.publications.wiring_diagrams',
  'goods-publications-operation-manuals' => 'goods.publications.operation_manuals',
  'goods-publications-project-planners' => 'goods.publications.project_planners',
  'goods-kits' => 'goods.kits',
  'goods-shower-pan-kits' => 'goods.shower_pan_kits',
  'goods-shower-floor-heating-kits' => 'goods.shower_floor_heating_kits',
  'goods-shower-waterproofing-accessories' => 'goods.shower_waterproofing_accessories',
  'goods-shower-waterproofing-accessories-waterproofing-membranes' => 'goods.shower_waterproofing_accessories.waterproofing_membranes',
  'goods-drain-assemblies' => 'goods.drain.assemblies',
  'goods-drain-kits' => 'goods.drain.kits',
  'goods-drain-grate-covers' => 'goods.drain.grate_covers'
}.freeze
PL_URL_TO_PATH =
{
  # Floor Heating
  'floor-heating' => PL_FLOOR_HEATING,
  'floor-heating-tempzone' => PL_FLOOR_HEATING_TEMPZONE,
  'floor-heating-tempzone-flex-roll' => PL_FLOOR_HEATING_TEMPZONE_FLEX_ROLL,
  'floor-heating-tempzone-easy-mat' => PL_FLOOR_HEATING_TEMPZONE_EASY_MAT,
  'floor-heating-tempzone-cable' => PL_FLOOR_HEATING_TEMPZONE_CABLE,
  'floor-heating-tempzone-cable-120-v' => 'floor_heating.tempzone.cable.120_v',
  'floor-heating-tempzone-cable-240-v' => 'floor_heating.tempzone.cable.240_v',
  'floor-heating-tempzone-installation-kits' => PL_FLOOR_HEATING_TEMPZONE_INSTALLATION_KITS,
  'floor-heating-tempzone-custom-mat' => PL_FLOOR_HEATING_TEMPZONE_CUSTOM_MAT,
  'floor-heating-tempzone-cable-kits-with-uncoupling-membrane-ntrust2' => 'floor_heating.tempzone.cable.kits_with_uncoupling_membrane.ntrust2',
  'floor-heating-tempzone-cable-kits-with-uncoupling-membrane-njoy' => 'floor_heating.tempzone.cable.kits_with_uncoupling_membrane.njoy',
  'floor-heating-tempzone-cable-kits-with-fixing-strips-ntrust2' => 'floor_heating.tempzone.cable.kits_with_fixing_strips.ntrust2',
  'floor-heating-tempzone-cable-kits-with-fixing-strips-njoy' => 'floor_heating.tempzone.cable.kits_with_fixing_strips.njoy',
  'floor-heating-tempzone-flex-roll-twin-conductor-kits-ntrust2' => 'floor_heating.tempzone.flex_roll.twin_conductor.kits.ntrust2',
  'floor-heating-tempzone-flex-roll-twin-conductor-kits-njoy' => 'floor_heating.tempzone.flex_roll.twin_conductor.kits.njoy',
  'floor-heating-tempzone-easy-mat-twin-conductor-kits-ntrust2' => 'floor_heating.tempzone.easy_mat.twin_conductor.kits.ntrust2',
  'floor-heating-tempzone-easy-mat-twin-conductor-kits-njoy' => 'floor_heating.tempzone.easy_mat.twin_conductor.kits.njoy',
  'floor-heating-tempzone-flex-roll-twin-conductor-120-v' => PL_FLOOR_HEATING_TEMPZONE_FLEX_ROLL_TWIN_120V,
  'floor-heating-tempzone-flex-roll-twin-conductor-240-v' => PL_FLOOR_HEATING_TEMPZONE_FLEX_ROLL_TWIN_240V,
  'floor-heating-tempzone-easy-mat-twin-conductor' => PL_FLOOR_HEATING_TEMPZONE_EASY_MAT_TWIN,
  'floor-heating-tempzone-easy-mat-twin-conductor-120-v' => 'floor_heating.tempzone.easy_mat.twin_conductor.120_v',
  'floor-heating-tempzone-ruler-cable' => PL_FLOOR_HEATING_TEMPZONE_RULER_CABLE,
  'floor-heating-tempzone-thin-cable' => PL_FLOOR_HEATING_TEMPZONE_THIN_CABLE,
  'floor-heating-tempzone-ruler-cable-120v' => 'floor_heating.tempzone.ruler_cable.120v',
  'floor-heating-tempzone-ruler-cable-240v' => 'floor_heating.tempzone.ruler_cable.240v',
  'floor-heating-tempzone-shower-mat-bench' => 'floor_heating.tempzone.shower_mat.bench',
  'floor-heating-tempzone-shower-mat-floor' => 'floor_heating.tempzone.shower_mat.floor',
  'floor-heating-environ' => PL_FLOOR_HEATING_ENVIRON,
  'floor-heating-environ-flex-roll' => PL_FLOOR_HEATING_ENVIRON_FLEX_ROLL,
  'floor-heating-environ-easy-mat' => PL_FLOOR_HEATING_ENVIRON_EASY_MAT,
  'floor-heating-environ-flex-roll-120-v' => 'floor_heating.environ.flex_roll.120_v',
  'floor-heating-environ-flex-roll-240-v' => 'floor_heating.environ.flex_roll.240_v',
  'floor-heating-environ-easy-mat-120-v-flat-lead' => 'floor_heating.environ.easy_mat.120_v_flat_lead',
  'floor-heating-environ-easy-mat-240-v-flat-lead' => 'floor_heating.environ.easy_mat.240_v_flat_lead',
  'floor-heating-slab-heat' => PL_FLOOR_HEATING_SLAB_HEAT,
  'floor-heating-slab-heat-mat' => PL_FLOOR_HEATING_SLAB_HEAT_MAT,
  'floor-heating-slab-heat-cable' => PL_FLOOR_HEATING_SLAB_HEAT_CABLE,
  'floor-heating-underlayment' => PL_FLOOR_HEATING_UNDERLAYMENT,
  'floor-heating-underlayment-thermalsheet' => PL_FLOOR_HEATING_UNDERLAYMENT_THERMALSHEET,
  'floor-heating-underlayment-prodeso' => PL_FLOOR_HEATING_UNDERLAYMENT_PRODESO,
  'floor-heating-rough-in-kits-kits' => 'floor_heating.rough_in_kits.kits',
  'floor-heating-control' => PL_FLOOR_HEATING_CONTROL,
  'floor-heating-control-smartstat' => PL_FLOOR_HEATING_CONTROL_SMARTSTAT,
  'floor-heating-control-easystat' => PL_FLOOR_HEATING_CONTROL_EASYSTAT,
  'floor-heating-control-integration' => PL_FLOOR_HEATING_CONTROL_INTEGRATION,
  # Snow Melting
  'snow-melting' => PL_SNOW_MELTING,
  'snow-melting-mat' => PL_SNOW_MELTING_MAT,
  'snow-melting-cable' => PL_SNOW_MELTING_CABLE,
  'snow-melting-control' => PL_SNOW_MELTING_CONTROL,
  'snowmelt-powermat' => 'snow_melting.mat.powermat',
  'snowmelt-omnimat' => 'snow_melting.mat.omnimat',
  'snowmelt-ecomat' => 'snow_melting.mat.ecomat',
  'snow-melting-mat-120-v' => 'snow_melting.mat.120_v',
  'snow-melting-mat-240-v' => 'snow_melting.mat.240_v',
  'snow-melting-cable-120-v' => 'snow_melting.cable.120_v',
  'snow-melting-cable-208-v' => 'snow_melting.cable.208_v',
  'snow-melting-cable-240-v' => 'snow_melting.cable.240_v',
  'snow-melting-cable-277-v' => 'snow_melting.cable.277_v',
  # Pipe Freeze Protection
  'pipe-freeze-protection' => PL_PIPE_FREEZE_PROTECTION,
  'pipe-freeze-protection-self-regulating-cable-120-v' => 'pipe_freeze_protection.self_regulating_cable.120_v',
  'pipe-freeze-protection-self-regulating-cable-240-v' => 'pipe_freeze_protection.self_regulating_cable.240_v',
  'pipe-freeze-protection-constant-wattage-cable' => 'pipe_freeze_protection.constant_wattage_cable',
  # Roof & Gutter Deicing
  'roof-and-gutter-deicing' => 'roof_gutter_deicing',
  'roof-and-gutter-deicing-constant-wattage-pre-assembled-plug-in-kits' => 'roof_gutter_deicing.constant_wattage.pre_assembled_plug_in_kits',
  'roof-and-gutter-deicing-self-regulating-cut-to-length-cable-120-v' => 'roof_gutter_deicing.self_regulating_cut_to_length_cable.120_v',
  'roof-and-gutter-deicing-self-regulating-cut-to-length-cable-240-v' => 'roof_gutter_deicing.self_regulating_cut_to_length_cable.240_v',
  # Radiant Panels
  'radiant-panel' => PL_RADIANT_PANEL,
  'radiant-panel-lava' => PL_RADIANT_PANEL_LAVA,
  'radiant-panel-lava-glass' => 'radiant_panel.lava.glass',
  'radiant-panel-lava-mirror' => 'radiant_panel.lava.mirror',
  'radiant-panel-lava-crystal' => 'radiant_panel.lava.crystal',
  'radiant-panel-lava-light' => 'radiant_panel.lava.light',
  'radiant-panel-ember' => 'radiant_panel.ember',
  'radiant-panel-ember-flex' => 'radiant_panel.ember.flex',
  'radiant-panel-ember-glass' => 'radiant_panel.ember.glass',
  'radiant-panel-ember-mirror' => 'radiant_panel.ember.mirror',
  # Towel Warmers
  'towel-warmer' => PL_TOWEL_WARMER,
  'towel-warmer-barcelona' => 'towel_warmer.barcelona',
  'towel-warmer-classic' => 'towel_warmer.classic',
  'towel-warmer-cosmopolitan' => PL_TOWEL_WARMER_COSMOPOLITAN,
  'towel-warmer-control' => 'towel_warmer.control',
  'towel-warmer-crystal-accessories' => PL_TOWEL_WARMER_CRYSTAL_ACCESSORIES,
  'towel-warmer-crystal-collection' => 'towel_warmer.crystal_collection',
  # Mirrors
  'led-mirror' => PL_LED_MIRROR,
  'mirror-defogger' => 'mirror_defogger',
  # Countertop Heaters
  'countertop-heater' => 'countertop_heater',
  'countertop-heater-standard' => 'countertop_heater.standard',
  # Shower Kits
  'shower-kits' => 'shower_kits',
  # Rental Tools
  'rental-tools' => 'rental_tools',
  # Under Desk Heater (support-only)
  'under-desk-heater' => 'under_desk_heater',
  # Services
  'services' => PL_SERVICES,
  'services-smartfit' => PL_SERVICES_SMARTFIT,
  'services-smartinstall' => PL_SERVICES_SMARTINSTALL,
  'services-smartfix' => PL_SERVICES_SMARTFIX,
  'services-smartguide' => PL_SERVICES_SMARTGUIDE
}.freeze
VALID_LTREE_PATTERN =

Resolve a legacy hyphenated product line segment (e.g. from old routes or +url+ param)
to +slug_ltree+. Uses +PL_URL_TO_PATH+ when present; otherwise treats a single segment
as +tr('-', '_')+ (multi-level hyphen strings must be mapped in +PL_URL_TO_PATH+).

/\A[a-zA-Z0-9_]+(\.[a-zA-Z0-9_]+)*\z/

Class Method Summary collapse

Class Method Details

.product_category_path_for(url) ⇒ Object



328
329
330
# File 'app/constants/ltree_paths.rb', line 328

def self.product_category_path_for(url)
  PC_URL_TO_PATH[url]
end

.product_line_path_for(url) ⇒ Object

Look up ltree path for a product line or product category URL
Returns the slug path if found in mappings, nil otherwise



311
312
313
# File 'app/constants/ltree_paths.rb', line 311

def self.product_line_path_for(url)
  PL_URL_TO_PATH[url]
end

.slug_ltree_from_legacy_hyphen_url(legacy_segment) ⇒ Object



320
321
322
323
324
325
326
# File 'app/constants/ltree_paths.rb', line 320

def self.slug_ltree_from_legacy_hyphen_url(legacy_segment)
  return nil if legacy_segment.blank?

  s = legacy_segment.to_s
  result = product_line_path_for(s) || s.tr('-', '_')
  result.match?(VALID_LTREE_PATTERN) ? result : nil
end

.verify_allObject

Verify all hardcoded paths match current database values



333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'app/constants/ltree_paths.rb', line 333

def self.verify_all
  errors = []

  PC_URL_TO_PATH.each do |url, expected_path|
    pc = ProductCategory.find_by(url: url)
    if pc.nil?
      errors << "ProductCategory '#{url}' not found"
    elsif pc.ltree_path_slugs != expected_path
      errors << "ProductCategory '#{url}': expected '#{expected_path}', got '#{pc.ltree_path_slugs}'"
    end
  end

  PL_URL_TO_PATH.each do |url, expected_path|
    pl = ProductLine.find_by(slug_ltree: expected_path)
    if pl.nil?
      errors << "ProductLine slug_ltree='#{expected_path}' (from URL key '#{url}') not found"
    elsif pl.ltree_path_slugs != expected_path
      errors << "ProductLine '#{url}': expected '#{expected_path}', got '#{pl.ltree_path_slugs}'"
    end
  end

  if errors.empty?
    puts "✅ All #{PC_URL_TO_PATH.size + PL_URL_TO_PATH.size} ltree slug paths verified!"
    true
  else
    puts "#{errors.size} errors found:"
    errors.each { |e| puts "  - #{e}" }
    false
  end
end