Skip to content

Commit e2912eb

Browse files
committed
Add cop for checking duplicate assingments to ignored_columns
Overwriting previous assignments is usually a mistake, since it will un-ignore the first set of columns
1 parent 210c368 commit e2912eb

File tree

5 files changed

+117
-0
lines changed

5 files changed

+117
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* [#514](https://github.com/rubocop/rubocop-rails/pull/514): Add new `Rails/DuplicateIgnoredColumns` cop. ([@fsateler][])

config/default.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,11 @@ Rails/DelegateAllowBlank:
251251
Enabled: true
252252
VersionAdded: '0.44'
253253

254+
Rails/DuplicateIgnoredColumns:
255+
Description: 'Looks for assignments of `ignored_columns` that override previous assignments.'
256+
Enabled: pending
257+
VersionAdded: '<<next>>'
258+
254259
Rails/DurationArithmetic:
255260
Description: 'Do not use duration as arithmetic operand with `Time.current`.'
256261
StyleGuide: 'https://rails.rubystyle.guide#duration-arithmetic'
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# frozen_string_literal: true
2+
3+
module RuboCop
4+
module Cop
5+
module Rails
6+
# This cops looks for assignments of `ignored_columns` that override previous
7+
# assignments.
8+
#
9+
# Overwriting previous assignments is usually a mistake, since it will
10+
# un-ignore the first set of columns
11+
#
12+
# @example
13+
#
14+
# # bad
15+
# class User < ActiveRecord::Base
16+
# self.ignored_columns = [:one]
17+
# self.ignored_columns = [:two]
18+
# end
19+
#
20+
# # bad
21+
# class User < ActiveRecord::Base
22+
# self.ignored_columns += [:one]
23+
# self.ignored_columns = [:two]
24+
# end
25+
#
26+
# # good
27+
# class User < ActiveRecord::Base
28+
# self.ignored_columns = [:one, :two]
29+
# end
30+
#
31+
# # good
32+
# class User < ActiveRecord::Base
33+
# self.ignored_columns = [:one]
34+
# self.ignored_columns += [:two]
35+
# end
36+
#
37+
class DuplicateIgnoredColumns < Base
38+
MSG = 'This assignment to `ignored_columns` overwrites previous ones.'
39+
40+
def_node_matcher :ignored_columns_assign, <<-PATTERN
41+
(send self :ignored_columns= ...)
42+
PATTERN
43+
def_node_matcher :ignored_columns_append, <<-PATTERN
44+
(op-asgn
45+
(send self :ignored_columns)
46+
:+ ...
47+
)
48+
PATTERN
49+
50+
def on_op_asgn(node)
51+
ignored_columns_append(node) do
52+
@seen_before = true
53+
end
54+
end
55+
56+
def on_send(node)
57+
ignored_columns_assign(node) do
58+
add_offense(node) if @seen_before
59+
@seen_before = true
60+
end
61+
end
62+
63+
def on_new_investigation
64+
@seen_before = false
65+
super
66+
end
67+
end
68+
end
69+
end
70+
end

lib/rubocop/cop/rails_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
require_relative 'rails/default_scope'
3131
require_relative 'rails/delegate'
3232
require_relative 'rails/delegate_allow_blank'
33+
require_relative 'rails/duplicate_ignored_columns'
3334
require_relative 'rails/duration_arithmetic'
3435
require_relative 'rails/dynamic_find_by'
3536
require_relative 'rails/eager_evaluation_log_message'
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::Rails::DuplicateIgnoredColumns, :config do
4+
it 'registers an offense when setting `ignored_columns` twice' do
5+
expect_offense(<<~RUBY)
6+
class User < ActiveRecord::Base
7+
self.ignored_columns = [:one]
8+
self.ignored_columns = [:two]
9+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This assignment to `ignored_columns` overwrites previous ones.
10+
end
11+
RUBY
12+
end
13+
14+
it 'registers an offense when setting `ignored_columns` after appending' do
15+
expect_offense(<<~RUBY)
16+
class User < ActiveRecord::Base
17+
self.ignored_columns += [:one]
18+
self.ignored_columns = [:two]
19+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This assignment to `ignored_columns` overwrites previous ones.
20+
end
21+
RUBY
22+
end
23+
24+
it 'does not register an offense when using `ignored_columns` once' do
25+
expect_no_offenses(<<~RUBY)
26+
class User < ActiveRecord::Base
27+
self.ignored_columns = [:one]
28+
end
29+
RUBY
30+
end
31+
32+
it 'does not register an offense when setting `ignored_columns` and then appending' do
33+
expect_no_offenses(<<~RUBY)
34+
class User < ActiveRecord::Base
35+
self.ignored_columns = [:one]
36+
self.ignored_columns += [:two]
37+
end
38+
RUBY
39+
end
40+
end

0 commit comments

Comments
 (0)