rubocop-rails 2.13.2 → 2.14.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/default.yml +69 -2
- data/lib/rubocop/cop/mixin/class_send_node_helper.rb +20 -0
- data/lib/rubocop/cop/rails/action_controller_test_case.rb +47 -0
- data/lib/rubocop/cop/rails/after_commit_override.rb +2 -12
- data/lib/rubocop/cop/rails/bulk_change_table.rb +20 -6
- data/lib/rubocop/cop/rails/compact_blank.rb +13 -5
- data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +108 -0
- data/lib/rubocop/cop/rails/duplicate_association.rb +56 -0
- data/lib/rubocop/cop/rails/duplicate_scope.rb +46 -0
- data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +94 -0
- data/lib/rubocop/cop/rails/i18n_locale_texts.rb +110 -0
- data/lib/rubocop/cop/rails/migration_class_name.rb +71 -0
- data/lib/rubocop/cop/rails/pluck.rb +15 -7
- data/lib/rubocop/cop/rails/table_name_assignment.rb +44 -0
- data/lib/rubocop/cop/rails/transaction_exit_statement.rb +77 -0
- data/lib/rubocop/cop/rails_cops.rb +10 -0
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +13 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c8ac7c4db62e8518ff9316e0a3ac8919ac440eaf9ba84eacf883cf902fffca7a
|
4
|
+
data.tar.gz: 8a4b1e0c90e4ea2b8ba06352bc7525b56c4d95af49e618fb77a6bfd4bc5dafdb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb91cd3a6e867309efc10717843f0994a743bf1a4eb65b058863340d48904624377e88bb1b38cc0e091b9c2d5c676901987c1a31c3f6f50e5923863feb11f900
|
7
|
+
data.tar.gz: fe8208f3d1962a6c5400c74ab174b7b5b8c88641a564616f155cf90d91915ea85b6de031dc99a9737eb93fe3c39d878507f52d7f0aed85480142f630d0a082f5
|
data/config/default.yml
CHANGED
@@ -7,7 +7,9 @@ inherit_mode:
|
|
7
7
|
AllCops:
|
8
8
|
Exclude:
|
9
9
|
- bin/*
|
10
|
-
|
10
|
+
# Exclude db/schema.rb and db/[CONFIGURATION_NAMESPACE]_schema.rb by default.
|
11
|
+
# See: https://guides.rubyonrails.org/active_record_multiple_databases.html#setting-up-your-application
|
12
|
+
- db/*schema.rb
|
11
13
|
# What version of Rails is the inspected code using? If a value is specified
|
12
14
|
# for TargetRailsVersion then it is used. Acceptable values are specified
|
13
15
|
# as a float (i.e. 5.1); the patch version of Rails should not be included.
|
@@ -38,6 +40,16 @@ Lint/NumberConversion:
|
|
38
40
|
- fortnights
|
39
41
|
- in_milliseconds
|
40
42
|
|
43
|
+
Rails/ActionControllerTestCase:
|
44
|
+
Description: 'Use `ActionDispatch::IntegrationTest` instead of `ActionController::TestCase`.'
|
45
|
+
StyleGuide: 'https://rails.rubystyle.guide/#integration-testing'
|
46
|
+
Reference: 'https://api.rubyonrails.org/classes/ActionController/TestCase.html'
|
47
|
+
Enabled: 'pending'
|
48
|
+
SafeAutocorrect: false
|
49
|
+
VersionAdded: '2.14'
|
50
|
+
Include:
|
51
|
+
- '**/test/**/*.rb'
|
52
|
+
|
41
53
|
Rails/ActionFilter:
|
42
54
|
Description: 'Enforces consistent use of action filter methods.'
|
43
55
|
Enabled: true
|
@@ -195,9 +207,12 @@ Rails/ContentTag:
|
|
195
207
|
Enabled: true
|
196
208
|
VersionAdded: '2.6'
|
197
209
|
VersionChanged: '2.12'
|
198
|
-
# This `Exclude` config prevents false positives for `tag` calls to `has_one: tag
|
210
|
+
# This `Exclude` config prevents false positives for `tag` calls to `has_one: tag` and Puma configuration:
|
211
|
+
# https://puma.io/puma/Puma/DSL.html#tag-instance_method
|
212
|
+
# No helpers are used in normal models and configs.
|
199
213
|
Exclude:
|
200
214
|
- app/models/**/*.rb
|
215
|
+
- config/**/*.rb
|
201
216
|
|
202
217
|
Rails/CreateTableWithTimestamps:
|
203
218
|
Description: >-
|
@@ -251,6 +266,22 @@ Rails/DelegateAllowBlank:
|
|
251
266
|
Enabled: true
|
252
267
|
VersionAdded: '0.44'
|
253
268
|
|
269
|
+
Rails/DeprecatedActiveModelErrorsMethods:
|
270
|
+
Description: 'Avoid manipulating ActiveModel errors hash directly.'
|
271
|
+
Enabled: pending
|
272
|
+
Safe: false
|
273
|
+
VersionAdded: '2.14'
|
274
|
+
|
275
|
+
Rails/DuplicateAssociation:
|
276
|
+
Description: "Don't repeat associations in a model."
|
277
|
+
Enabled: pending
|
278
|
+
VersionAdded: '2.14'
|
279
|
+
|
280
|
+
Rails/DuplicateScope:
|
281
|
+
Description: 'Multiple scopes share this same where clause.'
|
282
|
+
Enabled: pending
|
283
|
+
VersionAdded: '2.14'
|
284
|
+
|
254
285
|
Rails/DurationArithmetic:
|
255
286
|
Description: 'Do not use duration as arithmetic operand with `Time.current`.'
|
256
287
|
StyleGuide: 'https://rails.rubystyle.guide#duration-arithmetic'
|
@@ -415,6 +446,15 @@ Rails/HttpStatus:
|
|
415
446
|
- numeric
|
416
447
|
- symbolic
|
417
448
|
|
449
|
+
Rails/I18nLazyLookup:
|
450
|
+
Description: 'Checks for places where I18n "lazy" lookup can be used.'
|
451
|
+
StyleGuide: 'https://rails.rubystyle.guide/#lazy-lookup'
|
452
|
+
Reference: 'https://guides.rubyonrails.org/i18n.html#lazy-lookup'
|
453
|
+
Enabled: pending
|
454
|
+
VersionAdded: '2.14'
|
455
|
+
Include:
|
456
|
+
- 'controllers/**/*'
|
457
|
+
|
418
458
|
Rails/I18nLocaleAssignment:
|
419
459
|
Description: 'Prefer the usage of `I18n.with_locale` instead of manually updating `I18n.locale` value.'
|
420
460
|
Enabled: 'pending'
|
@@ -423,6 +463,12 @@ Rails/I18nLocaleAssignment:
|
|
423
463
|
- spec/**/*.rb
|
424
464
|
- test/**/*.rb
|
425
465
|
|
466
|
+
Rails/I18nLocaleTexts:
|
467
|
+
Description: 'Enforces use of I18n and locale files instead of locale specific strings.'
|
468
|
+
StyleGuide: 'https://rails.rubystyle.guide/#locale-texts'
|
469
|
+
Enabled: pending
|
470
|
+
VersionAdded: '2.14'
|
471
|
+
|
426
472
|
Rails/IgnoredSkipActionFilterOption:
|
427
473
|
Description: 'Checks that `if` and `only` (or `except`) are not used together as options of `skip_*` action filter.'
|
428
474
|
Reference: 'https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options'
|
@@ -495,6 +541,13 @@ Rails/MatchRoute:
|
|
495
541
|
- config/routes.rb
|
496
542
|
- config/routes/**/*.rb
|
497
543
|
|
544
|
+
Rails/MigrationClassName:
|
545
|
+
Description: 'The class name of the migration should match its file name.'
|
546
|
+
Enabled: pending
|
547
|
+
VersionAdded: '2.14'
|
548
|
+
Include:
|
549
|
+
- db/migrate/*.rb
|
550
|
+
|
498
551
|
Rails/NegateInclude:
|
499
552
|
Description: 'Prefer `collection.exclude?(obj)` over `!collection.include?(obj)`.'
|
500
553
|
StyleGuide: 'https://rails.rubystyle.guide#exclude'
|
@@ -817,6 +870,15 @@ Rails/SquishedSQLHeredocs:
|
|
817
870
|
# to be preserved in order to work, thus auto-correction is not safe.
|
818
871
|
SafeAutoCorrect: false
|
819
872
|
|
873
|
+
Rails/TableNameAssignment:
|
874
|
+
Description: >-
|
875
|
+
Do not use `self.table_name =`. Use Inflections or `table_name_prefix` instead.
|
876
|
+
StyleGuide: 'https://rails.rubystyle.guide/#keep-ar-defaults'
|
877
|
+
Enabled: false
|
878
|
+
VersionAdded: '2.14'
|
879
|
+
Include:
|
880
|
+
- app/models/**/*.rb
|
881
|
+
|
820
882
|
Rails/TimeZone:
|
821
883
|
Description: 'Checks the correct usage of time zone aware methods.'
|
822
884
|
StyleGuide: 'https://rails.rubystyle.guide#time'
|
@@ -843,6 +905,11 @@ Rails/TimeZoneAssignment:
|
|
843
905
|
- spec/**/*.rb
|
844
906
|
- test/**/*.rb
|
845
907
|
|
908
|
+
Rails/TransactionExitStatement:
|
909
|
+
Description: 'Avoid the usage of `return`, `break` and `throw` in transaction blocks.'
|
910
|
+
Enabled: pending
|
911
|
+
VersionAdded: '2.14'
|
912
|
+
|
846
913
|
Rails/UniqBeforePluck:
|
847
914
|
Description: 'Prefer the use of uniq or distinct before pluck.'
|
848
915
|
Enabled: true
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
# A mixin to return all of the class send nodes.
|
6
|
+
module ClassSendNodeHelper
|
7
|
+
def class_send_nodes(class_node)
|
8
|
+
class_def = class_node.body
|
9
|
+
|
10
|
+
return [] unless class_def
|
11
|
+
|
12
|
+
if class_def.send_type?
|
13
|
+
[class_def]
|
14
|
+
else
|
15
|
+
class_def.each_child_node(:send)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Using `ActionController::TestCase`` is discouraged and should be replaced by
|
7
|
+
# `ActionDispatch::IntegrationTest``. Controller tests are too close to the
|
8
|
+
# internals of a controller whereas integration tests mimic the browser/user.
|
9
|
+
#
|
10
|
+
# @safety
|
11
|
+
# This cop's autocorrection is unsafe because the API of each test case class is different.
|
12
|
+
# Make sure to update each test of your controller test cases after changing the superclass.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# # bad
|
16
|
+
# class MyControllerTest < ActionController::TestCase
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# class MyControllerTest < ActionDispatch::IntegrationTest
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
class ActionControllerTestCase < Base
|
24
|
+
extend AutoCorrector
|
25
|
+
extend TargetRailsVersion
|
26
|
+
|
27
|
+
MSG = 'Use `ActionDispatch::IntegrationTest` instead.'
|
28
|
+
|
29
|
+
minimum_target_rails_version 5.0
|
30
|
+
|
31
|
+
def_node_matcher :action_controller_test_case?, <<~PATTERN
|
32
|
+
(class
|
33
|
+
(const nil? _)
|
34
|
+
(const (const {nil? cbase} :ActionController) :TestCase) nil?)
|
35
|
+
PATTERN
|
36
|
+
|
37
|
+
def on_class(node)
|
38
|
+
return unless action_controller_test_case?(node)
|
39
|
+
|
40
|
+
add_offense(node.parent_class) do |corrector|
|
41
|
+
corrector.replace(node.parent_class, 'ActionDispatch::IntegrationTest')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -32,6 +32,8 @@ module RuboCop
|
|
32
32
|
# after_update_commit :log_update_action
|
33
33
|
#
|
34
34
|
class AfterCommitOverride < Base
|
35
|
+
include ClassSendNodeHelper
|
36
|
+
|
35
37
|
MSG = 'There can only be one `after_*_commit :%<name>s` hook defined for a model.'
|
36
38
|
|
37
39
|
AFTER_COMMIT_CALLBACKS = %i[
|
@@ -63,18 +65,6 @@ module RuboCop
|
|
63
65
|
end
|
64
66
|
end
|
65
67
|
|
66
|
-
def class_send_nodes(class_node)
|
67
|
-
class_def = class_node.body
|
68
|
-
|
69
|
-
return [] unless class_def
|
70
|
-
|
71
|
-
if class_def.send_type?
|
72
|
-
[class_def]
|
73
|
-
else
|
74
|
-
class_def.each_child_node(:send).to_a
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
68
|
def after_commit_callback?(node)
|
79
69
|
AFTER_COMMIT_CALLBACKS.include?(node.method_name)
|
80
70
|
end
|
@@ -155,17 +155,31 @@ module RuboCop
|
|
155
155
|
return if include_bulk_options?(node)
|
156
156
|
return unless node.block_node
|
157
157
|
|
158
|
-
send_nodes = node.block_node.body
|
158
|
+
send_nodes = send_nodes_from_change_table_block(node.block_node.body)
|
159
159
|
|
160
|
-
|
161
|
-
combinable_transformations.include?(send_node.method_name)
|
162
|
-
end
|
163
|
-
|
164
|
-
add_offense_for_change_table(node) if transformations.size > 1
|
160
|
+
add_offense_for_change_table(node) if count_transformations(send_nodes) > 1
|
165
161
|
end
|
166
162
|
|
167
163
|
private
|
168
164
|
|
165
|
+
def send_nodes_from_change_table_block(body)
|
166
|
+
if body.send_type?
|
167
|
+
[body]
|
168
|
+
else
|
169
|
+
body.each_child_node(:send).to_a
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
def count_transformations(send_nodes)
|
174
|
+
send_nodes.sum do |node|
|
175
|
+
if node.method?(:remove)
|
176
|
+
node.arguments.count { |arg| !arg.hash_type? }
|
177
|
+
else
|
178
|
+
combinable_transformations.include?(node.method_name) ? 1 : 0
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
169
183
|
# @param node [RuboCop::AST::SendNode] (send nil? :change_table ...)
|
170
184
|
def include_bulk_options?(node)
|
171
185
|
# arguments: [{(sym :table)(str "table")} (hash (pair (sym :bulk) _))]
|
@@ -13,6 +13,12 @@ module RuboCop
|
|
13
13
|
# `[[1, 2], [3, nil]].compact_blank` are not compatible. The same is true for `blank?`.
|
14
14
|
# This will work fine when the receiver is a hash object.
|
15
15
|
#
|
16
|
+
# And `compact_blank!` has different implementations for `Array`, `Hash`, and
|
17
|
+
# `ActionController::Parameters`.
|
18
|
+
# `Array#compact_blank!`, `Hash#compact_blank!` are equivalent to `delete_if(&:blank?)`.
|
19
|
+
# `ActionController::Parameters#compact_blank!` is equivalent to `reject!(&:blank?)`.
|
20
|
+
# If the cop makes a mistake, auto-corrected code may get unexpected behavior.
|
21
|
+
#
|
16
22
|
# @example
|
17
23
|
#
|
18
24
|
# # bad
|
@@ -23,8 +29,10 @@ module RuboCop
|
|
23
29
|
# collection.compact_blank
|
24
30
|
#
|
25
31
|
# # bad
|
26
|
-
# collection.
|
27
|
-
# collection.
|
32
|
+
# collection.delete_if(&:blank?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
|
33
|
+
# collection.delete_if { |_k, v| v.blank? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!`
|
34
|
+
# collection.reject!(&:blank?) # Same behavior as `ActionController::Parameters#compact_blank!`
|
35
|
+
# collection.reject! { |_k, v| v.blank? } # Same behavior as `ActionController::Parameters#compact_blank!`
|
28
36
|
#
|
29
37
|
# # good
|
30
38
|
# collection.compact_blank!
|
@@ -35,20 +43,20 @@ module RuboCop
|
|
35
43
|
extend TargetRailsVersion
|
36
44
|
|
37
45
|
MSG = 'Use `%<preferred_method>s` instead.'
|
38
|
-
RESTRICT_ON_SEND = %i[reject reject!].freeze
|
46
|
+
RESTRICT_ON_SEND = %i[reject delete_if reject!].freeze
|
39
47
|
|
40
48
|
minimum_target_rails_version 6.1
|
41
49
|
|
42
50
|
def_node_matcher :reject_with_block?, <<~PATTERN
|
43
51
|
(block
|
44
|
-
(send _ {:reject :reject!})
|
52
|
+
(send _ {:reject :delete_if :reject!})
|
45
53
|
$(args ...)
|
46
54
|
(send
|
47
55
|
$(lvar _) :blank?))
|
48
56
|
PATTERN
|
49
57
|
|
50
58
|
def_node_matcher :reject_with_block_pass?, <<~PATTERN
|
51
|
-
(send _ {:reject :reject!}
|
59
|
+
(send _ {:reject :delete_if :reject!}
|
52
60
|
(block_pass
|
53
61
|
(sym :blank?)))
|
54
62
|
PATTERN
|
@@ -0,0 +1,108 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks direct manipulation of ActiveModel#errors as hash.
|
7
|
+
# These operations are deprecated in Rails 6.1 and will not work in Rails 7.
|
8
|
+
#
|
9
|
+
# @safety
|
10
|
+
# This cop is unsafe because it can report `errors` manipulation on non-ActiveModel,
|
11
|
+
# which is obviously valid.
|
12
|
+
# The cop has no way of knowing whether a variable is an ActiveModel or not.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# # bad
|
16
|
+
# user.errors[:name] << 'msg'
|
17
|
+
# user.errors.messages[:name] << 'msg'
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# user.errors.add(:name, 'msg')
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# user.errors[:name].clear
|
24
|
+
# user.errors.messages[:name].clear
|
25
|
+
#
|
26
|
+
# # good
|
27
|
+
# user.errors.delete(:name)
|
28
|
+
#
|
29
|
+
class DeprecatedActiveModelErrorsMethods < Base
|
30
|
+
MSG = 'Avoid manipulating ActiveModel errors as hash directly.'
|
31
|
+
|
32
|
+
MANIPULATIVE_METHODS = Set[
|
33
|
+
*%i[
|
34
|
+
<< append clear collect! compact! concat
|
35
|
+
delete delete_at delete_if drop drop_while fill filter! keep_if
|
36
|
+
flatten! insert map! pop prepend push reject! replace reverse!
|
37
|
+
rotate! select! shift shuffle! slice! sort! sort_by! uniq! unshift
|
38
|
+
]
|
39
|
+
].freeze
|
40
|
+
|
41
|
+
def_node_matcher :receiver_matcher_outside_model, '{send ivar lvar}'
|
42
|
+
def_node_matcher :receiver_matcher_inside_model, '{nil? send ivar lvar}'
|
43
|
+
|
44
|
+
def_node_matcher :any_manipulation?, <<~PATTERN
|
45
|
+
{
|
46
|
+
#root_manipulation?
|
47
|
+
#root_assignment?
|
48
|
+
#messages_details_manipulation?
|
49
|
+
#messages_details_assignment?
|
50
|
+
}
|
51
|
+
PATTERN
|
52
|
+
|
53
|
+
def_node_matcher :root_manipulation?, <<~PATTERN
|
54
|
+
(send
|
55
|
+
(send
|
56
|
+
(send #receiver_matcher :errors) :[] ...)
|
57
|
+
MANIPULATIVE_METHODS
|
58
|
+
...
|
59
|
+
)
|
60
|
+
PATTERN
|
61
|
+
|
62
|
+
def_node_matcher :root_assignment?, <<~PATTERN
|
63
|
+
(send
|
64
|
+
(send #receiver_matcher :errors)
|
65
|
+
:[]=
|
66
|
+
...)
|
67
|
+
PATTERN
|
68
|
+
|
69
|
+
def_node_matcher :messages_details_manipulation?, <<~PATTERN
|
70
|
+
(send
|
71
|
+
(send
|
72
|
+
(send
|
73
|
+
(send #receiver_matcher :errors)
|
74
|
+
{:messages :details})
|
75
|
+
:[]
|
76
|
+
...)
|
77
|
+
MANIPULATIVE_METHODS
|
78
|
+
...)
|
79
|
+
PATTERN
|
80
|
+
|
81
|
+
def_node_matcher :messages_details_assignment?, <<~PATTERN
|
82
|
+
(send
|
83
|
+
(send
|
84
|
+
(send #receiver_matcher :errors)
|
85
|
+
{:messages :details})
|
86
|
+
:[]=
|
87
|
+
...)
|
88
|
+
PATTERN
|
89
|
+
|
90
|
+
def on_send(node)
|
91
|
+
any_manipulation?(node) do
|
92
|
+
add_offense(node)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def receiver_matcher(node)
|
99
|
+
model_file? ? receiver_matcher_inside_model(node) : receiver_matcher_outside_model(node)
|
100
|
+
end
|
101
|
+
|
102
|
+
def model_file?
|
103
|
+
processed_source.buffer.name.include?('/models/')
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop looks for associations that have been defined multiple times in the same file.
|
7
|
+
#
|
8
|
+
# When an association is defined multiple times on a model, Active Record overrides the
|
9
|
+
# previously defined association with the new one. Because of this, this cop's autocorrection
|
10
|
+
# simply keeps the last of any duplicates and discards the rest.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
#
|
14
|
+
# # bad
|
15
|
+
# belongs_to :foo
|
16
|
+
# belongs_to :bar
|
17
|
+
# has_one :foo
|
18
|
+
#
|
19
|
+
# # good
|
20
|
+
# belongs_to :bar
|
21
|
+
# has_one :foo
|
22
|
+
#
|
23
|
+
class DuplicateAssociation < Base
|
24
|
+
include RangeHelp
|
25
|
+
extend AutoCorrector
|
26
|
+
include ClassSendNodeHelper
|
27
|
+
|
28
|
+
MSG = "Association `%<name>s` is defined multiple times. Don't repeat associations."
|
29
|
+
|
30
|
+
def_node_matcher :association, <<~PATTERN
|
31
|
+
(send nil? {:belongs_to :has_one :has_many :has_and_belongs_to_many} ({sym str} $_) ...)
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_class(class_node)
|
35
|
+
offenses(class_node).each do |name, nodes|
|
36
|
+
nodes.each do |node|
|
37
|
+
add_offense(node, message: format(MSG, name: name)) do |corrector|
|
38
|
+
next if nodes.last == node
|
39
|
+
|
40
|
+
corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def offenses(class_node)
|
49
|
+
class_send_nodes(class_node).select { |node| association(node) }
|
50
|
+
.group_by { |node| association(node).to_sym }
|
51
|
+
.select { |_, nodes| nodes.length > 1 }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks for multiple scopes in a model that have the same `where` clause. This
|
7
|
+
# often means you copy/pasted a scope, updated the name, and forgot to change the condition.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# scope :visible, -> { where(visible: true) }
|
13
|
+
# scope :hidden, -> { where(visible: true) }
|
14
|
+
#
|
15
|
+
# # good
|
16
|
+
# scope :visible, -> { where(visible: true) }
|
17
|
+
# scope :hidden, -> { where(visible: false) }
|
18
|
+
#
|
19
|
+
class DuplicateScope < Base
|
20
|
+
include ClassSendNodeHelper
|
21
|
+
|
22
|
+
MSG = 'Multiple scopes share this same where clause.'
|
23
|
+
|
24
|
+
def_node_matcher :scope, <<~PATTERN
|
25
|
+
(send nil? :scope _ $...)
|
26
|
+
PATTERN
|
27
|
+
|
28
|
+
def on_class(class_node)
|
29
|
+
offenses(class_node).each do |node|
|
30
|
+
add_offense(node)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def offenses(class_node)
|
37
|
+
class_send_nodes(class_node).select { |node| scope(node) }
|
38
|
+
.group_by { |node| scope(node) }
|
39
|
+
.select { |_, nodes| nodes.length > 1 }
|
40
|
+
.values
|
41
|
+
.flatten
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks for places where I18n "lazy" lookup can be used.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # en.yml
|
10
|
+
# # en:
|
11
|
+
# # books:
|
12
|
+
# # create:
|
13
|
+
# # success: Book created!
|
14
|
+
#
|
15
|
+
# # bad
|
16
|
+
# class BooksController < ApplicationController
|
17
|
+
# def create
|
18
|
+
# # ...
|
19
|
+
# redirect_to books_url, notice: t('books.create.success')
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # good
|
24
|
+
# class BooksController < ApplicationController
|
25
|
+
# def create
|
26
|
+
# # ...
|
27
|
+
# redirect_to books_url, notice: t('.success')
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
#
|
31
|
+
class I18nLazyLookup < Base
|
32
|
+
include VisibilityHelp
|
33
|
+
extend AutoCorrector
|
34
|
+
|
35
|
+
MSG = 'Use "lazy" lookup for the text used in controllers.'
|
36
|
+
|
37
|
+
def_node_matcher :translate_call?, <<~PATTERN
|
38
|
+
(send nil? {:translate :t} ${sym_type? str_type?} ...)
|
39
|
+
PATTERN
|
40
|
+
|
41
|
+
def on_send(node)
|
42
|
+
translate_call?(node) do |key_node|
|
43
|
+
key = key_node.value
|
44
|
+
return if key.to_s.start_with?('.')
|
45
|
+
|
46
|
+
controller, action = controller_and_action(node)
|
47
|
+
return unless controller && action
|
48
|
+
|
49
|
+
scoped_key = get_scoped_key(key_node, controller, action)
|
50
|
+
return unless key == scoped_key
|
51
|
+
|
52
|
+
add_offense(key_node) do |corrector|
|
53
|
+
unscoped_key = key_node.value.to_s.split('.').last
|
54
|
+
corrector.replace(key_node, "'.#{unscoped_key}'")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def controller_and_action(node)
|
62
|
+
action_node = node.each_ancestor(:def).first
|
63
|
+
return unless action_node && node_visibility(action_node) == :public
|
64
|
+
|
65
|
+
controller_node = node.each_ancestor(:class).first
|
66
|
+
return unless controller_node && controller_node.identifier.source.end_with?('Controller')
|
67
|
+
|
68
|
+
[controller_node, action_node]
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_scoped_key(key_node, controller, action)
|
72
|
+
path = controller_path(controller).tr('/', '.')
|
73
|
+
action_name = action.method_name
|
74
|
+
key = key_node.value.to_s.split('.').last
|
75
|
+
|
76
|
+
"#{path}.#{action_name}.#{key}"
|
77
|
+
end
|
78
|
+
|
79
|
+
def controller_path(controller)
|
80
|
+
module_name = controller.parent_module_name
|
81
|
+
controller_name = controller.identifier.source
|
82
|
+
|
83
|
+
path = if module_name == 'Object'
|
84
|
+
controller_name
|
85
|
+
else
|
86
|
+
"#{module_name}::#{controller_name}"
|
87
|
+
end
|
88
|
+
|
89
|
+
path.delete_suffix('Controller').underscore
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Enforces use of I18n and locale files instead of locale specific strings.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# # bad
|
10
|
+
# class User < ApplicationRecord
|
11
|
+
# validates :email, presence: { message: "must be present" }
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# # config/locales/en.yml
|
16
|
+
# # en:
|
17
|
+
# # activerecord:
|
18
|
+
# # errors:
|
19
|
+
# # models:
|
20
|
+
# # user:
|
21
|
+
# # blank: "must be present"
|
22
|
+
#
|
23
|
+
# class User < ApplicationRecord
|
24
|
+
# validates :email, presence: true
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # bad
|
28
|
+
# class PostsController < ApplicationController
|
29
|
+
# def create
|
30
|
+
# # ...
|
31
|
+
# redirect_to root_path, notice: "Post created!"
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
# # good
|
36
|
+
# # config/locales/en.yml
|
37
|
+
# # en:
|
38
|
+
# # posts:
|
39
|
+
# # create:
|
40
|
+
# # success: "Post created!"
|
41
|
+
#
|
42
|
+
# class PostsController < ApplicationController
|
43
|
+
# def create
|
44
|
+
# # ...
|
45
|
+
# redirect_to root_path, notice: t(".success")
|
46
|
+
# end
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# # bad
|
50
|
+
# class UserMailer < ApplicationMailer
|
51
|
+
# def welcome(user)
|
52
|
+
# mail(to: user.email, subject: "Welcome to My Awesome Site")
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # good
|
57
|
+
# # config/locales/en.yml
|
58
|
+
# # en:
|
59
|
+
# # user_mailer:
|
60
|
+
# # welcome:
|
61
|
+
# # subject: "Welcome to My Awesome Site"
|
62
|
+
#
|
63
|
+
# class UserMailer < ApplicationMailer
|
64
|
+
# def welcome(user)
|
65
|
+
# mail(to: user.email)
|
66
|
+
# end
|
67
|
+
# end
|
68
|
+
#
|
69
|
+
class I18nLocaleTexts < Base
|
70
|
+
MSG = 'Move locale texts to the locale files in the `config/locales` directory.'
|
71
|
+
|
72
|
+
RESTRICT_ON_SEND = %i[validates redirect_to []= mail].freeze
|
73
|
+
|
74
|
+
def_node_search :validation_message, <<~PATTERN
|
75
|
+
(pair (sym :message) $str)
|
76
|
+
PATTERN
|
77
|
+
|
78
|
+
def_node_search :redirect_to_flash, <<~PATTERN
|
79
|
+
(pair (sym {:notice :alert}) $str)
|
80
|
+
PATTERN
|
81
|
+
|
82
|
+
def_node_matcher :flash_assignment?, <<~PATTERN
|
83
|
+
(send (send nil? :flash) :[]= _ $str)
|
84
|
+
PATTERN
|
85
|
+
|
86
|
+
def_node_search :mail_subject, <<~PATTERN
|
87
|
+
(pair (sym :subject) $str)
|
88
|
+
PATTERN
|
89
|
+
|
90
|
+
def on_send(node)
|
91
|
+
case node.method_name
|
92
|
+
when :validates
|
93
|
+
validation_message(node) do |text_node|
|
94
|
+
add_offense(text_node)
|
95
|
+
end
|
96
|
+
return
|
97
|
+
when :redirect_to
|
98
|
+
text_node = redirect_to_flash(node).to_a.last
|
99
|
+
when :[]=
|
100
|
+
text_node = flash_assignment?(node)
|
101
|
+
when :mail
|
102
|
+
text_node = mail_subject(node).to_a.last
|
103
|
+
end
|
104
|
+
|
105
|
+
add_offense(text_node) if text_node
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop makes sure that each migration file defines a migration class
|
7
|
+
# whose name matches the file name.
|
8
|
+
# (e.g. `20220224111111_create_users.rb` should define `CreateUsers` class.)
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # db/migrate/20220224111111_create_users.rb
|
12
|
+
#
|
13
|
+
# # bad
|
14
|
+
# class SellBooks < ActiveRecord::Migration[7.0]
|
15
|
+
# end
|
16
|
+
#
|
17
|
+
# # good
|
18
|
+
# class CreateUsers < ActiveRecord::Migration[7.0]
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
class MigrationClassName < Base
|
22
|
+
extend AutoCorrector
|
23
|
+
include MigrationsHelper
|
24
|
+
|
25
|
+
MSG = 'Replace with `%<corrected_class_name>s` that matches the file name.'
|
26
|
+
|
27
|
+
def on_class(node)
|
28
|
+
return if in_migration?(node)
|
29
|
+
|
30
|
+
snake_class_name = to_snakecase(node.identifier.source)
|
31
|
+
|
32
|
+
basename = basename_without_timestamp_and_suffix
|
33
|
+
return if snake_class_name == basename
|
34
|
+
|
35
|
+
corrected_class_name = to_camelcase(basename)
|
36
|
+
message = format(MSG, corrected_class_name: corrected_class_name)
|
37
|
+
|
38
|
+
add_offense(node.identifier, message: message) do |corrector|
|
39
|
+
corrector.replace(node.identifier, corrected_class_name)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def basename_without_timestamp_and_suffix
|
46
|
+
filepath = processed_source.file_path
|
47
|
+
basename = File.basename(filepath, '.rb')
|
48
|
+
basename = remove_gem_suffix(basename)
|
49
|
+
basename.sub(/\A\d+_/, '')
|
50
|
+
end
|
51
|
+
|
52
|
+
# e.g.: from `add_blobs.active_storage` to `add_blobs`.
|
53
|
+
def remove_gem_suffix(file_name)
|
54
|
+
file_name.sub(/\..+\z/, '')
|
55
|
+
end
|
56
|
+
|
57
|
+
def to_camelcase(word)
|
58
|
+
word.split('_').map(&:capitalize).join
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_snakecase(word)
|
62
|
+
word
|
63
|
+
.gsub(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
64
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
65
|
+
.tr('-', '_')
|
66
|
+
.downcase
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -21,25 +21,31 @@ module RuboCop
|
|
21
21
|
extend AutoCorrector
|
22
22
|
extend TargetRailsVersion
|
23
23
|
|
24
|
-
MSG = 'Prefer `pluck(:%<value>s)` over `%<
|
24
|
+
MSG = 'Prefer `pluck(:%<value>s)` over `%<current>s`.'
|
25
25
|
|
26
26
|
minimum_target_rails_version 5.0
|
27
27
|
|
28
28
|
def_node_matcher :pluck_candidate?, <<~PATTERN
|
29
|
-
(block (send _
|
29
|
+
({block numblock} (send _ {:map :collect}) $_argument (send (lvar $_element) :[] (sym $_value)))
|
30
30
|
PATTERN
|
31
31
|
|
32
32
|
def on_block(node)
|
33
|
-
pluck_candidate?(node) do |
|
34
|
-
|
33
|
+
pluck_candidate?(node) do |argument, element, value|
|
34
|
+
match = if node.block_type?
|
35
|
+
argument.children.first.source.to_sym == element
|
36
|
+
else # numblock
|
37
|
+
argument == 1 && element == :_1
|
38
|
+
end
|
39
|
+
next unless match
|
35
40
|
|
36
|
-
message = message(
|
41
|
+
message = message(value, node)
|
37
42
|
|
38
43
|
add_offense(offense_range(node), message: message) do |corrector|
|
39
44
|
corrector.replace(offense_range(node), "pluck(:#{value})")
|
40
45
|
end
|
41
46
|
end
|
42
47
|
end
|
48
|
+
alias on_numblock on_block
|
43
49
|
|
44
50
|
private
|
45
51
|
|
@@ -47,8 +53,10 @@ module RuboCop
|
|
47
53
|
node.send_node.loc.selector.join(node.loc.end)
|
48
54
|
end
|
49
55
|
|
50
|
-
def message(
|
51
|
-
|
56
|
+
def message(value, node)
|
57
|
+
current = offense_range(node).source
|
58
|
+
|
59
|
+
format(MSG, value: value, current: current)
|
52
60
|
end
|
53
61
|
end
|
54
62
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop enforces the absence of explicit table name assignment.
|
7
|
+
#
|
8
|
+
# `self.table_name=` should only be used for very good reasons,
|
9
|
+
# such as not having control over the database, or working
|
10
|
+
# on a legacy project.
|
11
|
+
#
|
12
|
+
# If you need to change how your model's name is translated to
|
13
|
+
# a table name, you may want to look at Inflections:
|
14
|
+
# https://api.rubyonrails.org/classes/ActiveSupport/Inflector/Inflections.html
|
15
|
+
#
|
16
|
+
# If you wish to add a prefix in front of your model, or wish to change
|
17
|
+
# the default prefix, `self.table_name_prefix` might better suit your needs:
|
18
|
+
# https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema.html#method-c-table_name_prefix-3D
|
19
|
+
#
|
20
|
+
# STI base classes named `Base` are ignored by this cop.
|
21
|
+
# For more information: https://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# # bad
|
25
|
+
# self.table_name = 'some_table_name'
|
26
|
+
# self.table_name = :some_other_name
|
27
|
+
class TableNameAssignment < Base
|
28
|
+
include ActiveRecordHelper
|
29
|
+
|
30
|
+
MSG = 'Do not use `self.table_name =`.'
|
31
|
+
|
32
|
+
def_node_matcher :base_class?, <<~PATTERN
|
33
|
+
(class (const ... :Base) ...)
|
34
|
+
PATTERN
|
35
|
+
|
36
|
+
def on_class(class_node)
|
37
|
+
return if base_class?(class_node)
|
38
|
+
|
39
|
+
find_set_table_name(class_node).each { |node| add_offense(node) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# This cop checks for the use of exit statements (namely `return`,
|
7
|
+
# `break` and `throw`) in transactions. This is due to the eventual
|
8
|
+
# unexpected behavior when using ActiveRecord >= 7, where transactions
|
9
|
+
# exitted using these statements are being rollbacked rather than
|
10
|
+
# committed (pre ActiveRecord 7 behavior).
|
11
|
+
#
|
12
|
+
# As alternatives, it would be more intuitive to explicitly raise an
|
13
|
+
# error when rollback is desired, and to use `next` when commit is
|
14
|
+
# desired.
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# # bad
|
18
|
+
# ApplicationRecord.transaction do
|
19
|
+
# return if user.active?
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# # bad
|
23
|
+
# ApplicationRecord.transaction do
|
24
|
+
# break if user.active?
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # bad
|
28
|
+
# ApplicationRecord.transaction do
|
29
|
+
# throw if user.active?
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# # good
|
33
|
+
# ApplicationRecord.transaction do
|
34
|
+
# # Rollback
|
35
|
+
# raise "User is active" if user.active?
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# # good
|
39
|
+
# ApplicationRecord.transaction do
|
40
|
+
# # Commit
|
41
|
+
# next if user.active?
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# @see https://github.com/rails/rails/commit/15aa4200e083
|
45
|
+
class TransactionExitStatement < Base
|
46
|
+
MSG = <<~MSG.chomp
|
47
|
+
Exit statement `%<statement>s` is not allowed. Use `raise` (rollback) or `next` (commit).
|
48
|
+
MSG
|
49
|
+
|
50
|
+
RESTRICT_ON_SEND = %i[transaction].freeze
|
51
|
+
|
52
|
+
def_node_search :exit_statements, <<~PATTERN
|
53
|
+
({return | break | send nil? :throw} ...)
|
54
|
+
PATTERN
|
55
|
+
|
56
|
+
def on_send(node)
|
57
|
+
parent = node.parent
|
58
|
+
|
59
|
+
return unless parent&.block_type?
|
60
|
+
|
61
|
+
exit_statements(parent.body).each do |statement_node|
|
62
|
+
statement = if statement_node.return_type?
|
63
|
+
'return'
|
64
|
+
elsif statement_node.break_type?
|
65
|
+
'break'
|
66
|
+
else
|
67
|
+
statement_node.method_name
|
68
|
+
end
|
69
|
+
message = format(MSG, statement: statement)
|
70
|
+
|
71
|
+
add_offense(statement_node, message: message)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -2,11 +2,13 @@
|
|
2
2
|
|
3
3
|
require_relative 'mixin/active_record_helper'
|
4
4
|
require_relative 'mixin/active_record_migrations_helper'
|
5
|
+
require_relative 'mixin/class_send_node_helper'
|
5
6
|
require_relative 'mixin/enforce_superclass'
|
6
7
|
require_relative 'mixin/index_method'
|
7
8
|
require_relative 'mixin/migrations_helper'
|
8
9
|
require_relative 'mixin/target_rails_version'
|
9
10
|
|
11
|
+
require_relative 'rails/action_controller_test_case'
|
10
12
|
require_relative 'rails/action_filter'
|
11
13
|
require_relative 'rails/active_record_aliases'
|
12
14
|
require_relative 'rails/active_record_callbacks_order'
|
@@ -31,6 +33,9 @@ require_relative 'rails/date'
|
|
31
33
|
require_relative 'rails/default_scope'
|
32
34
|
require_relative 'rails/delegate'
|
33
35
|
require_relative 'rails/delegate_allow_blank'
|
36
|
+
require_relative 'rails/deprecated_active_model_errors_methods'
|
37
|
+
require_relative 'rails/duplicate_association'
|
38
|
+
require_relative 'rails/duplicate_scope'
|
34
39
|
require_relative 'rails/duration_arithmetic'
|
35
40
|
require_relative 'rails/dynamic_find_by'
|
36
41
|
require_relative 'rails/eager_evaluation_log_message'
|
@@ -49,7 +54,9 @@ require_relative 'rails/has_many_or_has_one_dependent'
|
|
49
54
|
require_relative 'rails/helper_instance_variable'
|
50
55
|
require_relative 'rails/http_positional_arguments'
|
51
56
|
require_relative 'rails/http_status'
|
57
|
+
require_relative 'rails/i18n_lazy_lookup'
|
52
58
|
require_relative 'rails/i18n_locale_assignment'
|
59
|
+
require_relative 'rails/i18n_locale_texts'
|
53
60
|
require_relative 'rails/ignored_skip_action_filter_option'
|
54
61
|
require_relative 'rails/index_by'
|
55
62
|
require_relative 'rails/index_with'
|
@@ -59,6 +66,7 @@ require_relative 'rails/lexically_scoped_action_filter'
|
|
59
66
|
require_relative 'rails/link_to_blank'
|
60
67
|
require_relative 'rails/mailer_name'
|
61
68
|
require_relative 'rails/match_route'
|
69
|
+
require_relative 'rails/migration_class_name'
|
62
70
|
require_relative 'rails/negate_include'
|
63
71
|
require_relative 'rails/not_null_column'
|
64
72
|
require_relative 'rails/order_by_id'
|
@@ -96,8 +104,10 @@ require_relative 'rails/scope_args'
|
|
96
104
|
require_relative 'rails/short_i18n'
|
97
105
|
require_relative 'rails/skips_model_validations'
|
98
106
|
require_relative 'rails/squished_sql_heredocs'
|
107
|
+
require_relative 'rails/table_name_assignment'
|
99
108
|
require_relative 'rails/time_zone'
|
100
109
|
require_relative 'rails/time_zone_assignment'
|
110
|
+
require_relative 'rails/transaction_exit_statement'
|
101
111
|
require_relative 'rails/uniq_before_pluck'
|
102
112
|
require_relative 'rails/unique_validation_without_index'
|
103
113
|
require_relative 'rails/unknown_env'
|
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.14.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bozhidar Batsov
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2022-
|
13
|
+
date: 2022-03-16 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|
@@ -79,10 +79,12 @@ files:
|
|
79
79
|
- lib/rubocop-rails.rb
|
80
80
|
- lib/rubocop/cop/mixin/active_record_helper.rb
|
81
81
|
- lib/rubocop/cop/mixin/active_record_migrations_helper.rb
|
82
|
+
- lib/rubocop/cop/mixin/class_send_node_helper.rb
|
82
83
|
- lib/rubocop/cop/mixin/enforce_superclass.rb
|
83
84
|
- lib/rubocop/cop/mixin/index_method.rb
|
84
85
|
- lib/rubocop/cop/mixin/migrations_helper.rb
|
85
86
|
- lib/rubocop/cop/mixin/target_rails_version.rb
|
87
|
+
- lib/rubocop/cop/rails/action_controller_test_case.rb
|
86
88
|
- lib/rubocop/cop/rails/action_filter.rb
|
87
89
|
- lib/rubocop/cop/rails/active_record_aliases.rb
|
88
90
|
- lib/rubocop/cop/rails/active_record_callbacks_order.rb
|
@@ -107,6 +109,9 @@ files:
|
|
107
109
|
- lib/rubocop/cop/rails/default_scope.rb
|
108
110
|
- lib/rubocop/cop/rails/delegate.rb
|
109
111
|
- lib/rubocop/cop/rails/delegate_allow_blank.rb
|
112
|
+
- lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb
|
113
|
+
- lib/rubocop/cop/rails/duplicate_association.rb
|
114
|
+
- lib/rubocop/cop/rails/duplicate_scope.rb
|
110
115
|
- lib/rubocop/cop/rails/duration_arithmetic.rb
|
111
116
|
- lib/rubocop/cop/rails/dynamic_find_by.rb
|
112
117
|
- lib/rubocop/cop/rails/eager_evaluation_log_message.rb
|
@@ -125,7 +130,9 @@ files:
|
|
125
130
|
- lib/rubocop/cop/rails/helper_instance_variable.rb
|
126
131
|
- lib/rubocop/cop/rails/http_positional_arguments.rb
|
127
132
|
- lib/rubocop/cop/rails/http_status.rb
|
133
|
+
- lib/rubocop/cop/rails/i18n_lazy_lookup.rb
|
128
134
|
- lib/rubocop/cop/rails/i18n_locale_assignment.rb
|
135
|
+
- lib/rubocop/cop/rails/i18n_locale_texts.rb
|
129
136
|
- lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb
|
130
137
|
- lib/rubocop/cop/rails/index_by.rb
|
131
138
|
- lib/rubocop/cop/rails/index_with.rb
|
@@ -135,6 +142,7 @@ files:
|
|
135
142
|
- lib/rubocop/cop/rails/link_to_blank.rb
|
136
143
|
- lib/rubocop/cop/rails/mailer_name.rb
|
137
144
|
- lib/rubocop/cop/rails/match_route.rb
|
145
|
+
- lib/rubocop/cop/rails/migration_class_name.rb
|
138
146
|
- lib/rubocop/cop/rails/negate_include.rb
|
139
147
|
- lib/rubocop/cop/rails/not_null_column.rb
|
140
148
|
- lib/rubocop/cop/rails/order_by_id.rb
|
@@ -172,8 +180,10 @@ files:
|
|
172
180
|
- lib/rubocop/cop/rails/short_i18n.rb
|
173
181
|
- lib/rubocop/cop/rails/skips_model_validations.rb
|
174
182
|
- lib/rubocop/cop/rails/squished_sql_heredocs.rb
|
183
|
+
- lib/rubocop/cop/rails/table_name_assignment.rb
|
175
184
|
- lib/rubocop/cop/rails/time_zone.rb
|
176
185
|
- lib/rubocop/cop/rails/time_zone_assignment.rb
|
186
|
+
- lib/rubocop/cop/rails/transaction_exit_statement.rb
|
177
187
|
- lib/rubocop/cop/rails/uniq_before_pluck.rb
|
178
188
|
- lib/rubocop/cop/rails/unique_validation_without_index.rb
|
179
189
|
- lib/rubocop/cop/rails/unknown_env.rb
|
@@ -195,7 +205,7 @@ metadata:
|
|
195
205
|
homepage_uri: https://docs.rubocop.org/rubocop-rails/
|
196
206
|
changelog_uri: https://github.com/rubocop/rubocop-rails/blob/master/CHANGELOG.md
|
197
207
|
source_code_uri: https://github.com/rubocop/rubocop-rails/
|
198
|
-
documentation_uri: https://docs.rubocop.org/rubocop-rails/2.
|
208
|
+
documentation_uri: https://docs.rubocop.org/rubocop-rails/2.14/
|
199
209
|
bug_tracker_uri: https://github.com/rubocop/rubocop-rails/issues
|
200
210
|
rubygems_mfa_required: 'true'
|
201
211
|
post_install_message:
|