rubocop-rails 2.28.0 → 2.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/config/default.yml +18 -0
- data/lib/rubocop/cop/mixin/index_method.rb +12 -5
- data/lib/rubocop/cop/mixin/migrations_helper.rb +0 -29
- data/lib/rubocop/cop/mixin/routes_helper.rb +20 -0
- data/lib/rubocop/cop/rails/add_column_index.rb +1 -1
- data/lib/rubocop/cop/rails/bulk_change_table.rb +1 -1
- data/lib/rubocop/cop/rails/dangerous_column_names.rb +1 -1
- data/lib/rubocop/cop/rails/http_positional_arguments.rb +7 -0
- data/lib/rubocop/cop/rails/index_by.rb +28 -12
- data/lib/rubocop/cop/rails/index_with.rb +28 -12
- data/lib/rubocop/cop/rails/match_route.rb +1 -9
- data/lib/rubocop/cop/rails/migration_class_name.rb +1 -1
- data/lib/rubocop/cop/rails/multiple_route_paths.rb +50 -0
- data/lib/rubocop/cop/rails/not_null_column.rb +6 -3
- data/lib/rubocop/cop/rails/reversible_migration.rb +4 -2
- data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -1
- data/lib/rubocop/cop/rails/schema_comment.rb +1 -1
- data/lib/rubocop/cop/rails/strong_parameters_expect.rb +104 -0
- data/lib/rubocop/cop/rails/three_state_boolean_column.rb +1 -1
- data/lib/rubocop/cop/rails/time_zone.rb +10 -6
- data/lib/rubocop/cop/rails_cops.rb +3 -0
- data/lib/rubocop/rails/migration_file_skippable.rb +54 -0
- data/lib/rubocop/rails/version.rb +1 -1
- data/lib/rubocop/rails.rb +0 -1
- data/lib/rubocop-rails.rb +3 -0
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 210e46df0db68aeef5761f3afeeb86d62a52015be55190d3e6e1fd65368721be
|
4
|
+
data.tar.gz: 7ff2ef268227cf39cb23b0479a8cf19c4ecc2acdf62c18f8e1766756e5965119
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c84c5690318920b054525a7fc21ca4e0f067a2093757f7ff8182d429587c94898ba1ea1160893fe29e9a8ef9427f6cc076f613f283b5b857da0529fea7654a47
|
7
|
+
data.tar.gz: ca501a5661bcebf2a6769a8cba620c637872e17023ac19fe8f6415b5ff4305d735ead0d24c7ffaee46f24c6cbeb466fcffeebdfb9cd96836211ab446643fc2a7
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -90,7 +90,7 @@ When `MigratedSchemaVersion: '20241225000000'` is set, migration files lower tha
|
|
90
90
|
For example, to ignore db/migrate/20241225000000_create_articles.rb and earlier migrations you would configure it the following way:
|
91
91
|
|
92
92
|
```yaml
|
93
|
-
AllCops
|
93
|
+
AllCops:
|
94
94
|
MigratedSchemaVersion: '20241225000000'
|
95
95
|
```
|
96
96
|
|
data/config/default.yml
CHANGED
@@ -698,6 +698,15 @@ Rails/MigrationClassName:
|
|
698
698
|
Include:
|
699
699
|
- db/**/*.rb
|
700
700
|
|
701
|
+
Rails/MultipleRoutePaths:
|
702
|
+
Description: 'Checks for mapping a route with multiple paths, which is deprecated and will be removed in Rails 8.1.'
|
703
|
+
Enabled: pending
|
704
|
+
Severity: warning
|
705
|
+
VersionAdded: '2.29'
|
706
|
+
Include:
|
707
|
+
- config/routes.rb
|
708
|
+
- config/routes/**/*.rb
|
709
|
+
|
701
710
|
Rails/NegateInclude:
|
702
711
|
Description: 'Prefer `collection.exclude?(obj)` over `!collection.include?(obj)`.'
|
703
712
|
StyleGuide: 'https://rails.rubystyle.guide#exclude'
|
@@ -1072,6 +1081,15 @@ Rails/StripHeredoc:
|
|
1072
1081
|
Enabled: pending
|
1073
1082
|
VersionAdded: '2.15'
|
1074
1083
|
|
1084
|
+
Rails/StrongParametersExpect:
|
1085
|
+
Description: 'Enforces the use of `ActionController::Parameters#expect` as a method for strong parameter handling.'
|
1086
|
+
Reference: 'https://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-expect'
|
1087
|
+
Enabled: pending
|
1088
|
+
Include:
|
1089
|
+
- app/controllers/**/*.rb
|
1090
|
+
SafeAutoCorrect: false
|
1091
|
+
VersionAdded: '2.29'
|
1092
|
+
|
1075
1093
|
Rails/TableNameAssignment:
|
1076
1094
|
Description: >-
|
1077
1095
|
Do not use `self.table_name =`. Use Inflections or `table_name_prefix` instead.
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
module IndexMethod # rubocop:disable Metrics/ModuleLength
|
7
7
|
RESTRICT_ON_SEND = %i[each_with_object to_h map collect []].freeze
|
8
8
|
|
9
|
-
def on_block(node)
|
9
|
+
def on_block(node)
|
10
10
|
on_bad_each_with_object(node) do |*match|
|
11
11
|
handle_possible_offense(node, match, 'each_with_object')
|
12
12
|
end
|
@@ -18,6 +18,8 @@ module RuboCop
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
alias on_numblock on_block
|
22
|
+
|
21
23
|
def on_send(node)
|
22
24
|
on_bad_map_to_h(node) do |*match|
|
23
25
|
handle_possible_offense(node, match, 'map { ... }.to_h')
|
@@ -122,9 +124,9 @@ module RuboCop
|
|
122
124
|
end
|
123
125
|
|
124
126
|
def self.from_map_to_h(node, match)
|
125
|
-
|
126
|
-
|
127
|
-
|
127
|
+
if node.block_literal?
|
128
|
+
strip_trailing_chars = 0
|
129
|
+
else
|
128
130
|
map_range = node.children.first.source_range
|
129
131
|
node_range = node.source_range
|
130
132
|
strip_trailing_chars = node_range.end_pos - map_range.end_pos
|
@@ -153,11 +155,16 @@ module RuboCop
|
|
153
155
|
end
|
154
156
|
|
155
157
|
def set_new_arg_name(transformed_argname, corrector)
|
158
|
+
return if block_node.numblock_type?
|
159
|
+
|
156
160
|
corrector.replace(block_node.arguments, "|#{transformed_argname}|")
|
157
161
|
end
|
158
162
|
|
159
163
|
def set_new_body_expression(transforming_body_expr, corrector)
|
160
|
-
|
164
|
+
body_source = transforming_body_expr.source
|
165
|
+
body_source = "{ #{body_source} }" if transforming_body_expr.hash_type? && !transforming_body_expr.braces?
|
166
|
+
|
167
|
+
corrector.replace(block_node.body, body_source)
|
161
168
|
end
|
162
169
|
end
|
163
170
|
end
|
@@ -21,35 +21,6 @@ module RuboCop
|
|
21
21
|
migration_class?(class_node)
|
22
22
|
end
|
23
23
|
end
|
24
|
-
|
25
|
-
# rubocop:disable Style/DocumentDynamicEvalDefinition
|
26
|
-
%i[on_send on_csend on_block on_numblock on_class].each do |method|
|
27
|
-
class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
|
28
|
-
def #{method}(node)
|
29
|
-
return if already_migrated_file?
|
30
|
-
|
31
|
-
super if method(__method__).super_method
|
32
|
-
end
|
33
|
-
RUBY
|
34
|
-
end
|
35
|
-
# rubocop:enable Style/DocumentDynamicEvalDefinition
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
def already_migrated_file?
|
40
|
-
return false unless migrated_schema_version
|
41
|
-
|
42
|
-
match_data = File.basename(processed_source.file_path).match(/(?<timestamp>\d{14})/)
|
43
|
-
schema_version = match_data['timestamp'] if match_data
|
44
|
-
|
45
|
-
return false unless schema_version
|
46
|
-
|
47
|
-
schema_version <= migrated_schema_version.to_s # Ignore applied migration files.
|
48
|
-
end
|
49
|
-
|
50
|
-
def migrated_schema_version
|
51
|
-
config.for_all_cops.fetch('MigratedSchemaVersion', nil)
|
52
|
-
end
|
53
24
|
end
|
54
25
|
end
|
55
26
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# Common functionality for cops working with routes.
|
6
|
+
module RoutesHelper
|
7
|
+
extend NodePattern::Macros
|
8
|
+
|
9
|
+
HTTP_METHODS = %i[get post put patch delete].freeze
|
10
|
+
|
11
|
+
def_node_matcher :routes_draw?, <<~PATTERN
|
12
|
+
(send (send _ :routes) :draw)
|
13
|
+
PATTERN
|
14
|
+
|
15
|
+
def within_routes?(node)
|
16
|
+
node.each_ancestor(:block).any? { |block| routes_draw?(block.send_node) }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -19,7 +19,7 @@ module RuboCop
|
|
19
19
|
class AddColumnIndex < Base
|
20
20
|
extend AutoCorrector
|
21
21
|
include RangeHelp
|
22
|
-
|
22
|
+
include MigrationsHelper
|
23
23
|
|
24
24
|
MSG = '`add_column` does not accept an `index` key, use `add_index` instead.'
|
25
25
|
RESTRICT_ON_SEND = %i[add_column].freeze
|
@@ -40,6 +40,10 @@ module RuboCop
|
|
40
40
|
(hash (kwsplat _))
|
41
41
|
PATTERN
|
42
42
|
|
43
|
+
def_node_matcher :forwarded_kwrestarg?, <<~PATTERN
|
44
|
+
(hash (forwarded-kwrestarg))
|
45
|
+
PATTERN
|
46
|
+
|
43
47
|
def_node_matcher :include_rack_test_methods?, <<~PATTERN
|
44
48
|
(send nil? :include
|
45
49
|
(const
|
@@ -83,7 +87,9 @@ module RuboCop
|
|
83
87
|
end
|
84
88
|
end
|
85
89
|
|
90
|
+
# rubocop:disable Metrics/CyclomaticComplexity
|
86
91
|
def needs_conversion?(data)
|
92
|
+
return false if data.forwarded_args_type? || forwarded_kwrestarg?(data)
|
87
93
|
return true unless data.hash_type?
|
88
94
|
return false if kwsplat_hash?(data)
|
89
95
|
|
@@ -91,6 +97,7 @@ module RuboCop
|
|
91
97
|
special_keyword_arg?(pair.key) || (format_arg?(pair.key) && data.pairs.one?)
|
92
98
|
end
|
93
99
|
end
|
100
|
+
# rubocop:enable Metrics/CyclomaticComplexity
|
94
101
|
|
95
102
|
def special_keyword_arg?(node)
|
96
103
|
node.sym_type? && KEYWORD_ARGS.include?(node.value)
|
@@ -29,18 +29,28 @@ module RuboCop
|
|
29
29
|
PATTERN
|
30
30
|
|
31
31
|
def_node_matcher :on_bad_to_h, <<~PATTERN
|
32
|
-
|
33
|
-
(
|
34
|
-
|
35
|
-
|
32
|
+
{
|
33
|
+
(block
|
34
|
+
(call _ :to_h)
|
35
|
+
(args (arg $_el))
|
36
|
+
(array $_ (lvar _el)))
|
37
|
+
(numblock
|
38
|
+
(call _ :to_h) $1
|
39
|
+
(array $_ (lvar :_1)))
|
40
|
+
}
|
36
41
|
PATTERN
|
37
42
|
|
38
43
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
39
44
|
(call
|
40
|
-
|
41
|
-
(
|
42
|
-
|
43
|
-
|
45
|
+
{
|
46
|
+
(block
|
47
|
+
(call _ {:map :collect})
|
48
|
+
(args (arg $_el))
|
49
|
+
(array $_ (lvar _el)))
|
50
|
+
(numblock
|
51
|
+
(call _ {:map :collect}) $1
|
52
|
+
(array $_ (lvar :_1)))
|
53
|
+
}
|
44
54
|
:to_h)
|
45
55
|
PATTERN
|
46
56
|
|
@@ -48,10 +58,16 @@ module RuboCop
|
|
48
58
|
(send
|
49
59
|
(const {nil? cbase} :Hash)
|
50
60
|
:[]
|
51
|
-
|
52
|
-
(
|
53
|
-
|
54
|
-
|
61
|
+
{
|
62
|
+
(block
|
63
|
+
(call _ {:map :collect})
|
64
|
+
(args (arg $_el))
|
65
|
+
(array $_ (lvar _el)))
|
66
|
+
(numblock
|
67
|
+
(call _ {:map :collect}) $1
|
68
|
+
(array $_ (lvar :_1)))
|
69
|
+
}
|
70
|
+
)
|
55
71
|
PATTERN
|
56
72
|
|
57
73
|
private
|
@@ -32,18 +32,28 @@ module RuboCop
|
|
32
32
|
PATTERN
|
33
33
|
|
34
34
|
def_node_matcher :on_bad_to_h, <<~PATTERN
|
35
|
-
|
36
|
-
(
|
37
|
-
|
38
|
-
|
35
|
+
{
|
36
|
+
(block
|
37
|
+
(call _ :to_h)
|
38
|
+
(args (arg $_el))
|
39
|
+
(array (lvar _el) $_))
|
40
|
+
(numblock
|
41
|
+
(call _ :to_h) $1
|
42
|
+
(array (lvar :_1) $_))
|
43
|
+
}
|
39
44
|
PATTERN
|
40
45
|
|
41
46
|
def_node_matcher :on_bad_map_to_h, <<~PATTERN
|
42
47
|
(call
|
43
|
-
|
44
|
-
(
|
45
|
-
|
46
|
-
|
48
|
+
{
|
49
|
+
(block
|
50
|
+
(call _ {:map :collect})
|
51
|
+
(args (arg $_el))
|
52
|
+
(array (lvar _el) $_))
|
53
|
+
(numblock
|
54
|
+
(call _ {:map :collect}) $1
|
55
|
+
(array (lvar :_1) $_))
|
56
|
+
}
|
47
57
|
:to_h)
|
48
58
|
PATTERN
|
49
59
|
|
@@ -51,10 +61,16 @@ module RuboCop
|
|
51
61
|
(send
|
52
62
|
(const {nil? cbase} :Hash)
|
53
63
|
:[]
|
54
|
-
|
55
|
-
(
|
56
|
-
|
57
|
-
|
64
|
+
{
|
65
|
+
(block
|
66
|
+
(call _ {:map :collect})
|
67
|
+
(args (arg $_el))
|
68
|
+
(array (lvar _el) $_))
|
69
|
+
(numblock
|
70
|
+
(call _ {:map :collect}) $1
|
71
|
+
(array (lvar :_1) $_))
|
72
|
+
}
|
73
|
+
)
|
58
74
|
PATTERN
|
59
75
|
|
60
76
|
private
|
@@ -21,11 +21,11 @@ module RuboCop
|
|
21
21
|
# match 'photos/:id', to: 'photos#show', via: :all
|
22
22
|
#
|
23
23
|
class MatchRoute < Base
|
24
|
+
include RoutesHelper
|
24
25
|
extend AutoCorrector
|
25
26
|
|
26
27
|
MSG = 'Use `%<http_method>s` instead of `match` to define a route.'
|
27
28
|
RESTRICT_ON_SEND = %i[match].freeze
|
28
|
-
HTTP_METHODS = %i[get post put patch delete].freeze
|
29
29
|
|
30
30
|
def_node_matcher :match_method_call?, <<~PATTERN
|
31
31
|
(send nil? :match $_ $(hash ...) ?)
|
@@ -60,14 +60,6 @@ module RuboCop
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
-
def_node_matcher :routes_draw?, <<~PATTERN
|
64
|
-
(send (send _ :routes) :draw)
|
65
|
-
PATTERN
|
66
|
-
|
67
|
-
def within_routes?(node)
|
68
|
-
node.each_ancestor(:block).any? { |a| routes_draw?(a.send_node) }
|
69
|
-
end
|
70
|
-
|
71
63
|
def extract_via(node)
|
72
64
|
via_pair = via_pair(node)
|
73
65
|
return %i[get] unless via_pair
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks for mapping a route with multiple paths, which is deprecated and will be removed in Rails 8.1.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
#
|
10
|
+
# # bad
|
11
|
+
# get '/users', '/other_path', to: 'users#index'
|
12
|
+
#
|
13
|
+
# # good
|
14
|
+
# get '/users', to: 'users#index'
|
15
|
+
# get '/other_path', to: 'users#index'
|
16
|
+
#
|
17
|
+
class MultipleRoutePaths < Base
|
18
|
+
include RoutesHelper
|
19
|
+
extend AutoCorrector
|
20
|
+
|
21
|
+
MSG = 'Use separate routes instead of combining multiple route paths in a single route.'
|
22
|
+
RESTRICT_ON_SEND = HTTP_METHODS
|
23
|
+
|
24
|
+
IGNORED_ARGUMENT_TYPES = %i[array hash].freeze
|
25
|
+
|
26
|
+
def on_send(node)
|
27
|
+
return unless within_routes?(node)
|
28
|
+
|
29
|
+
route_paths = node.arguments.reject { |argument| IGNORED_ARGUMENT_TYPES.include?(argument.type) }
|
30
|
+
return if route_paths.count < 2
|
31
|
+
|
32
|
+
add_offense(node) do |corrector|
|
33
|
+
corrector.replace(node, migrate_to_multiple_routes(node, route_paths))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def migrate_to_multiple_routes(node, route_paths)
|
40
|
+
rest = route_paths.last.source_range.end.join(node.source_range.end).source
|
41
|
+
indentation = ' ' * node.source_range.column
|
42
|
+
|
43
|
+
route_paths.map do |route_path|
|
44
|
+
"#{node.method_name} #{route_path.source}#{rest}"
|
45
|
+
end.join("\n#{indentation}")
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -41,11 +41,14 @@ module RuboCop
|
|
41
41
|
# change_column_null :products, :category_id, false
|
42
42
|
class NotNullColumn < Base
|
43
43
|
include DatabaseTypeResolvable
|
44
|
-
|
44
|
+
include MigrationsHelper
|
45
45
|
|
46
46
|
MSG = 'Do not add a NOT NULL column without a default value.'
|
47
47
|
RESTRICT_ON_SEND = %i[add_column add_reference].freeze
|
48
48
|
|
49
|
+
VIRTUAL_TYPE_VALUES = [:virtual, 'virtual'].freeze
|
50
|
+
TEXT_TYPE_VALUES = [:text, 'text'].freeze
|
51
|
+
|
49
52
|
def_node_matcher :add_not_null_column?, <<~PATTERN
|
50
53
|
(send nil? :add_column _ _ $_ (hash $...))
|
51
54
|
PATTERN
|
@@ -92,8 +95,8 @@ module RuboCop
|
|
92
95
|
|
93
96
|
def check_column(type, pairs)
|
94
97
|
if type.respond_to?(:value)
|
95
|
-
return if
|
96
|
-
return if (type.value
|
98
|
+
return if VIRTUAL_TYPE_VALUES.include?(type.value)
|
99
|
+
return if TEXT_TYPE_VALUES.include?(type.value) && database == MYSQL
|
97
100
|
end
|
98
101
|
|
99
102
|
check_pairs(pairs)
|
@@ -151,7 +151,7 @@ module RuboCop
|
|
151
151
|
# remove_index :users, column: :email
|
152
152
|
# end
|
153
153
|
class ReversibleMigration < Base
|
154
|
-
|
154
|
+
include MigrationsHelper
|
155
155
|
|
156
156
|
MSG = '%<action>s is not reversible.'
|
157
157
|
|
@@ -215,8 +215,10 @@ module RuboCop
|
|
215
215
|
end
|
216
216
|
|
217
217
|
def check_drop_table_node(node)
|
218
|
+
return unless (last_argument = node.last_argument)
|
219
|
+
|
218
220
|
drop_table_call(node) do
|
219
|
-
unless node.parent.block_type? ||
|
221
|
+
unless node.parent.block_type? || last_argument.block_pass_type?
|
220
222
|
add_offense(node, message: format(MSG, action: 'drop_table(without block)'))
|
221
223
|
end
|
222
224
|
end
|
@@ -23,7 +23,7 @@ module RuboCop
|
|
23
23
|
#
|
24
24
|
class SchemaComment < Base
|
25
25
|
include ActiveRecordMigrationsHelper
|
26
|
-
|
26
|
+
include MigrationsHelper
|
27
27
|
|
28
28
|
COLUMN_MSG = 'New database column without `comment`.'
|
29
29
|
TABLE_MSG = 'New database table without `comment`.'
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Enforces the use of `ActionController::Parameters#expect` as a method for strong parameter handling.
|
7
|
+
#
|
8
|
+
# @safety
|
9
|
+
# This cop's autocorrection is considered unsafe because there are cases where the HTTP status may change
|
10
|
+
# from 500 to 400 when handling invalid parameters. This change, however, reflects an intentional
|
11
|
+
# incompatibility introduced for valid reasons by the `expect` method, which aligns better with
|
12
|
+
# strong parameter conventions.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
#
|
16
|
+
# # bad
|
17
|
+
# params.require(:user).permit(:name, :age)
|
18
|
+
# params.permit(user: [:name, :age]).require(:user)
|
19
|
+
#
|
20
|
+
# # good
|
21
|
+
# params.expect(user: [:name, :age])
|
22
|
+
#
|
23
|
+
class StrongParametersExpect < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
extend TargetRailsVersion
|
26
|
+
|
27
|
+
MSG = 'Use `%<prefer>s` instead.'
|
28
|
+
RESTRICT_ON_SEND = %i[require permit].freeze
|
29
|
+
|
30
|
+
minimum_target_rails_version 8.0
|
31
|
+
|
32
|
+
def_node_matcher :params_require_permit, <<~PATTERN
|
33
|
+
$(call
|
34
|
+
$(call
|
35
|
+
(send nil? :params) :require _) :permit ...)
|
36
|
+
PATTERN
|
37
|
+
|
38
|
+
def_node_matcher :params_permit_require, <<~PATTERN
|
39
|
+
$(call
|
40
|
+
$(call
|
41
|
+
(send nil? :params) :permit (hash (pair _require_param_name _ )))
|
42
|
+
:require _require_param_name)
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
46
|
+
def on_send(node)
|
47
|
+
return if part_of_ignored_node?(node)
|
48
|
+
|
49
|
+
if (permit_method, require_method = params_require_permit(node))
|
50
|
+
range = offense_range(require_method, node)
|
51
|
+
prefer = expect_method(require_method, permit_method)
|
52
|
+
replace_argument = true
|
53
|
+
elsif (require_method, permit_method = params_permit_require(node))
|
54
|
+
range = offense_range(permit_method, node)
|
55
|
+
prefer = "expect(#{permit_method.arguments.map(&:source).join(', ')})"
|
56
|
+
replace_argument = false
|
57
|
+
else
|
58
|
+
return
|
59
|
+
end
|
60
|
+
|
61
|
+
add_offense(range, message: format(MSG, prefer: prefer)) do |corrector|
|
62
|
+
corrector.remove(require_method.loc.dot.join(require_method.source_range.end))
|
63
|
+
corrector.replace(permit_method.loc.selector, 'expect')
|
64
|
+
if replace_argument
|
65
|
+
corrector.insert_before(permit_method.first_argument, "#{require_key(require_method)}[")
|
66
|
+
corrector.insert_after(permit_method.last_argument, ']')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
ignore_node(node)
|
71
|
+
end
|
72
|
+
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
73
|
+
alias on_csend on_send
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def offense_range(method_node, node)
|
78
|
+
method_node.loc.selector.join(node.source_range.end)
|
79
|
+
end
|
80
|
+
|
81
|
+
def expect_method(require_method, permit_method)
|
82
|
+
require_key = require_key(require_method)
|
83
|
+
permit_args = permit_method.arguments.map(&:source).join(', ')
|
84
|
+
|
85
|
+
arguments = "#{require_key}[#{permit_args}]"
|
86
|
+
|
87
|
+
"expect(#{arguments})"
|
88
|
+
end
|
89
|
+
|
90
|
+
def require_key(require_method)
|
91
|
+
if (first_argument = require_method.first_argument).respond_to?(:value)
|
92
|
+
require_arg = first_argument.value
|
93
|
+
separator = ': '
|
94
|
+
else
|
95
|
+
require_arg = first_argument.source
|
96
|
+
separator = ' => '
|
97
|
+
end
|
98
|
+
|
99
|
+
"#{require_arg}#{separator}"
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -18,7 +18,7 @@ module RuboCop
|
|
18
18
|
# t.boolean :active, default: true, null: false
|
19
19
|
#
|
20
20
|
class ThreeStateBooleanColumn < Base
|
21
|
-
|
21
|
+
include MigrationsHelper
|
22
22
|
|
23
23
|
MSG = 'Boolean columns should always have a default value and a `NOT NULL` constraint.'
|
24
24
|
RESTRICT_ON_SEND = %i[add_column column boolean].freeze
|
@@ -97,11 +97,9 @@ module RuboCop
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def autocorrect_time_new(node, corrector)
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
corrector.replace(node.loc.selector, 'now')
|
104
|
-
end
|
100
|
+
replacement = replacement(node)
|
101
|
+
|
102
|
+
corrector.replace(node.loc.selector, replacement)
|
105
103
|
end
|
106
104
|
|
107
105
|
# remove redundant `.in_time_zone` from `Time.zone.now.in_time_zone`
|
@@ -183,7 +181,7 @@ module RuboCop
|
|
183
181
|
|
184
182
|
def safe_method(method_name, node)
|
185
183
|
if %w[new current].include?(method_name)
|
186
|
-
node
|
184
|
+
replacement(node)
|
187
185
|
else
|
188
186
|
method_name
|
189
187
|
end
|
@@ -259,6 +257,12 @@ module RuboCop
|
|
259
257
|
pair.key.sym_type? && pair.key.value == :in && !pair.value.nil_type?
|
260
258
|
end
|
261
259
|
end
|
260
|
+
|
261
|
+
def replacement(node)
|
262
|
+
return 'now' unless node.arguments?
|
263
|
+
|
264
|
+
node.first_argument.str_type? ? 'parse' : 'local'
|
265
|
+
end
|
262
266
|
end
|
263
267
|
end
|
264
268
|
end
|
@@ -7,9 +7,11 @@ require_relative 'mixin/database_type_resolvable'
|
|
7
7
|
require_relative 'mixin/enforce_superclass'
|
8
8
|
require_relative 'mixin/index_method'
|
9
9
|
require_relative 'mixin/migrations_helper'
|
10
|
+
require_relative 'mixin/routes_helper'
|
10
11
|
require_relative 'mixin/target_rails_version'
|
11
12
|
|
12
13
|
require_relative 'rails/action_controller_flash_before_render'
|
14
|
+
require_relative 'rails/strong_parameters_expect'
|
13
15
|
require_relative 'rails/action_controller_test_case'
|
14
16
|
require_relative 'rails/action_filter'
|
15
17
|
require_relative 'rails/action_order'
|
@@ -77,6 +79,7 @@ require_relative 'rails/link_to_blank'
|
|
77
79
|
require_relative 'rails/mailer_name'
|
78
80
|
require_relative 'rails/match_route'
|
79
81
|
require_relative 'rails/migration_class_name'
|
82
|
+
require_relative 'rails/multiple_route_paths'
|
80
83
|
require_relative 'rails/negate_include'
|
81
84
|
require_relative 'rails/not_null_column'
|
82
85
|
require_relative 'rails/order_by_id'
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Rails
|
5
|
+
# This module allows cops to detect and ignore files that have already been migrated
|
6
|
+
# by leveraging the `AllCops: MigratedSchemaVersion` configuration.
|
7
|
+
#
|
8
|
+
# [source,yaml]
|
9
|
+
# -----
|
10
|
+
# AllCops:
|
11
|
+
# MigratedSchemaVersion: '20241225000000'
|
12
|
+
# -----
|
13
|
+
#
|
14
|
+
# When applied to cops, it overrides the `add_global_offense` and `add_offense` methods,
|
15
|
+
# ensuring that cops skip processing if the file is determined to be a migrated file
|
16
|
+
# based on the schema version.
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
module MigrationFileSkippable
|
20
|
+
def add_global_offense(message = nil, severity: nil)
|
21
|
+
return if already_migrated_file?
|
22
|
+
|
23
|
+
super if method(__method__).super_method
|
24
|
+
end
|
25
|
+
|
26
|
+
def add_offense(node_or_range, message: nil, severity: nil, &block)
|
27
|
+
return if already_migrated_file?
|
28
|
+
|
29
|
+
super if method(__method__).super_method
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.apply_to_cops!
|
33
|
+
RuboCop::Cop::Registry.all.each { |cop| cop.prepend(MigrationFileSkippable) }
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def already_migrated_file?
|
39
|
+
return false unless migrated_schema_version
|
40
|
+
|
41
|
+
match_data = File.basename(processed_source.file_path).match(/(?<timestamp>\d{14})/)
|
42
|
+
schema_version = match_data['timestamp'] if match_data
|
43
|
+
|
44
|
+
return false unless schema_version
|
45
|
+
|
46
|
+
schema_version <= migrated_schema_version.to_s # Ignore applied migration files.
|
47
|
+
end
|
48
|
+
|
49
|
+
def migrated_schema_version
|
50
|
+
@migrated_schema_version ||= config.for_all_cops.fetch('MigratedSchemaVersion', nil)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
data/lib/rubocop/rails.rb
CHANGED
@@ -5,7 +5,6 @@ module RuboCop
|
|
5
5
|
module Rails
|
6
6
|
PROJECT_ROOT = Pathname.new(__dir__).parent.parent.expand_path.freeze
|
7
7
|
CONFIG_DEFAULT = PROJECT_ROOT.join('config', 'default.yml').freeze
|
8
|
-
CONFIG = YAML.safe_load(CONFIG_DEFAULT.read, permitted_classes: [Regexp, Symbol]).freeze
|
9
8
|
|
10
9
|
private_constant(:CONFIG_DEFAULT, :PROJECT_ROOT)
|
11
10
|
|
data/lib/rubocop-rails.rb
CHANGED
@@ -15,6 +15,9 @@ RuboCop::Rails::Inject.defaults!
|
|
15
15
|
|
16
16
|
require_relative 'rubocop/cop/rails_cops'
|
17
17
|
|
18
|
+
require_relative 'rubocop/rails/migration_file_skippable'
|
19
|
+
RuboCop::Rails::MigrationFileSkippable.apply_to_cops!
|
20
|
+
|
18
21
|
RuboCop::Cop::Style::HashExcept.minimum_target_ruby_version(2.0)
|
19
22
|
|
20
23
|
RuboCop::Cop::Style::InverseMethods.singleton_class.prepend(
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubocop-rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.29.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
- Yuji Nakayama
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2025-01-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -101,6 +101,7 @@ files:
|
|
101
101
|
- lib/rubocop/cop/mixin/enforce_superclass.rb
|
102
102
|
- lib/rubocop/cop/mixin/index_method.rb
|
103
103
|
- lib/rubocop/cop/mixin/migrations_helper.rb
|
104
|
+
- lib/rubocop/cop/mixin/routes_helper.rb
|
104
105
|
- lib/rubocop/cop/mixin/target_rails_version.rb
|
105
106
|
- lib/rubocop/cop/rails/action_controller_flash_before_render.rb
|
106
107
|
- lib/rubocop/cop/rails/action_controller_test_case.rb
|
@@ -170,6 +171,7 @@ files:
|
|
170
171
|
- lib/rubocop/cop/rails/mailer_name.rb
|
171
172
|
- lib/rubocop/cop/rails/match_route.rb
|
172
173
|
- lib/rubocop/cop/rails/migration_class_name.rb
|
174
|
+
- lib/rubocop/cop/rails/multiple_route_paths.rb
|
173
175
|
- lib/rubocop/cop/rails/negate_include.rb
|
174
176
|
- lib/rubocop/cop/rails/not_null_column.rb
|
175
177
|
- lib/rubocop/cop/rails/order_by_id.rb
|
@@ -213,6 +215,7 @@ files:
|
|
213
215
|
- lib/rubocop/cop/rails/skips_model_validations.rb
|
214
216
|
- lib/rubocop/cop/rails/squished_sql_heredocs.rb
|
215
217
|
- lib/rubocop/cop/rails/strip_heredoc.rb
|
218
|
+
- lib/rubocop/cop/rails/strong_parameters_expect.rb
|
216
219
|
- lib/rubocop/cop/rails/table_name_assignment.rb
|
217
220
|
- lib/rubocop/cop/rails/three_state_boolean_column.rb
|
218
221
|
- lib/rubocop/cop/rails/time_zone.rb
|
@@ -236,6 +239,7 @@ files:
|
|
236
239
|
- lib/rubocop/cop/rails_cops.rb
|
237
240
|
- lib/rubocop/rails.rb
|
238
241
|
- lib/rubocop/rails/inject.rb
|
242
|
+
- lib/rubocop/rails/migration_file_skippable.rb
|
239
243
|
- lib/rubocop/rails/schema_loader.rb
|
240
244
|
- lib/rubocop/rails/schema_loader/schema.rb
|
241
245
|
- lib/rubocop/rails/version.rb
|
@@ -246,7 +250,7 @@ metadata:
|
|
246
250
|
homepage_uri: https://docs.rubocop.org/rubocop-rails/
|
247
251
|
changelog_uri: https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md
|
248
252
|
source_code_uri: https://github.com/rubocop/rubocop-rails/
|
249
|
-
documentation_uri: https://docs.rubocop.org/rubocop-rails/2.
|
253
|
+
documentation_uri: https://docs.rubocop.org/rubocop-rails/2.29/
|
250
254
|
bug_tracker_uri: https://github.com/rubocop/rubocop-rails/issues
|
251
255
|
rubygems_mfa_required: 'true'
|
252
256
|
rdoc_options: []
|
@@ -263,7 +267,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
263
267
|
- !ruby/object:Gem::Version
|
264
268
|
version: '0'
|
265
269
|
requirements: []
|
266
|
-
rubygems_version: 3.6.
|
270
|
+
rubygems_version: 3.6.2
|
267
271
|
specification_version: 4
|
268
272
|
summary: Automatic Rails code style checking tool.
|
269
273
|
test_files: []
|