1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
|
# frozen_string_literal: true
module RuboCop
module Cop
# Cop that flags the usage of `ActiveRecord::Base.ignored_columns=` directly
#
# @example
# # bad
# class User < ApplicationRecord
# self.ignored_columns = [:name]
# self.ignored_columns += [:full_name]
# end
#
# # good
# class User < ApplicationRecord
# include IgnorableColumns
#
# ignore_column :name, remove_after: '2023-05-22', remove_with: '16.0'
# ignore_column :full_name, remove_after: '2023-05-22', remove_with: '16.0'
# end
class IgnoredColumns < RuboCop::Cop::Base
USE_CONCERN_ADD_MSG = 'Use `IgnoredColumns` concern instead of adding to `self.ignored_columns`.'
USE_CONCERN_SET_MSG = 'Use `IgnoredColumns` concern instead of setting `self.ignored_columns`.'
WRONG_MODEL_MSG = <<~MSG
If the model exists in CE and EE, the column has to be ignored
in the CE model. If the model only exists in EE, then it has to be added there.
MSG
RESTRICT_ON_SEND = %i[ignored_columns ignored_columns= ignore_column ignore_columns].freeze
def_node_matcher :ignored_columns_add?, <<~PATTERN
(send (self) :ignored_columns)
PATTERN
def_node_matcher :ignored_columns_set?, <<~PATTERN
(send (self) :ignored_columns= ...)
PATTERN
def_node_matcher :using_ignore_columns?, <<~PATTERN
(send nil? {:ignore_columns :ignore_column}...)
PATTERN
def on_send(node)
if ignored_columns_add?(node)
add_offense(node.loc.selector, message: USE_CONCERN_ADD_MSG)
end
if ignored_columns_set?(node)
add_offense(node.loc.selector, message: USE_CONCERN_SET_MSG)
end
if using_ignore_columns?(node) && used_in_wrong_model?
add_offense(node, message: WRONG_MODEL_MSG)
end
end
private
def used_in_wrong_model?
file_path = processed_source.file_path
ee_model?(file_path) && ce_model_exists?(file_path)
end
def ee_model?(path)
path.include?(ee_directory)
end
def ee_directory
File.join(rails_root, 'ee')
end
def rails_root
File.expand_path('../..', __dir__)
end
def ce_model_exists?(path)
File.exist?(path.gsub(%r{/ee/}, '/'))
end
end
end
end
|