File tree Expand file tree Collapse file tree 5 files changed +110
-0
lines changed Expand file tree Collapse file tree 5 files changed +110
-0
lines changed Original file line number Diff line number Diff line change
1
+ * [ #1324 ] ( https://github.com/rubocop/rubocop-rails/pull/1324 ) : Add ` Rails/FindByOrAssignmentMemoization ` cop. ([ @r7kamura ] [ ] )
Original file line number Diff line number Diff line change @@ -502,6 +502,12 @@ Rails/FindById:
502
502
Enabled : ' pending'
503
503
VersionAdded : ' 2.7'
504
504
505
+ Rails/FindByOrAssignmentMemoization :
506
+ Description : ' Avoid memoization by `find_by` with `||=`.'
507
+ Enabled : pending
508
+ Safe : false
509
+ VersionAdded : ' <<next>>'
510
+
505
511
Rails/FindEach :
506
512
Description : ' Prefer all.find_each over all.each.'
507
513
StyleGuide : ' https://rails.rubystyle.guide#find-each'
Original file line number Diff line number Diff line change
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Avoid memoization by `find_by` with `||=`.
7
+ #
8
+ # It is common to see code that attempts to memoize `find_by` result by `||=`,
9
+ # but `find_by` may return `nil`, in which case it is not memoized as intended.
10
+ #
11
+ # @safety
12
+ # This cop is unsafe because detected `find_by` may not be activerecord's method,
13
+ # or the code may have a different purpose than memoization.
14
+ #
15
+ # @example
16
+ # # bad
17
+ # def current_user
18
+ # @current_user ||= User.find_by(id: session[:user_id])
19
+ # end
20
+ #
21
+ # # good
22
+ # def current_user
23
+ # @current_user =
24
+ # if instance_variable_defined?(:@current_user)
25
+ # @current_user
26
+ # else
27
+ # User.find_by(id: session[:user_id])
28
+ # end
29
+ # end
30
+ class FindByOrAssignmentMemoization < Base
31
+ extend AutoCorrector
32
+
33
+ MSG = 'Avoid memoization by `find_by` with `||=`.'
34
+
35
+ RESTRICT_ON_SEND = %i[ find_by ] . freeze
36
+
37
+ def_node_matcher :find_by_or_assignment_memoization , <<~PATTERN
38
+ (or_asgn
39
+ (ivasgn $_)
40
+ $(send _ :find_by ...)
41
+ )
42
+ PATTERN
43
+
44
+ def on_send ( node )
45
+ assignment_node = node . parent
46
+ find_by_or_assignment_memoization ( assignment_node ) do |varible_name , find_by |
47
+ add_offense ( assignment_node ) do |corrector |
48
+ corrector . replace (
49
+ assignment_node ,
50
+ <<~RUBY . rstrip
51
+ #{ varible_name } =
52
+ if instance_variable_defined?(:#{ varible_name } )
53
+ #{ varible_name }
54
+ else
55
+ #{ find_by . source }
56
+ end
57
+ RUBY
58
+ )
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
Original file line number Diff line number Diff line change 55
55
require_relative 'rails/file_path'
56
56
require_relative 'rails/find_by'
57
57
require_relative 'rails/find_by_id'
58
+ require_relative 'rails/find_by_or_assignment_memoization'
58
59
require_relative 'rails/find_each'
59
60
require_relative 'rails/freeze_time'
60
61
require_relative 'rails/has_and_belongs_to_many'
Original file line number Diff line number Diff line change
1
+ # frozen_string_literal: true
2
+
3
+ RSpec . describe RuboCop ::Cop ::Rails ::FindByOrAssignmentMemoization , :config do
4
+ context 'when using `find_by` with `||=`' do
5
+ it 'registers an offense' do
6
+ expect_offense ( <<~RUBY )
7
+ @current_user ||= User.find_by(id: session[:user_id])
8
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Avoid memoization by `find_by` with `||=`.
9
+ RUBY
10
+
11
+ expect_correction ( <<~RUBY )
12
+ @current_user =
13
+ if instance_variable_defined?(:@current_user)
14
+ @current_user
15
+ else
16
+ User.find_by(id: session[:user_id])
17
+ end
18
+ RUBY
19
+ end
20
+ end
21
+
22
+ context 'with `find_by!`' do
23
+ it 'does not register an offense' do
24
+ expect_no_offenses ( <<~RUBY )
25
+ @current_user ||= User.find_by!(id: session[:user_id])
26
+ RUBY
27
+ end
28
+ end
29
+
30
+ context 'with local variable' do
31
+ it 'does not register an offense' do
32
+ expect_no_offenses ( <<~RUBY )
33
+ current_user ||= User.find_by(id: session[:user_id])
34
+ RUBY
35
+ end
36
+ end
37
+ end
You can’t perform that action at this time.
0 commit comments