Fix multiple N+1s in ConversationsController (#25134)
This commit is contained in:
		
							parent
							
								
									bc8592627b
								
							
						
					
					
						commit
						3e1724e972
					
				@ -11,7 +11,7 @@ class Api::V1::ConversationsController < Api::BaseController
 | 
			
		||||
 | 
			
		||||
  def index
 | 
			
		||||
    @conversations = paginated_conversations
 | 
			
		||||
    render json: @conversations, each_serializer: REST::ConversationSerializer
 | 
			
		||||
    render json: @conversations, each_serializer: REST::ConversationSerializer, relationships: StatusRelationshipsPresenter.new(@conversations.map(&:last_status), current_user&.account_id)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def read
 | 
			
		||||
@ -32,7 +32,20 @@ class Api::V1::ConversationsController < Api::BaseController
 | 
			
		||||
 | 
			
		||||
  def paginated_conversations
 | 
			
		||||
    AccountConversation.where(account: current_account)
 | 
			
		||||
                       .to_a_paginated_by_id(limit_param(LIMIT), params_slice(:max_id, :since_id, :min_id))
 | 
			
		||||
                       .includes(
 | 
			
		||||
                         account: :account_stat,
 | 
			
		||||
                         last_status: [
 | 
			
		||||
                           :media_attachments,
 | 
			
		||||
                           :preview_cards,
 | 
			
		||||
                           :status_stat,
 | 
			
		||||
                           :tags,
 | 
			
		||||
                           {
 | 
			
		||||
                             active_mentions: [account: :account_stat],
 | 
			
		||||
                             account: :account_stat,
 | 
			
		||||
                           },
 | 
			
		||||
                         ]
 | 
			
		||||
                       )
 | 
			
		||||
                       .to_a_paginated_by_id(limit_param(LIMIT), **params_slice(:max_id, :since_id, :min_id))
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def insert_pagination_headers
 | 
			
		||||
 | 
			
		||||
@ -16,34 +16,51 @@
 | 
			
		||||
class AccountConversation < ApplicationRecord
 | 
			
		||||
  include Redisable
 | 
			
		||||
 | 
			
		||||
  attr_writer :participant_accounts
 | 
			
		||||
 | 
			
		||||
  before_validation :set_last_status
 | 
			
		||||
  after_commit :push_to_streaming_api
 | 
			
		||||
 | 
			
		||||
  belongs_to :account
 | 
			
		||||
  belongs_to :conversation
 | 
			
		||||
  belongs_to :last_status, class_name: 'Status'
 | 
			
		||||
 | 
			
		||||
  before_validation :set_last_status
 | 
			
		||||
 | 
			
		||||
  def participant_account_ids=(arr)
 | 
			
		||||
    self[:participant_account_ids] = arr.sort
 | 
			
		||||
    @participant_accounts = nil
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def participant_accounts
 | 
			
		||||
    if participant_account_ids.empty?
 | 
			
		||||
      [account]
 | 
			
		||||
    else
 | 
			
		||||
      participants = Account.where(id: participant_account_ids)
 | 
			
		||||
      participants.empty? ? [account] : participants
 | 
			
		||||
    @participant_accounts ||= begin
 | 
			
		||||
      if participant_account_ids.empty?
 | 
			
		||||
        [account]
 | 
			
		||||
      else
 | 
			
		||||
        participants = Account.where(id: participant_account_ids).to_a
 | 
			
		||||
        participants.empty? ? [account] : participants
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  class << self
 | 
			
		||||
    def to_a_paginated_by_id(limit, options = {})
 | 
			
		||||
      if options[:min_id]
 | 
			
		||||
        paginate_by_min_id(limit, options[:min_id], options[:max_id]).reverse
 | 
			
		||||
      else
 | 
			
		||||
        paginate_by_max_id(limit, options[:max_id], options[:since_id]).to_a
 | 
			
		||||
    def to_a_paginated_by_id(limit, min_id: nil, max_id: nil, since_id: nil, preload_participants: true)
 | 
			
		||||
      array = begin
 | 
			
		||||
        if min_id
 | 
			
		||||
          paginate_by_min_id(limit, min_id, max_id).reverse
 | 
			
		||||
        else
 | 
			
		||||
          paginate_by_max_id(limit, max_id, since_id).to_a
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      if preload_participants
 | 
			
		||||
        participant_ids = array.flat_map(&:participant_account_ids)
 | 
			
		||||
        accounts_by_id = Account.where(id: participant_ids).index_by(&:id)
 | 
			
		||||
 | 
			
		||||
        array.each do |conversation|
 | 
			
		||||
          conversation.participant_accounts = conversation.participant_account_ids.filter_map { |id| accounts_by_id[id] }
 | 
			
		||||
        end
 | 
			
		||||
      end
 | 
			
		||||
 | 
			
		||||
      array
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
    def paginate_by_min_id(limit, min_id = nil, max_id = nil)
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user