Sha256: 8ff878c0a62c38e45a81effec6fbf50527e6ae41ba7d0d01fd7d14f5378db07c

Contents?: true

Size: 1.7 KB

Versions: 13

Compression:

Stored size: 1.7 KB

Contents

# frozen_string_literal: true

require "n1_loader/active_record"

require_relative 'context/setup_database'

class User < ActiveRecord::Base
  has_many :payments

  n1_optimized :payments_total do
    # Arguments can be:
    # argument :something, optional: true
    # argument :something, default: -> { 100 }
    #
    # Note: do not use mutable (mostly timing related) defaults like:
    # argument :from, default -> { 2.minutes.from_now }
    # because such values will be unique for every loader call which will make N+1 issue stay
    argument :from
    argument :to

    # This is used to define logic how loaders are compared to each other
    # default is:
    # cache_key { *arguments.map(&:object_id) }
    cache_key { [from, to] }

    def perform(users)
      total_per_user =
        Payment
        .group(:user_id)
        .where(created_at: from..to)
        .where(user: users)
        .sum(:amount)
        .tap { |h| h.default = 0 }

      users.each do |user|
        total = total_per_user[user.id]
        fulfill(user, total)
      end
    end
  end
end

class Payment < ActiveRecord::Base
  belongs_to :user

  validates :amount, presence: true
end

fill_database

from = 2.days.ago
to = 1.day.ago

# Has N+1
p User.all.map { |user|
  user.payments.select do |payment|
    payment.created_at >= from && payment.created_at <= to
  end.sum(&:amount)
}
# Has no N+1 but we load too many data that we don't need
p User.all.includes(:payments).map { |user|
  user.payments.select do |payment|
    payment.created_at >= from && payment.created_at <= to
  end.sum(&:amount)
}
# Has no N+1 and calculation is the most efficient
p User.all.includes(:payments_total).map { |user| user.payments_total(from: from, to: to) }

Version data entries

13 entries across 13 versions & 1 rubygems

Version Path
n1_loader-1.7.2 examples/arguments_support.rb
n1_loader-1.7.1 examples/arguments_support.rb
n1_loader-1.7.0 examples/arguments_support.rb
n1_loader-1.6.6 examples/arguments_support.rb
n1_loader-1.6.5 examples/arguments_support.rb
n1_loader-1.6.4 examples/arguments_support.rb
n1_loader-1.6.3 examples/arguments_support.rb
n1_loader-1.6.2 examples/arguments_support.rb
n1_loader-1.6.1 examples/arguments_support.rb
n1_loader-1.6.0 examples/arguments_support.rb
n1_loader-1.5.1 examples/arguments_support.rb
n1_loader-1.5.0 examples/arguments_support.rb
n1_loader-1.4.4 examples/arguments_support.rb