sanger/sequencescape

View on GitHub
app/models/comment.rb

Summary

Maintainability
A
0 mins
Test Coverage
A
94%
# frozen_string_literal: true
# A comment can be assigned to any commentable record.
class Comment < ApplicationRecord
  # include Uuid::Uuidable
  belongs_to :commentable, polymorphic: true, optional: false
  has_many :comments, as: :commentable
  belongs_to :user

  # @!attribute title
  #   @return [String] A short string, best used to identify the comment source.
  # @!attribute key
  #   @return [String] Longer text containing the main body of the comment

  after_create :trigger_commentable_callback

  scope :include_uuid, -> { all }

  # Caution, only works for a single class
  def self.counts_for(commentables)
    where(commentable: commentables).group(:commentable_id).count
  end

  #
  # We don't want to load comments upfront, as it can result in a lot of data
  # in some cases. However, we do want to display counts. However when it
  # comes to requests, there are three places we may wish to look:
  # - The request itself
  # - The receptacle (source receptacle)
  # - The labware associated with the receptacle
  # Rather than having three separate columns, we instead reduce it down to
  # a single place. This method lets us aggregate those counts
  # @param requests [Array<Request>] Requests to get counts for. Preferably with preloaded assets
  #
  # @return [Hash] Hash of counts indexed by request_id
  #
  def self.counts_for_requests(requests) # rubocop:todo Metrics/AbcSize
    all_commentables = requests.flat_map { |request| [request, request.asset, request.asset&.labware] }
    counts = where(commentable: all_commentables.compact).group(:commentable_type, :commentable_id).count
    requests.each_with_object({}) do |request, counter_cache|
      request_count = counts.fetch(['Request', request.id], 0)
      receptacle_count = counts.fetch(['Receptacle', request.asset_id], 0)
      labware_count = counts.fetch(['Labware', request.asset.labware_id], 0)
      counter_cache[request.id] = request_count + receptacle_count + labware_count
    end
  end

  private

  ##
  # We add the comments to each submission to ensure that are available for all the requests.
  # At time of writing, submissions add comments to each request, so there are a lot of comments
  # getting created here. We should consider either storing comments on submissions, orders,
  # or having a many-to-many relationship.
  def trigger_commentable_callback
    commentable.try(:after_comment_addition, self)
  end
end