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 =

Pc services.

'services'
PC_SHIPPING =

Pc shipping.

'shipping'
PC_SHIPPING_AND_HANDLING =

Pc shipping and handling.

'shipping_and_handling'
PC_HEATING_ELEMENTS =

Pc heating elements.

'goods.heating_elements'
PC_HEATING_ELEMENTS_HEATING_CABLES =

Pc heating elements heating cables.

'goods.heating_elements.heating_cables'
PC_HEATING_ELEMENTS_CUSTOM_MATS =

Pc heating elements custom mats.

'goods.heating_elements.heating_custom_mats'
PC_HEATING_ELEMENTS_COUNTERTOP =

Pc heating elements countertop.

'goods.heating_elements.countertop_heaters'
PC_CONTROLS =

Pc controls.

'goods.controls'
PC_CONTROLS_THERMOSTATS =

Pc controls thermostats.

'goods.controls.thermostats'
PC_ACCESSORIES =

Pc accessories.

'goods.accessories'
PC_ACCESSORIES_INSULATIONS =

Pc accessories insulations.

'goods.accessories.insulations'
PC_ACCESSORIES_MEMBRANES =

Pc accessories membranes.

'goods.accessories.membranes'
PC_SPARE_PARTS =

Pc spare parts.

'goods.spare_parts'
PC_SPARE_PARTS_COLD_LEADS =

Pc spare parts cold leads.

'goods.spare_parts.cold_leads'
PC_TOOLS =

Pc tools.

'goods.tools'
PC_POWER =

Pc power.

'goods.power'
PC_POWER_RELAY_PANELS =

Pc power relay panels.

'goods.power.relay_panels'
PC_POWER_MODULES =

Pc power modules.

'goods.power.modules'
PC_SENSORS =

Pc sensors.

'goods.sensors'
PC_TOWEL_WARMERS =

Pc towel warmers.

'goods.towel_warmers'
PC_TOWEL_WARMERS_PLUG_IN =

Pc towel warmers plug in.

'goods.towel_warmers.plug_in'
PC_TOWEL_WARMERS_HARDWIRED =

Pc towel warmers hardwired.

'goods.towel_warmers.hardwired'
PC_TOWEL_WARMERS_DUAL_CONNECTION =

Pc towel warmers dual connection.

'goods.towel_warmers.dual_connection'
PC_MIRROR_DEFOGGERS =

Pc mirror defoggers.

'goods.mirror_defoggers'
PC_MIRRORS =

Pc mirrors.

'goods.mirrors'
PC_INFRARED_HEATING_PANELS =

Pc infrared heating panels.

'goods.infrared_heating_panels'
PC_INFRARED_HEATING_PANELS_PLUG_IN =

Pc infrared heating panels plug in.

'goods.infrared_heating_panels.plug_in'
PC_INFRARED_HEATING_PANELS_HARDWIRED =

Pc infrared heating panels hardwired.

'goods.infrared_heating_panels.hardwired'
PC_UPGRADES =

Pc upgrades.

'goods.upgrades'
PC_PUBLICATIONS =

Pc publications.

'goods.publications'
PC_PUBLICATIONS_INSTALLATION =

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 =

Pl floor heating tempzone.

'floor_heating.tempzone'
PL_FLOOR_HEATING_TEMPZONE_FLEX_ROLL =

Pl floor heating tempzone flex roll.

'floor_heating.tempzone.flex_roll'
PL_FLOOR_HEATING_TEMPZONE_EASY_MAT =

Pl floor heating tempzone easy mat.

'floor_heating.tempzone.easy_mat'
PL_FLOOR_HEATING_TEMPZONE_CABLE =

Pl floor heating tempzone cable.

'floor_heating.tempzone.cable'
PL_FLOOR_HEATING_TEMPZONE_THIN_CABLE =

Pl floor heating tempzone thin cable.

'floor_heating.tempzone.thin_cable'
PL_FLOOR_HEATING_TEMPZONE_RULER_CABLE =

Pl floor heating tempzone ruler cable.

'floor_heating.tempzone.ruler_cable'
PL_FLOOR_HEATING_TEMPZONE_SHOWER_MAT =

Pl floor heating tempzone shower mat.

'floor_heating.tempzone.shower_mat'
PL_FLOOR_HEATING_TEMPZONE_INSTALLATION_KITS =

Pl floor heating tempzone installation kits.

'floor_heating.tempzone.installation_kits'
PL_FLOOR_HEATING_TEMPZONE_CUSTOM_MAT =

Pl floor heating tempzone custom mat.

'floor_heating.tempzone.custom_mat'
PL_FLOOR_HEATING_TEMPZONE_EASY_MAT_TWIN =

Pl floor heating tempzone easy mat twin.

'floor_heating.tempzone.easy_mat.twin_conductor'
PL_FLOOR_HEATING_TEMPZONE_FLEX_ROLL_TWIN_120V =

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 =

Pl floor heating tempzone flex roll twin 240v.

'floor_heating.tempzone.flex_roll.twin_conductor.240_v'
PL_FLOOR_HEATING_ROUGH_IN_KITS =

Pl floor heating rough in kits.

'floor_heating.rough_in_kits'
PL_FLOOR_HEATING_ENVIRON =

Pl floor heating environ.

'floor_heating.environ'
PL_FLOOR_HEATING_ENVIRON_FLEX_ROLL =

Pl floor heating environ flex roll.

'floor_heating.environ.flex_roll'
PL_FLOOR_HEATING_ENVIRON_EASY_MAT =

Pl floor heating environ easy mat.

'floor_heating.environ.easy_mat'
PL_FLOOR_HEATING_SLAB_HEAT =

Pl floor heating slab heat.

'floor_heating.slab_heat'
PL_FLOOR_HEATING_SLAB_HEAT_MAT =

Pl floor heating slab heat mat.

'floor_heating.slab_heat.mat'
PL_FLOOR_HEATING_SLAB_HEAT_CABLE =

Pl floor heating slab heat cable.

'floor_heating.slab_heat.cable'
PL_FLOOR_HEATING_UNDERLAYMENT =

Pl floor heating underlayment.

'floor_heating.underlayment'
PL_FLOOR_HEATING_UNDERLAYMENT_CORK =

Pl floor heating underlayment cork.

'floor_heating.underlayment.cork'
PL_FLOOR_HEATING_UNDERLAYMENT_CERAZORB =

Pl floor heating underlayment cerazorb.

'floor_heating.underlayment.cerazorb'
PL_FLOOR_HEATING_UNDERLAYMENT_THERMALSHEET =

Pl floor heating underlayment thermalsheet.

'floor_heating.underlayment.thermalsheet'
PL_FLOOR_HEATING_UNDERLAYMENT_PRODESO =

Pl floor heating underlayment prodeso.

'floor_heating.underlayment.prodeso'
PL_LED_MIRROR_MADE_TO_ORDER =

Pl led mirror made to order.

'led_mirror.made_to_order'
PL_FLOOR_HEATING_CONTROL =

Pl floor heating control.

'floor_heating.control'
PL_FLOOR_HEATING_CONTROL_SMARTSTAT =

Pl floor heating control smartstat.

'floor_heating.control.smartstat'
PL_FLOOR_HEATING_CONTROL_EASYSTAT =

Pl floor heating control easystat.

'floor_heating.control.easystat'
PL_FLOOR_HEATING_CONTROL_INTEGRATION =

Pl floor heating control integration.

'floor_heating.control.integration'
PL_FLOOR_HEATING_CONTROL_NSPIRE_TOUCH =

Pl floor heating control nspire touch.

'floor_heating.control.nspire_touch'
PL_FLOOR_HEATING_CONTROL_NSPIRE_TOUCH_WIFI =

Pl floor heating control nspire touch wifi.

'floor_heating.control.nspire_touch_wifi'
PL_FLOOR_HEATING_CONTROL_NJOY_WIFI =

Pl floor heating control njoy wifi.

'floor_heating.control.njoy_wifi'
PL_FLOOR_HEATING_CONTROL_NHANCE =

Pl floor heating control nhance.

'floor_heating.control.nhance'
PL_FLOOR_HEATING_CONTROL_NTRUST =

Pl floor heating control ntrust.

'floor_heating.control.ntrust'
PL_FLOOR_HEATING_CONTROL_NTRUST2 =

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 =

Pl snow melting.

'snow_melting'
PL_SNOW_MELTING_MAT =

Pl snow melting mat.

'snow_melting.mat'
PL_SNOW_MELTING_CABLE =

Pl snow melting cable.

'snow_melting.cable'
PL_SNOW_MELTING_CONTROL =

Pl snow melting control.

'snow_melting.control'
PL_ROOF_GUTTER_DEICING =

Pl roof gutter deicing. NOTE: this matches the ltree_path_slugs /
primary_pl_path_slugs columns, not slug_ltree — for the roof PL
those two columns diverge (slug_ltree is roof_and_gutter_deicing,
with and). Use ProductLineUrls::ROOF_GUTTER_DEICING when you need
the slug_ltree value.

'roof_gutter_deicing'
PL_ROOF_GUTTER_DEICING_CONTROL =

Pl roof gutter deicing control.

'roof_gutter_deicing.self_regulating_cut_to_length_cable.control'
PL_PIPE_FREEZE_PROTECTION =

Pl pipe freeze protection.

'pipe_freeze_protection'
PL_PIPE_FREEZE_PROTECTION_SELF_REG =

Pl pipe freeze protection self reg.

'pipe_freeze_protection.self_regulating_cable'
PL_PIPE_FREEZE_PROTECTION_CONTROL =

Pl pipe freeze protection control.

'pipe_freeze_protection.self_regulating_cable.pipe_freeze_control'
PL_ROOF_GUTTER_DEICING_SELF_REG =

Pl roof gutter deicing self reg.

'roof_gutter_deicing.self_regulating_cut_to_length_cable'
PL_INFRARED_HEATING_PANELS =

Pl infrared heating panel.

'infrared_heating_panels'
PL_INFRARED_HEATING_PANELS_CONTROL =

Pl infrared heating panel control.

'infrared_heating_panels.control'
PL_TOWEL_WARMER_CONTROL =

Pl towel warmer control.

'towel_warmer.control'
PL_COUNTERTOP_HEATER_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_INFRARED_HEATING_PANELS_CONTROL,
  PL_TOWEL_WARMER_CONTROL,
  PL_COUNTERTOP_HEATER_CONTROL
].freeze
PL_INFRARED_HEATING_PANELS_LAVA =

Pl infrared heating panel lava.

'infrared_heating_panels.lava'
PL_TOWEL_WARMER =

Pl towel warmer.

'towel_warmer'
PL_TOWEL_WARMER_CLASSIC =

Pl towel warmer classic.

'towel_warmer.classic'
PL_TOWEL_WARMER_CLASSIC_TAHOE =

Pl towel warmer classic tahoe.

'towel_warmer.classic.tahoe'
PL_TOWEL_WARMER_COSMOPOLITAN =

Pl towel warmer cosmopolitan.

'towel_warmer.cosmopolitan'
PL_TOWEL_WARMER_CRYSTAL_ACCESSORIES =

Pl towel warmer crystal accessories.

'towel_warmer.crystal_accessories'
PL_LED_MIRROR =

Pl led mirror.

'led_mirror'
PL_SERVICES =

Pl services.

'services'
PL_SERVICES_SMARTFIT =

Pl services smartfit.

'services.smartfit'
PL_SERVICES_SMARTINSTALL =

Pl services smartinstall.

'services.smartinstall'
PL_SERVICES_SMARTFIX =

Pl services smartfix.

'services.smartfix'
PL_SERVICES_SMARTGUIDE =

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_INFRARED_HEATING_PANELS,
  'goods-radiant-panels-plug-in' => PC_INFRARED_HEATING_PANELS_PLUG_IN,
  'goods-radiant-panels-hardwired' => PC_INFRARED_HEATING_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 =

Filesystem/URL path for pl url to.

{
  # 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' => PL_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',
  # Infrared Heating Panels (legacy radiant-panel* keys kept for /products/line redirects)
  'infrared-heating-panels' => PL_INFRARED_HEATING_PANELS,
  'radiant-panel' => PL_INFRARED_HEATING_PANELS,
  'radiant-panel-lava' => PL_INFRARED_HEATING_PANELS_LAVA,
  'radiant-panel-lava-glass' => 'infrared_heating_panels.lava.glass',
  'radiant-panel-lava-mirror' => 'infrared_heating_panels.lava.mirror',
  'radiant-panel-lava-crystal' => 'infrared_heating_panels.lava.crystal',
  'radiant-panel-lava-light' => 'infrared_heating_panels.lava.light',
  'radiant-panel-ember' => 'infrared_heating_panels.ember',
  'radiant-panel-ember-flex' => 'infrared_heating_panels.ember.flex',
  'radiant-panel-ember-glass' => 'infrared_heating_panels.ember.glass',
  'radiant-panel-ember-mirror' => 'infrared_heating_panels.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



426
427
428
# File 'app/constants/ltree_paths.rb', line 426

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



409
410
411
# File 'app/constants/ltree_paths.rb', line 409

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

.slug_ltree_from_legacy_hyphen_url(legacy_segment) ⇒ Object



418
419
420
421
422
423
424
# File 'app/constants/ltree_paths.rb', line 418

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



431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
# File 'app/constants/ltree_paths.rb', line 431

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