Class: Item::ArticleRetriever
- Inherits:
-
BaseService
- Object
- BaseService
- Item::ArticleRetriever
- Defined in:
- app/services/item/article_retriever.rb
Overview
Retrieves all the articles associated with a particular item.
Defined Under Namespace
Classes: Result
Constant Summary collapse
- ARTICLE_TYPE_TO_STI =
Article type to sti.
{ 'faq' => 'ArticleFaq', 'technical' => 'ArticleTechnical', 'training' => 'ArticleTraining', 'procedure' => 'ArticleProcedure', 'blog_post' => 'Post' }.freeze
Instance Attribute Summary collapse
-
#add_vote_data ⇒ Object
readonly
Returns the value of attribute add_vote_data.
-
#sales ⇒ Object
readonly
Returns the value of attribute sales.
-
#sti_types ⇒ Object
readonly
Returns the value of attribute sti_types.
-
#support ⇒ Object
readonly
Returns the value of attribute support.
Attributes inherited from BaseService
Instance Method Summary collapse
-
#initialize(article_types:, sales: nil, support: nil, add_vote_data: false) ⇒ ArticleRetriever
constructor
==== Initialization options.
-
#process(item: nil, product_line: nil, product_category: nil, tags: nil) ⇒ Result
Retrieves all product specifications available to a given item.
Methods inherited from BaseService
#log_debug, #log_error, #log_info, #log_warning, #logger, #tagged_logger
Constructor Details
#initialize(article_types:, sales: nil, support: nil, add_vote_data: false) ⇒ ArticleRetriever
==== Initialization options
- +:article_types+ - required, filter by STI type. Accepts old enum names (:faq, :technical, etc.)
- +:sales+ - true/false or nil for any
- +:support+ - true/false or nil for any
- +:add_vote_data+ - true/false. If true, custom columns vote_count and positive_votes will be added
28 29 30 31 32 33 34 35 |
# File 'app/services/item/article_retriever.rb', line 28 def initialize(article_types:, sales: nil, support: nil, add_vote_data: false) raise "Invalid article types, must be a non-empty array." unless article_types.present? && article_types.is_a?(Array) @sti_types = article_types.filter_map { |at| ARTICLE_TYPE_TO_STI[at.to_s] || at.to_s } @sales = sales @support = support @add_vote_data = add_vote_data end |
Instance Attribute Details
#add_vote_data ⇒ Object (readonly)
Returns the value of attribute add_vote_data.
19 20 21 |
# File 'app/services/item/article_retriever.rb', line 19 def add_vote_data @add_vote_data end |
#sales ⇒ Object (readonly)
Returns the value of attribute sales.
19 20 21 |
# File 'app/services/item/article_retriever.rb', line 19 def sales @sales end |
#sti_types ⇒ Object (readonly)
Returns the value of attribute sti_types.
19 20 21 |
# File 'app/services/item/article_retriever.rb', line 19 def sti_types @sti_types end |
#support ⇒ Object (readonly)
Returns the value of attribute support.
19 20 21 |
# File 'app/services/item/article_retriever.rb', line 19 def support @support end |
Instance Method Details
#process(item: nil, product_line: nil, product_category: nil, tags: nil) ⇒ Result
Retrieves all product specifications available to a given item
==== Parameters
- +item+ - The item for which you want to retrieve articles
==== Returns
A Result object with
Retrieves Article records matching the provided context and configured filters.
Applies configured STI types, sales/support flags, and optional vote enrichment; can filter by tags and by item, product line, and/or product category context, preloads tag associations, and returns a sorted, deduplicated set of articles.
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 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 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'app/services/item/article_retriever.rb', line 56 def process(item: nil, product_line: nil, product_category: nil, tags: nil) articles = [] article_scope = Article.all article_scope = article_scope.where(type: sti_types) if sti_types.present? article_scope = article_scope.where(sales: sales) unless sales.nil? article_scope = article_scope.where(support: support) unless support.nil? article_scope = article_scope.with_votes if add_vote_data # `tagged_with` called on the Article base class generates taggable_type = 'Article', # but taggings are stored using the actual STI class name (e.g. 'ArticleFaq', 'Post'). # Build a correlated EXISTS subquery with the correct taggable_type(s) explicitly. if .present? tag_names = Array().flatten.filter_map(&:presence).map { |t| t.to_s.strip.downcase }.uniq taggable_types = sti_types.presence || [Article.base_class.name] tag_subquery = Tagging .where(Tagging[:taggable_id].eq(Article.arel_table[:id])) .where(taggable_type: taggable_types) .joins(:tag) .where(Tag[:name].lower.in(tag_names)) .select('1') article_scope = article_scope.where("EXISTS (#{tag_subquery.to_sql})") end # Preload tags for efficient rendering with filter badges # Use preload (not includes) to avoid GROUP BY conflicts with with_votes scope article_scope = article_scope.preload(taggings: :tag) # Retrieve articles tagged to this specific item if item article_scope = article_scope.for_item_sku(item.sku) articles = article_scope.to_a if item.primary_product_line pl_articles = process(product_line: item.primary_product_line, product_category: item.product_category).articles articles += pl_articles # since we added product line articles, we have to resort now using both item and product line in our array end elsif product_line article_scope = article_scope.for_product_line_url_without_order(product_line.slug_ltree.to_s) # A product category can only be applied if a product line is specified # Match articles tagged for the relevant category OR articles with no # category restriction (empty array sentinel). if product_category article_scope = article_scope.where( "articles.applies_to_product_category_ids && ARRAY[?]::integer[] OR articles.applies_to_product_category_ids = '{}'", [product_category.id] ) elsif (pc_ids = product_line.product_category_ids.compact).present? article_scope = article_scope.where( "articles.applies_to_product_category_ids && ARRAY[?]::integer[] OR articles.applies_to_product_category_ids = '{}'", pc_ids ) end articles = article_scope.to_a else articles = article_scope.to_a end articles = if add_vote_data articles.sort_by { |a| [-(a.positive_votes.to_i + a.sort_booster.to_i), -(a.vote_count.to_i + a.sort_booster.to_i), a.subject] }.uniq else articles.sort_by(&:subject) end Result.new(articles: articles) end |