Skip to content

Commit 1872c95

Browse files
committed
Fix wrong autocorrect for Rails/FindByOrAssignmentMemoization
Followup to 501e5d3
1 parent e6c2b15 commit 1872c95

File tree

3 files changed

+84
-5
lines changed

3 files changed

+84
-5
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#1516](https://github.com/rubocop/rubocop-rails/pull/1516): Fix wrong autocorrect for `Rails/FindByOrAssignmentMemoization`. ([@earlopain][])

lib/rubocop/cop/rails/find_by_or_assignment_memoization.rb

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ module Rails
1313
# or the code may have a different purpose than memoization.
1414
#
1515
# @example
16-
# # bad
16+
# # bad - exclusively doing memoization
1717
# def current_user
1818
# @current_user ||= User.find_by(id: session[:user_id])
1919
# end
@@ -24,6 +24,22 @@ module Rails
2424
#
2525
# @current_user = User.find_by(id: session[:user_id])
2626
# end
27+
#
28+
# # bad - method contains other code
29+
# def current_user
30+
# @current_user ||= User.find_by(id: session[:user_id])
31+
# @current_user.do_something
32+
# end
33+
#
34+
# # good
35+
# def current_user
36+
# if defined?(@current_user)
37+
# @current_user
38+
# else
39+
# @current_user = User.find_by(id: session[:user_id])
40+
# end
41+
# @current_user.do_something
42+
# end
2743
class FindByOrAssignmentMemoization < Base
2844
extend AutoCorrector
2945

@@ -38,6 +54,22 @@ class FindByOrAssignmentMemoization < Base
3854
)
3955
PATTERN
4056

57+
# When a method body contains only memoization, the correction can be more succinct.
58+
def on_def(node)
59+
find_by_or_assignment_memoization(node.body) do |varible_name, find_by|
60+
add_offense(node.body) do |corrector|
61+
corrector.replace(
62+
node.body,
63+
<<~RUBY.rstrip
64+
return #{varible_name} if defined?(#{varible_name})
65+
66+
#{varible_name} = #{find_by.source}
67+
RUBY
68+
)
69+
end
70+
end
71+
end
72+
4173
def on_send(node)
4274
assignment_node = node.parent
4375
find_by_or_assignment_memoization(assignment_node) do |varible_name, find_by|
@@ -47,9 +79,11 @@ def on_send(node)
4779
corrector.replace(
4880
assignment_node,
4981
<<~RUBY.rstrip
50-
return #{varible_name} if defined?(#{varible_name})
51-
52-
#{varible_name} = #{find_by.source}
82+
if defined?(#{varible_name})
83+
#{varible_name}
84+
else
85+
#{varible_name} = #{find_by.source}
86+
end
5387
RUBY
5488
)
5589
end

spec/rubocop/cop/rails/find_by_or_assignment_memoization_spec.rb

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,53 @@
99
RUBY
1010

1111
expect_correction(<<~RUBY)
12-
return @current_user if defined?(@current_user)
12+
if defined?(@current_user)
13+
@current_user
14+
else
15+
@current_user = User.find_by(id: session[:user_id])
16+
end
17+
RUBY
18+
end
19+
end
20+
21+
context 'when using `find_by` with `||=` in a method body' do
22+
it 'registers an offense' do
23+
expect_offense(<<~RUBY)
24+
def foo
25+
@current_user ||= User.find_by(id: session[:user_id])
26+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid memoizing `find_by` results with `||=`.
27+
end
28+
RUBY
29+
30+
expect_correction(<<~RUBY)
31+
def foo
32+
return @current_user if defined?(@current_user)
1333
1434
@current_user = User.find_by(id: session[:user_id])
35+
end
36+
RUBY
37+
end
38+
39+
it 'registers registers an offense when the method contains other code' do
40+
expect_offense(<<~RUBY)
41+
def foo
42+
@current_user ||= User.find_by(id: session[:user_id])
43+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid memoizing `find_by` results with `||=`.
44+
45+
@current_user.do_something!
46+
end
47+
RUBY
48+
49+
expect_correction(<<~RUBY)
50+
def foo
51+
if defined?(@current_user)
52+
@current_user
53+
else
54+
@current_user = User.find_by(id: session[:user_id])
55+
end
56+
57+
@current_user.do_something!
58+
end
1559
RUBY
1660
end
1761
end

0 commit comments

Comments
 (0)