Module: Models::ItemScopable

Extended by:
ActiveSupport::Concern
Included in:
DigitalAsset, Item, ViewItem
Defined in:
app/concerns/models/item_scopable.rb

Overview

Provides ltree-based scopes for models with product category and product line paths.
Included by: Item, DigitalAsset, ViewItem

Preferred scopes (no DB lookup - use LtreePaths constants):
Item.by_product_category_path(LtreePaths::PC_CONTROLS)
Item.by_product_line_path(LtreePaths::PL_FLOOR_HEATING)

Uses Arel predicates from config/initializers/arel_ltree_predicates.rb

Class Method Summary collapse

Class Method Details

.by_product_category_idActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product category id. Active Record Scope

Returns:

See Also:



49
50
51
52
53
54
55
# File 'app/concerns/models/item_scopable.rb', line 49

scope :by_product_category_id, ->(*pc_ids) {
  ids = [pc_ids].flatten.compact.map(&:to_i)
  return none if ids.empty?

  paths = ProductCategory.where(id: ids).pluck(:ltree_path_ids).compact
  paths.empty? ? none : where(arel_table[:pc_path_ids].ltree_descendant(paths))
}

.by_product_category_id_directActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product category id direct. Active Record Scope

Returns:

See Also:



68
69
70
# File 'app/concerns/models/item_scopable.rb', line 68

scope :by_product_category_id_direct, ->(*pc_ids) {
  where(product_category_id: [pc_ids].flatten.compact)
}

.by_product_category_pathActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product category path. Active Record Scope

Returns:

See Also:



21
22
23
# File 'app/concerns/models/item_scopable.rb', line 21

scope :by_product_category_path, ->(slug_path) {
  slug_path.blank? ? none : where(arel_table[:pc_path_slugs].ltree_descendant(slug_path))
}

.by_product_category_path_exactActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product category path exact. Active Record Scope

Returns:

See Also:



27
28
29
# File 'app/concerns/models/item_scopable.rb', line 27

scope :by_product_category_path_exact, ->(slug_path) {
  slug_path.blank? ? none : where(pc_path_slugs: slug_path)
}

.by_product_category_urlActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product category url. Active Record Scope

Returns:

See Also:



32
33
34
35
36
37
38
# File 'app/concerns/models/item_scopable.rb', line 32

scope :by_product_category_url, ->(*pc_urls) {
  urls = [pc_urls].flatten.uniq.compact
  return none if urls.empty?

  paths = ProductCategory.where(url: urls).pluck(:ltree_path_ids).compact
  paths.empty? ? none : where(arel_table[:pc_path_ids].ltree_descendant(paths))
}

.by_product_category_url_exactActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product category url exact. Active Record Scope

Returns:

See Also:



41
42
43
44
45
46
# File 'app/concerns/models/item_scopable.rb', line 41

scope :by_product_category_url_exact, ->(*pc_urls) {
  urls = [pc_urls].flatten.uniq.compact
  return none if urls.empty?

  joins(:product_category).where(product_categories: { url: urls })
}

.by_product_line_idActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product line id. Active Record Scope

Returns:

See Also:



86
87
88
89
90
91
# File 'app/concerns/models/item_scopable.rb', line 86

scope :by_product_line_id, ->(*pl_ids) {
  ids = [pl_ids].flatten.compact.map(&:to_i)
  return none if ids.empty?

  where.ltree_contains(:all_pl_paths_ids, ids)
}

.by_product_line_pathActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product line path. Active Record Scope

Returns:

See Also:



77
78
79
# File 'app/concerns/models/item_scopable.rb', line 77

scope :by_product_line_path, ->(slug_path) {
  slug_path.blank? ? none : where(arel_table[:primary_pl_path_slugs].ltree_descendant(slug_path))
}

.by_product_line_path_fullActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product line path full. Active Record Scope

Returns:

See Also:



143
144
145
146
147
148
149
150
151
152
153
154
# File 'app/concerns/models/item_scopable.rb', line 143

scope :by_product_line_path_full, ->(*pl_paths) {
  paths = [pl_paths].flatten.uniq.compact.map(&:to_s)
  return none if paths.empty?

  where(
    "#{table_name}.primary_pl_path_slugs <@ ANY(ARRAY[?]::ltree[]) OR " \
    "#{table_name}.primary_pl_path_slugs @> ANY(ARRAY[?]::ltree[]) OR " \
    "EXISTS (SELECT 1 FROM unnest(#{table_name}.all_pl_paths_slugs) AS p " \
    'WHERE p @> ANY(ARRAY[?]::ltree[]) OR p <@ ANY(ARRAY[?]::ltree[]))',
    paths, paths, paths, paths
  )
}

.by_product_line_urlActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product line url. Active Record Scope

Returns:

See Also:



109
110
111
112
113
114
115
116
117
118
# File 'app/concerns/models/item_scopable.rb', line 109

scope :by_product_line_url, ->(*slug_ltrees) {
  paths = [slug_ltrees].flatten.uniq.compact
  return none if paths.empty?

  where(
    "EXISTS (SELECT 1 FROM unnest(#{table_name}.all_pl_paths_ids) AS p, product_lines pl " \
    'WHERE pl.slug_ltree IN (?) AND p <@ pl.ltree_path_ids)',
    paths
  )
}

.by_product_line_url_fullActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are by product line url full. Active Record Scope

Returns:

See Also:



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'app/concerns/models/item_scopable.rb', line 122

scope :by_product_line_url_full, ->(*slug_ltrees) {
  paths = [slug_ltrees].flatten.uniq.compact
  return none if paths.empty?

  where(
    'EXISTS (SELECT 1 FROM product_lines pl WHERE pl.slug_ltree IN (?) AND (' \
    "#{table_name}.primary_pl_path_ids <@ pl.ltree_path_ids OR " \
    "#{table_name}.primary_pl_path_ids @> pl.ltree_path_ids OR " \
    "EXISTS (SELECT 1 FROM unnest(#{table_name}.all_pl_paths_ids) AS p " \
    'WHERE p @> pl.ltree_path_ids OR p <@ pl.ltree_path_ids)))',
    paths
  )
}

.not_by_product_category_idActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are not by product category id. Active Record Scope

Returns:

See Also:



59
60
61
62
63
64
65
# File 'app/concerns/models/item_scopable.rb', line 59

scope :not_by_product_category_id, ->(*pc_ids) {
  ids = [pc_ids].flatten.compact.map(&:to_i)
  return all if ids.empty?

  paths = ProductCategory.where(id: ids).pluck(:ltree_path_ids).compact
  paths.empty? ? all : where.not(arel_table[:pc_path_ids].ltree_descendant(paths))
}

.not_by_product_line_idActiveRecord::Relation<Models::ItemScopable>

A relation of Models::ItemScopables that are not by product line id. Active Record Scope

Returns:

See Also:



96
97
98
99
100
101
102
103
104
105
# File 'app/concerns/models/item_scopable.rb', line 96

scope :not_by_product_line_id, ->(*pl_ids) {
  ids = [pl_ids].flatten.compact.map(&:to_i)
  return all if ids.empty?

  # Use NOT EXISTS to negate the ltree_contains logic
  where(
    "NOT EXISTS (SELECT 1 FROM unnest(#{table_name}.all_pl_paths_ids) AS p, unnest(ARRAY[?]::ltree[]) AS id WHERE index(p, id) >= 0)",
    ids.map(&:to_s)
  )
}