Remove N+1 query for project and group boards

- Add test for N+1 queries
- Add destroyable lists scope to Board and List
- Preload lists for both project and group boards
This commit is contained in:
charlieablett 2019-06-14 10:20:03 +12:00
parent 4633df7b9e
commit 426f1c20b1
7 changed files with 25 additions and 4 deletions

View file

@ -5,10 +5,13 @@ class Board < ApplicationRecord
belongs_to :project
has_many :lists, -> { order(:list_type, :position) }, dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :destroyable_lists, -> { destroyable }, class_name: "List"
validates :project, presence: true, if: :project_needed?
validates :group, presence: true, unless: :project
scope :with_associations, -> { preload(:destroyable_lists) }
def project_needed?
!group
end

View file

@ -2,4 +2,12 @@
class BoardSerializer < BaseSerializer
entity BoardSimpleEntity
def represent(resource, opts = {})
if resource.respond_to?(:with_associations)
resource = resource.with_associations
end
super
end
end

View file

@ -27,7 +27,7 @@ module API
end
get '/' do
authorize!(:read_board, user_project)
present paginate(board_parent.boards), with: Entities::Board
present paginate(board_parent.boards.with_associations), with: Entities::Board
end
desc 'Find a project board' do

View file

@ -11,7 +11,7 @@ module API
end
def board_lists
board.lists.destroyable
board.destroyable_lists
end
def create_list

View file

@ -1101,7 +1101,7 @@ module API
expose :project, using: Entities::BasicProjectDetails
expose :lists, using: Entities::List do |board|
board.lists.destroyable
board.destroyable_lists
end
end

View file

@ -37,7 +37,7 @@ module API
use :pagination
end
get '/' do
present paginate(board_parent.boards), with: Entities::Board
present paginate(board_parent.boards.with_associations), with: Entities::Board
end
end

View file

@ -14,6 +14,16 @@ shared_examples_for 'group and project boards' do |route_definition, ee = false|
end
end
it 'avoids N+1 queries' do
pat = create(:personal_access_token, user: user)
control = ActiveRecord::QueryRecorder.new { get api(root_url, personal_access_token: pat) }
create(:milestone, "#{board_parent.class.name.underscore}": board_parent)
create(:board, "#{board_parent.class.name.underscore}": board_parent)
expect { get api(root_url, personal_access_token: pat) }.not_to exceed_query_limit(control)
end
describe "GET #{route_definition}" do
context "when unauthenticated" do
it "returns authentication error" do