Reduce queries in API::Helpers#find_project
This method is implemented as follows:
def find_project(id)
project = Project.find_with_namespace(id) || Project.find_by(id: id)
if can?(current_user, :read_project, project)
project
else
not_found!('Project')
end
end
Given a numeric ID this method will run at least 2 queries to find the project:
- A query to find it by namespace (using
find_with_namespace
) - A query to find it by ID
This can be optimised in such a way that we always only run a single query when using something like:
if id =~ /^\d+$/
project = Project.find_by(id: id)
else
project = Project.find_with_namespace(id)
end
Furthermore the code can?(current_user, :read_project, project)
may end up running multiple queries depending on how its implemented. Similar to Ability.users_that_can_read_project
we should make sure this code only runs a single query. Since we only care about the read_project
permissions we shouldn't have to build an entire list of all possible permissions. The logic we can use instead is as simple as:
can_read = if user.admin?
true
elsif project.internal? && !user.external?
true
elsif project.owner == user
true
elsif project.team.members.include?(user)
true
else
false
end
So, in short:
- Optimise the finding of the project
- Measure how many queries
can?(current_user, :read_project, project)
will run - Given the number of queries is greater than 1, add a method that performs this check using as few queries as possible