AO3-7468 Preload current_user roles - #6002
Conversation
| expect(response).to have_http_status(:success) | ||
| end | ||
|
|
||
| it "preloads the user's roles" do |
There was a problem hiding this comment.
Instead of checking that roles are preloaded like this, you should create an n+1 test where the number of roles is variable, but get admin_user_path(user) should perform a constant number of queries for role lookups.
We have similar tests for other controller actions under spec/requests.
|
Thanks for the feedback! I replaced the controller preload assertion with a request-level N+1 test, preloaded roles for the history entries rendered on that page, and removed the two extra model expectations. |
| populate do |n| | ||
| role_names = %w[archivist no_resets official opendoors protected_user] | ||
| # Assigning roles also creates the role-change history rendered on this page. | ||
| user.reload.roles = role_names.first(n).map { |name| create(:role, name: name) } |
There was a problem hiding this comment.
You're limiting the number of roles to 5 or below. In populate you should create objects using the scale factor n, otherwise results won't be accurate.
Since we don't care what the roles actually are, you can do:
populate do |n|
user.roles = create_list(:role, n)
end|
|
||
| describe "#show", n_plus_one: true do | ||
| let!(:user) { create(:user) } | ||
| let!(:admin) { create(:policy_and_abuse_admin) } |
There was a problem hiding this comment.
You can inline admin in the before block - it won't be referred to elsewhere.
|
|
||
| it "performs a constant number of role queries" do | ||
| expect do | ||
| get admin_user_path(user) |
There was a problem hiding this comment.
You can define the get action as a subject:
subject do
proc do
get admin_user_path(user)
end
endthen use subject.call in both warmup and the actual test.
| it "performs a constant number of role queries" do | ||
| expect do | ||
| get admin_user_path(user) | ||
| expect(response).to have_http_status(:success) |
There was a problem hiding this comment.
These expects don't need to be nested here. You can move them after the first expect for constant query count.
| expect(response).to have_http_status(:success) | ||
| expect(response.body).to include("user_history") | ||
| end.to perform_constant_number_of_queries | ||
| .matching(/\b(?:roles|roles_users)\b/) |
There was a problem hiding this comment.
You should be able to skip matching and with_scale_factors, since these are the effects of only working with a max of 5 roles.
| include LoginMacros | ||
|
|
||
| describe "#show", n_plus_one: true do | ||
| let!(:user) { create(:user) } |
There was a problem hiding this comment.
You should wrap the tests in a context block e.g. "with a logged in user with multiple roles". There may be other kinds of n+1 queries we want to test for this controller action in the future.
Pull Request Checklist
as the first thing in your pull request title (e.g.
AO3-1234 Fix thing)until they are reviewed and merged before creating new pull requests.
Issue
https://otwarchive.atlassian.net/browse/AO3-7468
Purpose
This PR preloads a user's roles when Devise restores
current_userfrom the session. As a result, subsequenthas_role?permission checks use the loaded association instead of performing repeated role lookups throughout the request.It also:
has_role?for named-role checks in the admin user form.Credit
y7nieSEl5, she/her