Fix multiple N+1s in ConversationsController (#25134)
This commit is contained in:
		
							parent
							
								
									675672feb6
								
							
						
					
					
						commit
						2b45fecde1
					
				| @ -11,7 +11,7 @@ class Api::V1::ConversationsController < Api::BaseController | |||||||
| 
 | 
 | ||||||
|   def index |   def index | ||||||
|     @conversations = paginated_conversations |     @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 |   end | ||||||
| 
 | 
 | ||||||
|   def read |   def read | ||||||
| @ -32,7 +32,20 @@ class Api::V1::ConversationsController < Api::BaseController | |||||||
| 
 | 
 | ||||||
|   def paginated_conversations |   def paginated_conversations | ||||||
|     AccountConversation.where(account: current_account) |     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 |   end | ||||||
| 
 | 
 | ||||||
|   def insert_pagination_headers |   def insert_pagination_headers | ||||||
|  | |||||||
| @ -17,6 +17,8 @@ | |||||||
| class AccountConversation < ApplicationRecord | class AccountConversation < ApplicationRecord | ||||||
|   include Redisable |   include Redisable | ||||||
| 
 | 
 | ||||||
|  |   attr_writer :participant_accounts | ||||||
|  | 
 | ||||||
|   before_validation :set_last_status |   before_validation :set_last_status | ||||||
|   after_commit :push_to_streaming_api |   after_commit :push_to_streaming_api | ||||||
| 
 | 
 | ||||||
| @ -26,26 +28,42 @@ class AccountConversation < ApplicationRecord | |||||||
| 
 | 
 | ||||||
|   def participant_account_ids=(arr) |   def participant_account_ids=(arr) | ||||||
|     self[:participant_account_ids] = arr.sort |     self[:participant_account_ids] = arr.sort | ||||||
|  |     @participant_accounts = nil | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   def participant_accounts |   def participant_accounts | ||||||
|  |     @participant_accounts ||= begin | ||||||
|       if participant_account_ids.empty? |       if participant_account_ids.empty? | ||||||
|         [account] |         [account] | ||||||
|       else |       else | ||||||
|       participants = Account.where(id: participant_account_ids) |         participants = Account.where(id: participant_account_ids).to_a | ||||||
|         participants.empty? ? [account] : participants |         participants.empty? ? [account] : participants | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  |   end | ||||||
| 
 | 
 | ||||||
|   class << self |   class << self | ||||||
|     def to_a_paginated_by_id(limit, options = {}) |     def to_a_paginated_by_id(limit, min_id: nil, max_id: nil, since_id: nil, preload_participants: true) | ||||||
|       if options[:min_id] |       array = begin | ||||||
|         paginate_by_min_id(limit, options[:min_id], options[:max_id]).reverse |         if min_id | ||||||
|  |           paginate_by_min_id(limit, min_id, max_id).reverse | ||||||
|         else |         else | ||||||
|         paginate_by_max_id(limit, options[:max_id], options[:since_id]).to_a |           paginate_by_max_id(limit, max_id, since_id).to_a | ||||||
|         end |         end | ||||||
|       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) |     def paginate_by_min_id(limit, min_id = nil, max_id = nil) | ||||||
|       query = order(arel_table[:last_status_id].asc).limit(limit) |       query = order(arel_table[:last_status_id].asc).limit(limit) | ||||||
|       query = query.where(arel_table[:last_status_id].gt(min_id)) if min_id.present? |       query = query.where(arel_table[:last_status_id].gt(min_id)) if min_id.present? | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user