Skip to content

Commit cbe4fb8

Browse files
committed
Ruby: initial version of N+1 queries problem
1 parent c1adf01 commit cbe4fb8

File tree

5 files changed

+417
-1
lines changed

5 files changed

+417
-1
lines changed

ruby/ql/lib/codeql/ruby/frameworks/core/Kernel.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ module Kernel {
4242
* arr.send("push", 5) # => [5]
4343
* ```
4444
*/
45-
private predicate isPublicKernelMethod(string method) {
45+
predicate isPublicKernelMethod(string method) {
4646
method in [
4747
"class", "clone", "frozen?", "tap", "then", "yield_self", "send", "public_send", "__send__",
4848
"method", "public_method", "singleton_method"
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>
8+
9+
Performing database queries in a loop can be inefficient
10+
compared to performing a single query up front that retrieves all the data at once.
11+
12+
</p>
13+
14+
<p>
15+
16+
ORMs such as ActiveRecord implicitly query the database when certain
17+
members of an object are being accessed. But if such a member is accessed in a loop,
18+
it can result in a separate query for each iteration. ActiveRecord
19+
provides a way to eagerly load associated data using the <code>includes</code>
20+
method, which can be used to speed up such queries.
21+
22+
</p>
23+
</overview>
24+
25+
<recommendation>
26+
<p>
27+
28+
In ActiveRecord, use <code>includes</code> to eagerly load associated
29+
data that you expect to access in a loop.
30+
31+
</p>
32+
</recommendation>
33+
34+
<example>
35+
36+
<p>
37+
38+
The following example code gets the names of all podcasts followed by a user:
39+
40+
</p>
41+
42+
<sample src="examples/ActiveRecordQueryInLoop.rb"/>
43+
44+
<p>
45+
46+
However, the call to <code>name</code> inside the loop will result in a separate
47+
SQL query being executed to obtain the name. To speed this up, use
48+
<code>includes</code> to eagerly load the associated data:
49+
50+
</p>
51+
52+
<sample src="examples/ActiveRecordQueryInLoopFixed.rb"/>
53+
54+
<p>
55+
56+
Now all the associated podcast names are loaded up front with a single SQL query,
57+
and the call to <code>name</code> no longer results in a separate query.
58+
59+
</p>
60+
61+
</example>
62+
63+
<references>
64+
<li>OWASP: <a href="https://www.owasp.org/index.php/Server_Side_Request_Forgery">SSRF</a></li>
65+
<li>OWASP: <a href="https://cheatsheetseries.owasp.org/cheatsheets/Unvalidated_Redirects_and_Forwards_Cheat_Sheet.html">XSS Unvalidated Redirects and Forwards Cheat Sheet</a>.</li>
66+
</references>
67+
</qhelp>

0 commit comments

Comments
 (0)