docbrown/app/labor/article_suggester.rb
rhymes 6a626e819d Refactor: fix issues raised by bullet (#2965)
* Preload organization, not user

* Preload users only when needed

* Pre-load podcasts for podcast episodes in API

* Avoid eager loading error by loading rating votes separately

* Preload associations for moderation

* Preload user comments in trees

* Preload organization for non org dashboard and cleanup queries

* Optimize ArticleSuggester to only load N articles at need

* Remove eager loading and pass variables to partials for easier debug

* Reorganize tags validation code and ignore actsastaggableon eager loading issues

* Remove unused eager loading and bring up comments relation

* Preload podcasts when loading podcast episodes

* Fix views specs

* Make sure ArticleSuggester never returns duplicates

* Remove commented code

* Re-trigger build

* Move suggested articles back to view to respect fragment caching
2019-05-28 17:32:53 -04:00

51 lines
1.4 KiB
Ruby

class ArticleSuggester
def initialize(article)
@article = article
end
def articles(max: 4)
if article.tag_list.any?
# avoid loading more data if we don't need to
tagged_suggestions = suggestions_by_tag(max: max)
return tagged_suggestions if tagged_suggestions.size == max
# if there are not enough tagged articles, load other suggestions
# ignoring tagged articles that might be relevant twice, hence avoiding duplicates
num_remaining_needed = max - tagged_suggestions.size
other_articles = other_suggestions(
max: num_remaining_needed,
ids_to_ignore: tagged_suggestions.pluck(:id),
)
tagged_suggestions.union(other_articles)
else
other_suggestions(max: max)
end
end
private
attr_reader :article
def other_suggestions(max: 4, ids_to_ignore: [])
ids_to_ignore << article.id
Article.published.where(featured: true).
where.not(id: ids_to_ignore).
order("hotness_score DESC").
includes(:user).
offset(rand(0..offsets[1])).
first(max)
end
def suggestions_by_tag(max: 4)
Article.published.tagged_with(article.tag_list, any: true).
where.not(id: article.id).
order("hotness_score DESC").
includes(:user).
offset(rand(0..offsets[0])).
first(max)
end
def offsets
Rails.env.production? ? [10, 120] : [0, 0]
end
end