Skip to content

Commit 6897bb0

Browse files
committed
Add cop for checking assingments to ignored_columns
Setting `ignored_columns` may overwrite previous assignments, and that is problematic because it can un-ignore a previously set column list. Since it is not a problem to have a duplicate column in the list, simply recommend always appending.
1 parent 210c368 commit 6897bb0

File tree

5 files changed

+124
-0
lines changed

5 files changed

+124
-0
lines changed

changelog/new_set_ignored_columns.md

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/SetIgnoredColumns` cop. ([@fsateler][])

config/default.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,12 @@ Rails/ScopeArgs:
764764
Include:
765765
- app/models/**/*.rb
766766

767+
Rails/SetIgnoredColumns:
768+
Description: 'Looks for assignments of `ignored_columns` that override previous assignments.'
769+
Enabled: pending
770+
SafeAutoCorrect: false
771+
VersionAdded: '<<next>>'
772+
767773
Rails/ShortI18n:
768774
Description: 'Use the short form of the I18n methods: `t` instead of `translate` and `l` instead of `localize`.'
769775
StyleGuide: 'https://rails.rubystyle.guide/#short-i18n'
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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 may override previous
7+
# assignments.
8+
#
9+
# Overwriting previous assignments is usually a mistake, since it will
10+
# un-ignore the first set of columns. Since duplicate column names is not
11+
# a problem, it is better to simply append to the list.
12+
#
13+
# @example
14+
#
15+
# # bad
16+
# class User < ActiveRecord::Base
17+
# self.ignored_columns = [:one]
18+
# end
19+
#
20+
# # bad
21+
# class User < ActiveRecord::Base
22+
# self.ignored_columns = [:one, :two]
23+
# end
24+
#
25+
# # good
26+
# class User < ActiveRecord::Base
27+
# self.ignored_columns += [:one, :two]
28+
# end
29+
#
30+
# # good
31+
# class User < ActiveRecord::Base
32+
# self.ignored_columns += [:one]
33+
# self.ignored_columns += [:two]
34+
# end
35+
#
36+
class SetIgnoredColumns < Base
37+
extend AutoCorrector
38+
MSG = 'This assignment to `ignored_columns` may overwrite previous ones.'
39+
40+
def_node_matcher :ignored_columns_assign, <<-PATTERN
41+
(send self :ignored_columns= ...)
42+
PATTERN
43+
44+
def on_send(node)
45+
ignored_columns_assign(node) do
46+
add_offense(node) do |corrector|
47+
corrector.replace(node.loc.operator, '+=')
48+
end
49+
end
50+
end
51+
end
52+
end
53+
end
54+
end

lib/rubocop/cop/rails_cops.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
require_relative 'rails/save_bang'
9393
require_relative 'rails/schema_comment'
9494
require_relative 'rails/scope_args'
95+
require_relative 'rails/set_ignored_columns'
9596
require_relative 'rails/short_i18n'
9697
require_relative 'rails/skips_model_validations'
9798
require_relative 'rails/squished_sql_heredocs'
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# frozen_string_literal: true
2+
3+
RSpec.describe RuboCop::Cop::Rails::SetIgnoredColumns, :config do
4+
it 'registers an offense when using `ignored_columns` once' do
5+
expect_offense(<<~RUBY)
6+
class User < ActiveRecord::Base
7+
self.ignored_columns = [:one]
8+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This assignment to `ignored_columns` may overwrite previous ones.
9+
end
10+
RUBY
11+
12+
expect_correction(<<~RUBY)
13+
class User < ActiveRecord::Base
14+
self.ignored_columns += [:one]
15+
end
16+
RUBY
17+
end
18+
19+
it 'registers an offense when setting `ignored_columns` twice' do
20+
expect_offense(<<~RUBY)
21+
class User < ActiveRecord::Base
22+
self.ignored_columns = [:one]
23+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This assignment to `ignored_columns` may overwrite previous ones.
24+
self.ignored_columns = [:two]
25+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This assignment to `ignored_columns` may overwrite previous ones.
26+
end
27+
RUBY
28+
29+
expect_correction(<<~RUBY)
30+
class User < ActiveRecord::Base
31+
self.ignored_columns += [:one]
32+
self.ignored_columns += [:two]
33+
end
34+
RUBY
35+
end
36+
37+
it 'registers an offense when setting `ignored_columns` after appending' do
38+
expect_offense(<<~RUBY)
39+
class User < ActiveRecord::Base
40+
self.ignored_columns += [:one]
41+
self.ignored_columns = [:two]
42+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This assignment to `ignored_columns` may overwrite previous ones.
43+
end
44+
RUBY
45+
46+
expect_correction(<<~RUBY)
47+
class User < ActiveRecord::Base
48+
self.ignored_columns += [:one]
49+
self.ignored_columns += [:two]
50+
end
51+
RUBY
52+
end
53+
54+
it 'does not register an offense when appending to `ignored_columns` and then appending' do
55+
expect_no_offenses(<<~RUBY)
56+
class User < ActiveRecord::Base
57+
self.ignored_columns += [:one]
58+
self.ignored_columns += [:two]
59+
end
60+
RUBY
61+
end
62+
end

0 commit comments

Comments
 (0)