Bajena/ams_lazy_relationships

View on GitHub
lib/ams_lazy_relationships/loaders/simple_has_many.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require "ams_lazy_relationships/loaders/base"

module AmsLazyRelationships
  module Loaders
    # Batch loads ActiveRecord records belonging to given record by foreign key.
    # Useful when the relationship is not a standard ActiveRecord relationship.
    class SimpleHasMany < Base
      # @param association_class_name [String] Name of the ActiveRecord class
      #   e.g. in case when loading blog_post.comments it'd be "Comment"
      # @param foreign_key [Symbol] association's foreign key.
      #   e.g. in case when loading blog_post.comments it'd be :blog_post_id
      def initialize(association_class_name, foreign_key:)
        @association_class_name = association_class_name
        @foreign_key = foreign_key.to_sym
      end

      private

      attr_reader :association_class_name, :foreign_key

      def load_data(records, loader)
        # Some records use UUID class as id - it's safer to cast them to strings
        record_ids = records.map { |r| r.id.to_s }
        association_class_name.constantize.where(
          foreign_key => record_ids
        ).tap do |data|
          resolve(records, data, loader)
        end
      end

      def resolve(records, data, loader)
        data = data.group_by { |d| d.public_send(foreign_key).to_s }

        records.each do |r|
          loader.call(r, data[r.id.to_s] || [])
        end
      end

      def batch_key(record)
        "#{record.class}/#{association_class_name}"
      end
    end
  end
end