Module: UrlsHelper

Included in:
ApplicationHelper, PagesHelper, RmasHelper
Defined in:
app/helpers/urls_helper.rb

Defined Under Namespace

Classes: SalesProductResult

Instance Method Summary collapse

Instance Method Details

Returns array of { name:, url: } hashes from root to self.

Parameters:

  • product_line (ProductLine)

    the product line for breadcrumbs

  • section (Symbol, nil) (defaults to: nil)

    optional sub-section

  • full_url (:auto, true, false) (defaults to: :auto)

    forwarded to catalog_link

Returns:

  • (Array<Hash>)

    array of { name:, url: } hashes from root to self



191
192
193
194
195
196
197
198
# File 'app/helpers/urls_helper.rb', line 191

def catalog_breadcrumb_links(product_line, section: nil, full_url: :auto)
  portal_scope = section == :support ? :for_support_portal : :for_sales_portal
  product_line.self_and_ancestors.public_send(portal_scope).reverse.filter_map do |pl|
    url = catalog_link(pl, section: section, full_url: full_url)
    next unless url
    { name: pl.display_name, url: url }
  end
end

Returns locale-prefixed canonical path (or full URL), or nil.

Parameters:

  • resource (ProductLine, Item, ViewProductCatalog)

    catalog entity

  • section (Symbol, nil) (defaults to: nil)

    optional sub-section (e.g. :support, :reviews)

  • full_url (:auto, true, false) (defaults to: :auto)

    :auto detects CRM vs WWW context;
    true always returns a fully-qualified URL; false always returns a relative path

Returns:

  • (String, nil)

    locale-prefixed canonical path (or full URL), or nil



150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'app/helpers/urls_helper.rb', line 150

def catalog_link(resource, section: nil, full_url: :auto)
  record = resource.is_a?(ViewProductCatalog) ? resource.item : resource
  base = record&.canonical_path.presence
  return nil unless base

  root = base.split('/').first
  return nil unless CatalogPathResolver::PRODUCT_LINE_ROOT_SLUGS.include?(root)

  path = section ? "#{base}/#{section}" : base
  relative = cms_link("/#{path}")

  qualify = full_url == true || (full_url == :auto && crm_context?)
  qualify ? "#{WEB_URL}#{relative}" : relative
end

Returns locale-prefixed canonical path, or nil if not found.

Parameters:

  • product_line_url (String)

    URL slug of the product line

  • section (Symbol, nil) (defaults to: nil)

    optional sub-section

  • full_url (:auto, true, false) (defaults to: :auto)

    forwarded to catalog_link

Returns:

  • (String, nil)

    locale-prefixed canonical path, or nil if not found



179
180
181
182
183
184
185
# File 'app/helpers/urls_helper.rb', line 179

def catalog_link_for_product_line(product_line_url, section: nil, full_url: :auto)
  pl = ProductLine.find_by(slug_ltree: LtreePaths.slug_ltree_from_legacy_hyphen_url(product_line_url)) ||
       ProductLine.find_by(slug_ltree: product_line_url)
  return nil unless pl

  catalog_link(pl, section: section, full_url: full_url)
end

Returns locale-prefixed canonical path.

Parameters:

  • sku (String)

    item SKU

  • section (Symbol, nil) (defaults to: nil)

    optional sub-section

  • full_url (:auto, true, false) (defaults to: :auto)

    forwarded to catalog_link

Returns:

  • (String)

    locale-prefixed canonical path

Raises:

  • (ActiveRecord::RecordNotFound)

    if SKU doesn't exist



170
171
172
173
# File 'app/helpers/urls_helper.rb', line 170

def catalog_link_for_sku(sku, section: nil, full_url: :auto)
  item = Item.find_by!(sku: sku)
  catalog_link(item, section: section, full_url: full_url)
end

Foundation: locale-prefixed path builder

cms_link(path) is the single entry point for turning a raw path into a
locale-prefixed URL. All other helpers in this module build on top of it.
Delegates to Web::UrlBuilder.



30
31
32
# File 'app/helpers/urls_helper.rb', line 30

def cms_link(...)
  Web::UrlBuilder.new.process(...)
end

#delocalized_path(request_path = nil) ⇒ String

Returns path without locale prefix.

Parameters:

  • request_path (String, nil) (defaults to: nil)

    path to strip locale from (defaults to current request path)

Returns:

  • (String)

    path without locale prefix



40
41
42
# File 'app/helpers/urls_helper.rb', line 40

def delocalized_path(request_path = nil)
  cms_link(request_path, :delocalized)
end

#path_to_sales_product_sku(sku, _options = {}) ⇒ SalesProductResult?

Parameters:

  • sku (String)

    item SKU

Returns:



69
70
71
72
73
# File 'app/helpers/urls_helper.rb', line 69

def path_to_sales_product_sku(sku, _options = {})
  sku = CatalogPathResolver::SKU_ALIASES.fetch(sku, sku)
  vpc = ViewProductCatalog.where(catalog_id: Catalog.locale_to_catalog_id).find_by(item_sku: sku)
  resolve_vpc_to_sales_result(vpc)
end

#path_to_sales_product_sku_for_product_line(product_line, options = {}) ⇒ SalesProductResult?

Parameters:

  • product_line (ProductLine)

    the product line to resolve

  • options (Hash) (defaults to: {})

    :locale to override I18n.locale

Returns:



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'app/helpers/urls_helper.rb', line 78

def path_to_sales_product_sku_for_product_line(product_line, options = {})
  # Honor an explicit `:locale` override unconditionally - the docstring
  # promises it overrides I18n.locale. The previous implementation only
  # respected it when the ambient locale was bare `:en`, which silently
  # ignored the override under :'en-US' / :'en-CA' requests.
  locale_for_block = options[:locale] || (I18n.locale == :en ? :'en-US' : I18n.locale)

  CurrentScope.with_locale(locale_for_block) do
    target = if product_line.show_in_sales_portal? && product_line.available_to_public
               product_line
             else
               product_line.get_first_show_in_sales_portal_ancestor || product_line.root
             end

    next nil unless target.canonical_path

    main_product = Www::ProductLinePresenter.new(target).main_product
    url = if main_product
            item = main_product.respond_to?(:item) ? main_product.item : Item.find_by(sku: main_product.item_sku)
            cms_link("/#{item&.canonical_path || target.canonical_path}")
          else
            cms_link("/#{target.canonical_path}")
          end

    SalesProductResult.new(url: url, name: target.public_name)
  end
end

#path_to_sales_product_sku_for_product_line_slug(product_line_slug, options = {}) ⇒ SalesProductResult?

Parameters:

  • product_line_slug (String)

    URL slug of the product line

  • options (Hash) (defaults to: {})

    :locale, :product_line (preloaded)

Returns:



109
110
111
112
113
114
115
116
# File 'app/helpers/urls_helper.rb', line 109

def path_to_sales_product_sku_for_product_line_slug(product_line_slug, options = {})
  product_line = options[:product_line] ||
                 ProductLine.find_by(slug_ltree: LtreePaths.slug_ltree_from_legacy_hyphen_url(product_line_slug)) ||
                 ProductLine.find_by(slug_ltree: product_line_slug)
  return nil unless product_line

  path_to_sales_product_sku_for_product_line(product_line, options)
end

Resolve a locale-prefixed or absolute catalog URL to the deepest matching ProductLine.
Used when only a full cms_link path is available (e.g. product grids), not a single path segment.

Parameters:

  • link (String)

    full URL or path such as +/en-US/towel-warmer/classic/infinity+

Returns:



123
124
125
126
127
128
129
130
131
132
133
# File 'app/helpers/urls_helper.rb', line 123

def product_line_from_catalog_link(link)
  raw = link.to_s.split('?').first.to_s
  path = raw.sub(%r{\Ahttps?://[^/]+}i, '')
  path = path.sub(%r{\A/([a-z]{2}(?:-[A-Z]{2})?)/}i, '/')
  path = path.sub(%r{\A/+}, '')
  segments = path.split('/').map(&:presence).compact
  return nil if segments.empty?
  return nil unless CatalogPathResolver::PRODUCT_LINE_ROOT_SLUGS.include?(segments.first)

  CatalogPathResolver.new.resolve(root_slug: segments.first, path_segments: segments.drop(1)).product_line
end

#protocol_neutral_url(url) ⇒ String

Returns scheme-less URL (e.g. "//example.com/image.jpg").

Parameters:

  • url (String)

    URL to strip scheme from

Returns:

  • (String)

    scheme-less URL (e.g. "//example.com/image.jpg")



51
52
53
54
# File 'app/helpers/urls_helper.rb', line 51

def protocol_neutral_url(url)
  url = url.to_s.gsub('http:', '')
  url.to_s.gsub('https:', '')
end

#sanitize_external_url(url) ⇒ Object

Returns the trimmed string when +valid_external_url?+ passes; +nil+ otherwise (use for safe +link_to+ / +image_tag+ hrefs).



15
16
17
18
19
20
# File 'app/helpers/urls_helper.rb', line 15

def sanitize_external_url(url)
  url = url.to_s.strip
  return nil unless valid_external_url?(url)

  url
end

#valid_external_url?(url) ⇒ Boolean

True when +url+ parses as +http+ or +https+ with a non-empty host (rejects +javascript:+, +data:+, relatives, etc.).

Returns:

  • (Boolean)


5
6
7
8
9
10
11
12
# File 'app/helpers/urls_helper.rb', line 5

def valid_external_url?(url)
  return false if url.blank?

  uri = URI.parse(url.to_s.strip)
  %w[http https].include?(uri.scheme) && uri.host.present?
rescue URI::InvalidURIError
  false
end