Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
d68ee30a
Commit
d68ee30a
authored
Sep 27, 2019
by
Heinrich Lee Yu
Committed by
Douglas Barbosa Alexandre
Sep 27, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix N+1 in board lists
This reintroduces preloading of user preferences which we removed to fix a bug
parent
a193c73a
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
57 additions
and
50 deletions
+57
-50
app/controllers/boards/lists_controller.rb
app/controllers/boards/lists_controller.rb
+6
-1
app/models/list.rb
app/models/list.rb
+13
-23
app/services/boards/lists/list_service.rb
app/services/boards/lists/list_service.rb
+1
-1
spec/controllers/boards/lists_controller_spec.rb
spec/controllers/boards/lists_controller_spec.rb
+12
-13
spec/models/list_spec.rb
spec/models/list_spec.rb
+0
-12
spec/requests/boards/lists_controller_spec.rb
spec/requests/boards/lists_controller_spec.rb
+25
-0
No files found.
app/controllers/boards/lists_controller.rb
View file @
d68ee30a
...
@@ -11,6 +11,8 @@ module Boards
...
@@ -11,6 +11,8 @@ module Boards
def
index
def
index
lists
=
Boards
::
Lists
::
ListService
.
new
(
board
.
parent
,
current_user
).
execute
(
board
)
lists
=
Boards
::
Lists
::
ListService
.
new
(
board
.
parent
,
current_user
).
execute
(
board
)
List
.
preload_preferences_for_user
(
lists
,
current_user
)
render
json:
serialize_as_json
(
lists
)
render
json:
serialize_as_json
(
lists
)
end
end
...
@@ -51,7 +53,10 @@ module Boards
...
@@ -51,7 +53,10 @@ module Boards
service
=
Boards
::
Lists
::
GenerateService
.
new
(
board_parent
,
current_user
)
service
=
Boards
::
Lists
::
GenerateService
.
new
(
board_parent
,
current_user
)
if
service
.
execute
(
board
)
if
service
.
execute
(
board
)
lists
=
board
.
lists
.
movable
.
preload_associations
(
current_user
)
lists
=
board
.
lists
.
movable
.
preload_associations
List
.
preload_preferences_for_user
(
lists
,
current_user
)
render
json:
serialize_as_json
(
lists
)
render
json:
serialize_as_json
(
lists
)
else
else
head
:unprocessable_entity
head
:unprocessable_entity
...
...
app/models/list.rb
View file @
d68ee30a
...
@@ -21,20 +21,10 @@ class List < ApplicationRecord
...
@@ -21,20 +21,10 @@ class List < ApplicationRecord
scope
:destroyable
,
->
{
where
(
list_type:
list_types
.
slice
(
*
destroyable_types
).
values
)
}
scope
:destroyable
,
->
{
where
(
list_type:
list_types
.
slice
(
*
destroyable_types
).
values
)
}
scope
:movable
,
->
{
where
(
list_type:
list_types
.
slice
(
*
movable_types
).
values
)
}
scope
:movable
,
->
{
where
(
list_type:
list_types
.
slice
(
*
movable_types
).
values
)
}
scope
:preload_associations
,
->
(
user
)
do
scope
:preload_associations
,
->
{
preload
(
:board
,
label: :priorities
)
}
preload
(
:board
,
label: :priorities
)
end
scope
:ordered
,
->
{
order
(
:list_type
,
:position
)
}
scope
:ordered
,
->
{
order
(
:list_type
,
:position
)
}
# Loads list with preferences for given user
# if preferences exists for user or not
scope
:with_preferences_for
,
->
(
user
)
do
return
unless
user
includes
(
:list_user_preferences
).
where
(
list_user_preferences:
{
user_id:
[
user
.
id
,
nil
]
})
end
alias_method
:preferences
,
:list_user_preferences
alias_method
:preferences
,
:list_user_preferences
class
<<
self
class
<<
self
...
@@ -45,25 +35,25 @@ class List < ApplicationRecord
...
@@ -45,25 +35,25 @@ class List < ApplicationRecord
def
movable_types
def
movable_types
[
:label
]
[
:label
]
end
end
def
preload_preferences_for_user
(
lists
,
user
)
return
unless
user
lists
.
each
{
|
list
|
list
.
preferences_for
(
user
)
}
end
end
end
def
preferences_for
(
user
)
def
preferences_for
(
user
)
return
preferences
.
build
unless
user
return
preferences
.
build
unless
user
if
preferences
.
loaded?
BatchLoader
.
for
(
list_id:
id
,
user_id:
user
.
id
).
batch
(
default_value:
preferences
.
build
(
user:
user
))
do
|
items
,
loader
|
preloaded_preferences_for
(
user
)
list_ids
=
items
.
map
{
|
i
|
i
[
:list_id
]
}
else
user_ids
=
items
.
map
{
|
i
|
i
[
:user_id
]
}
preferences
.
find_or_initialize_by
(
user:
user
)
end
end
def
preloaded_preferences_for
(
user
)
ListUserPreference
.
where
(
list_id:
list_ids
,
user_id:
user_ids
).
find_each
do
|
preference
|
user_preferences
=
loader
.
call
({
list_id:
preference
.
list_id
,
user_id:
preference
.
user_id
},
preference
)
preferences
.
find
do
|
preference
|
preference
.
user_id
==
user
.
id
end
end
end
user_preferences
||
preferences
.
build
(
user:
user
)
end
end
def
update_preferences_for
(
user
,
preferences
=
{})
def
update_preferences_for
(
user
,
preferences
=
{})
...
...
app/services/boards/lists/list_service.rb
View file @
d68ee30a
...
@@ -6,7 +6,7 @@ module Boards
...
@@ -6,7 +6,7 @@ module Boards
def
execute
(
board
)
def
execute
(
board
)
board
.
lists
.
create
(
list_type: :backlog
)
unless
board
.
lists
.
backlog
.
exists?
board
.
lists
.
create
(
list_type: :backlog
)
unless
board
.
lists
.
backlog
.
exists?
board
.
lists
.
preload_associations
(
current_user
)
board
.
lists
.
preload_associations
end
end
end
end
end
end
...
...
spec/controllers/boards/lists_controller_spec.rb
View file @
d68ee30a
...
@@ -14,6 +14,10 @@ describe Boards::ListsController do
...
@@ -14,6 +14,10 @@ describe Boards::ListsController do
end
end
describe
'GET index'
do
describe
'GET index'
do
before
do
create
(
:list
,
board:
board
)
end
it
'returns a successful 200 response'
do
it
'returns a successful 200 response'
do
read_board_list
user:
user
,
board:
board
read_board_list
user:
user
,
board:
board
...
@@ -22,27 +26,22 @@ describe Boards::ListsController do
...
@@ -22,27 +26,22 @@ describe Boards::ListsController do
end
end
it
'returns a list of board lists'
do
it
'returns a list of board lists'
do
create
(
:list
,
board:
board
)
read_board_list
user:
user
,
board:
board
read_board_list
user:
user
,
board:
board
expect
(
response
).
to
match_response_schema
(
'lists'
)
expect
(
response
).
to
match_response_schema
(
'lists'
)
expect
(
json_response
.
length
).
to
eq
3
expect
(
json_response
.
length
).
to
eq
3
end
end
it
'avoids n+1 queries when serializing lists'
do
context
'when another user has list preferences'
do
list_1
=
create
(
:list
,
board:
board
)
before
do
list_1
.
update_preferences_for
(
user
,
{
collapsed:
true
})
board
.
lists
.
first
.
update_preferences_for
(
guest
,
collapsed:
true
)
end
control_count
=
ActiveRecord
::
QueryRecorder
.
new
{
read_board_list
user:
user
,
board:
board
}.
count
list_2
=
create
(
:list
,
board:
board
)
list_2
.
update_preferences_for
(
user
,
{
collapsed:
true
})
list_3
=
create
(
:list
,
board:
board
)
it
'returns the complete list of board lists'
do
list_3
.
update_preferences_for
(
user
,
{
collapsed:
true
})
read_board_list
user:
user
,
board:
board
expect
{
read_board_list
user:
user
,
board:
board
}.
not_to
exceed_query_limit
(
control_count
)
expect
(
json_response
.
length
).
to
eq
3
end
end
end
context
'with unauthorized user'
do
context
'with unauthorized user'
do
...
...
spec/models/list_spec.rb
View file @
d68ee30a
...
@@ -136,18 +136,6 @@ describe List do
...
@@ -136,18 +136,6 @@ describe List do
expect
(
preferences
).
to
be_persisted
expect
(
preferences
).
to
be_persisted
expect
(
preferences
.
collapsed
).
to
eq
(
true
)
expect
(
preferences
.
collapsed
).
to
eq
(
true
)
end
end
context
'when preferences are already loaded for user'
do
it
'gets preloaded user preferences'
do
fetched_list
=
described_class
.
where
(
id:
list
.
id
).
with_preferences_for
(
user
).
first
expect
(
fetched_list
).
to
receive
(
:preloaded_preferences_for
).
with
(
user
).
and_call_original
preferences
=
fetched_list
.
preferences_for
(
user
)
expect
(
preferences
.
collapsed
).
to
eq
(
true
)
end
end
end
end
context
'when preferences for user does not exist'
do
context
'when preferences for user does not exist'
do
...
...
spec/requests/boards/lists_controller_spec.rb
0 → 100644
View file @
d68ee30a
# frozen_string_literal: true
require
'spec_helper'
describe
Boards
::
ListsController
do
describe
'#index'
do
let
(
:board
)
{
create
(
:board
)
}
let
(
:user
)
{
board
.
project
.
owner
}
it
'does not have N+1 queries'
do
login_as
(
user
)
# First request has more queries because we create the default `backlog` list
get
board_lists_path
(
board
)
create
(
:list
,
board:
board
)
control_count
=
ActiveRecord
::
QueryRecorder
.
new
{
get
board_lists_path
(
board
)
}.
count
create_list
(
:list
,
5
,
board:
board
)
expect
{
get
board_lists_path
(
board
)
}.
not_to
exceed_query_limit
(
control_count
)
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment