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: [:pro_membership]). 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: [:pro_membership]). offset(rand(0..offsets[0])). first(max) end def offsets Rails.env.production? ? [10, 120] : [0, 0] end end