rubocop-rails 2.15.2 → 2.17.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/config/default.yml +122 -2
  3. data/config/obsoletion.yml +10 -0
  4. data/lib/rubocop/cop/mixin/active_record_helper.rb +3 -6
  5. data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
  6. data/lib/rubocop/cop/mixin/index_method.rb +6 -16
  7. data/lib/rubocop/cop/mixin/migrations_helper.rb +1 -1
  8. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +104 -0
  9. data/lib/rubocop/cop/rails/action_controller_test_case.rb +2 -2
  10. data/lib/rubocop/cop/rails/action_filter.rb +1 -1
  11. data/lib/rubocop/cop/rails/action_order.rb +117 -0
  12. data/lib/rubocop/cop/rails/active_record_aliases.rb +1 -4
  13. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  14. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  15. data/lib/rubocop/cop/rails/add_column_index.rb +1 -4
  16. data/lib/rubocop/cop/rails/application_controller.rb +1 -1
  17. data/lib/rubocop/cop/rails/application_job.rb +1 -1
  18. data/lib/rubocop/cop/rails/application_mailer.rb +1 -1
  19. data/lib/rubocop/cop/rails/application_record.rb +1 -1
  20. data/lib/rubocop/cop/rails/blank.rb +1 -2
  21. data/lib/rubocop/cop/rails/bulk_change_table.rb +6 -20
  22. data/lib/rubocop/cop/rails/compact_blank.rb +5 -1
  23. data/lib/rubocop/cop/rails/content_tag.rb +4 -5
  24. data/lib/rubocop/cop/rails/date.rb +4 -9
  25. data/lib/rubocop/cop/rails/delegate.rb +2 -5
  26. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +17 -13
  27. data/lib/rubocop/cop/rails/dot_separated_keys.rb +2 -2
  28. data/lib/rubocop/cop/rails/duration_arithmetic.rb +2 -2
  29. data/lib/rubocop/cop/rails/dynamic_find_by.rb +24 -12
  30. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +4 -0
  31. data/lib/rubocop/cop/rails/enum_uniqueness.rb +2 -5
  32. data/lib/rubocop/cop/rails/environment_comparison.rb +1 -2
  33. data/lib/rubocop/cop/rails/file_path.rb +5 -7
  34. data/lib/rubocop/cop/rails/find_each.rb +8 -2
  35. data/lib/rubocop/cop/rails/freeze_time.rb +76 -0
  36. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +2 -4
  37. data/lib/rubocop/cop/rails/helper_instance_variable.rb +1 -1
  38. data/lib/rubocop/cop/rails/http_positional_arguments.rb +4 -9
  39. data/lib/rubocop/cop/rails/http_status.rb +5 -10
  40. data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +2 -0
  41. data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
  42. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +3 -10
  43. data/lib/rubocop/cop/rails/index_by.rb +1 -1
  44. data/lib/rubocop/cop/rails/index_with.rb +1 -1
  45. data/lib/rubocop/cop/rails/inverse_of.rb +3 -6
  46. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +2 -6
  47. data/lib/rubocop/cop/rails/link_to_blank.rb +1 -4
  48. data/lib/rubocop/cop/rails/mailer_name.rb +3 -3
  49. data/lib/rubocop/cop/rails/migration_class_name.rb +1 -1
  50. data/lib/rubocop/cop/rails/output.rb +3 -6
  51. data/lib/rubocop/cop/rails/pluck.rb +32 -12
  52. data/lib/rubocop/cop/rails/pluralization_grammar.rb +1 -2
  53. data/lib/rubocop/cop/rails/presence.rb +21 -12
  54. data/lib/rubocop/cop/rails/present.rb +3 -6
  55. data/lib/rubocop/cop/rails/rake_environment.rb +1 -1
  56. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +2 -4
  57. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +1 -1
  58. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
  59. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +30 -26
  60. data/lib/rubocop/cop/rails/reflection_class_name.rb +17 -0
  61. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  62. data/lib/rubocop/cop/rails/relative_date_constant.rb +2 -5
  63. data/lib/rubocop/cop/rails/request_referer.rb +1 -2
  64. data/lib/rubocop/cop/rails/require_dependency.rb +1 -1
  65. data/lib/rubocop/cop/rails/reversible_migration.rb +10 -33
  66. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +1 -2
  67. data/lib/rubocop/cop/rails/root_pathname_methods.rb +225 -0
  68. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +1 -3
  69. data/lib/rubocop/cop/rails/save_bang.rb +10 -22
  70. data/lib/rubocop/cop/rails/short_i18n.rb +2 -5
  71. data/lib/rubocop/cop/rails/skips_model_validations.rb +2 -3
  72. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +1 -5
  73. data/lib/rubocop/cop/rails/time_zone.rb +10 -21
  74. data/lib/rubocop/cop/rails/time_zone_assignment.rb +1 -1
  75. data/lib/rubocop/cop/rails/to_s_with_argument.rb +78 -0
  76. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
  77. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  78. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -3
  79. data/lib/rubocop/cop/rails/unknown_env.rb +2 -4
  80. data/lib/rubocop/cop/rails/validation.rb +4 -12
  81. data/lib/rubocop/cop/rails/where_missing.rb +111 -0
  82. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
  83. data/lib/rubocop/cop/rails_cops.rb +10 -0
  84. data/lib/rubocop/rails/version.rb +1 -1
  85. data/lib/rubocop-rails.rb +10 -0
  86. metadata +16 -8
  87. data/bin/console +0 -11
  88. data/bin/setup +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 169ed04b1f5378e9e08fbffdca151afaf4b84fd54b1867a173740aadaede60b3
4
- data.tar.gz: 1a2ac75c313cfcdeec1814d7e3aff4777c5013527d2cf4a2aa4f95aeb45446bf
3
+ metadata.gz: e1cd420a9b6ec0e14a26063533cf9db61a81a43e44bec26a8b98e577cf761e49
4
+ data.tar.gz: 73918575c04e0f9ee8390d3efc0a4eb49b1cb4093695ecbafddbf995c406869d
5
5
  SHA512:
6
- metadata.gz: 51d495edd3e825db49ece8f51bfc118c73887681f414b86d31cd47d85dc5a1a22a385a2a17ed4ebf7d1c6332989795e2cde999a364d911c60f452993dc926c4b
7
- data.tar.gz: 4546785b39af93e6c7fe5a6a3b637fa5c21d4b358c38ea8ad3ebd5c272d1d0a504e8206e8201cfe3771af9199c336649d033e32b324f16b06fc7d150054dc488
6
+ metadata.gz: 93fffc6d3f6cbb781692725c13eb6f049e3106f2fb7ccb43a48fdf7c0d85a189914740d2ef743b0642eaa94ae0fc584ec1a32be53095a12167b3c02db2b035d4
7
+ data.tar.gz: 05ac2a5767f2c65437629fa623b3b4506547227c5b608a7ebc4e29a91b831e794ac6ee7c62a55b1573f3b228d40b6aaaedbda1fb7b81481c51f9c0df6884f389
data/config/default.yml CHANGED
@@ -10,6 +10,12 @@ AllCops:
10
10
  # Exclude db/schema.rb and db/[CONFIGURATION_NAMESPACE]_schema.rb by default.
11
11
  # See: https://guides.rubyonrails.org/active_record_multiple_databases.html#setting-up-your-application
12
12
  - db/*schema.rb
13
+ - log/**/*
14
+ - public/**/*
15
+ - storage/**/*
16
+ # Enable checking Active Support extensions.
17
+ # See: https://docs.rubocop.org/rubocop/configuration.html#enable-checking-active-support-extensions
18
+ ActiveSupportExtensionsEnabled: true
13
19
  # What version of Rails is the inspected code using? If a value is specified
14
20
  # for TargetRailsVersion then it is used. Acceptable values are specified
15
21
  # as a float (i.e. 5.1); the patch version of Rails should not be included.
@@ -23,6 +29,24 @@ Lint/NumberConversion:
23
29
  # Add Rails' duration methods to the ignore list for `Lint/NumberConversion`
24
30
  # so that calling `to_i` on one of these does not register an offense.
25
31
  # See: https://github.com/rubocop/rubocop/issues/8950
32
+ AllowedMethods:
33
+ - ago
34
+ - from_now
35
+ - second
36
+ - seconds
37
+ - minute
38
+ - minutes
39
+ - hour
40
+ - hours
41
+ - day
42
+ - days
43
+ - week
44
+ - weeks
45
+ - fortnight
46
+ - fortnights
47
+ - in_milliseconds
48
+ AllowedPatterns: []
49
+ # Deprecated.
26
50
  IgnoredMethods:
27
51
  - ago
28
52
  - from_now
@@ -40,12 +64,24 @@ Lint/NumberConversion:
40
64
  - fortnights
41
65
  - in_milliseconds
42
66
 
67
+ Rails:
68
+ Enabled: true
69
+ DocumentationBaseURL: https://docs.rubocop.org/rubocop-rails
70
+
71
+ Rails/ActionControllerFlashBeforeRender:
72
+ Description: 'Use `flash.now` instead of `flash` before `render`.'
73
+ StyleGuide: 'https://rails.rubystyle.guide/#flash-before-render'
74
+ Reference: 'https://api.rubyonrails.org/classes/ActionController/FlashBeforeRender.html'
75
+ Enabled: 'pending'
76
+ SafeAutoCorrect: false
77
+ VersionAdded: '2.16'
78
+
43
79
  Rails/ActionControllerTestCase:
44
80
  Description: 'Use `ActionDispatch::IntegrationTest` instead of `ActionController::TestCase`.'
45
81
  StyleGuide: 'https://rails.rubystyle.guide/#integration-testing'
46
82
  Reference: 'https://api.rubyonrails.org/classes/ActionController/TestCase.html'
47
83
  Enabled: 'pending'
48
- SafeAutocorrect: false
84
+ SafeAutoCorrect: false
49
85
  VersionAdded: '2.14'
50
86
  Include:
51
87
  - '**/test/**/*.rb'
@@ -62,6 +98,21 @@ Rails/ActionFilter:
62
98
  - app/controllers/**/*.rb
63
99
  - app/mailers/**/*.rb
64
100
 
101
+ Rails/ActionOrder:
102
+ Description: 'Enforce consistent ordering of controller actions.'
103
+ Enabled: pending
104
+ VersionAdded: '2.17'
105
+ ExpectedOrder:
106
+ - index
107
+ - show
108
+ - new
109
+ - edit
110
+ - create
111
+ - update
112
+ - destroy
113
+ Include:
114
+ - app/controllers/**/*.rb
115
+
65
116
  Rails/ActiveRecordAliases:
66
117
  Description: >-
67
118
  Avoid Active Record aliases:
@@ -96,6 +147,15 @@ Rails/ActiveSupportAliases:
96
147
  Enabled: true
97
148
  VersionAdded: '0.48'
98
149
 
150
+ Rails/ActiveSupportOnLoad:
151
+ Description: 'Use `ActiveSupport.on_load(...)` to patch Rails framework classes.'
152
+ Enabled: 'pending'
153
+ Reference:
154
+ - 'https://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html'
155
+ - 'https://guides.rubyonrails.org/engines.html#available-load-hooks'
156
+ SafeAutoCorrect: false
157
+ VersionAdded: '2.16'
158
+
99
159
  Rails/AddColumnIndex:
100
160
  Description: >-
101
161
  Rails migrations don't make use of a given `index` key, but also
@@ -306,10 +366,13 @@ Rails/DynamicFindBy:
306
366
  # The `Whitelist` has been deprecated, Please use `AllowedMethods` instead.
307
367
  Whitelist:
308
368
  - find_by_sql
369
+ - find_by_token_for
309
370
  AllowedMethods:
310
371
  - find_by_sql
372
+ - find_by_token_for
311
373
  AllowedReceivers:
312
374
  - Gem::Specification
375
+ - page # Prevents a warning for `page.find_by_id`. See: https://github.com/rubocop/rubocop-rails/issues/778
313
376
 
314
377
  Rails/EagerEvaluationLogMessage:
315
378
  Description: 'Checks that blocks are used for interpolated strings passed to `Rails.logger.debug`.'
@@ -407,6 +470,14 @@ Rails/FindEach:
407
470
  VersionChanged: '2.9'
408
471
  Include:
409
472
  - app/models/**/*.rb
473
+ AllowedMethods:
474
+ # Methods that don't work well with `find_each`.
475
+ - order
476
+ - limit
477
+ - select
478
+ - lock
479
+ AllowedPatterns: []
480
+ # Deprecated.
410
481
  IgnoredMethods:
411
482
  # Methods that don't work well with `find_each`.
412
483
  - order
@@ -414,6 +485,13 @@ Rails/FindEach:
414
485
  - select
415
486
  - lock
416
487
 
488
+ Rails/FreezeTime:
489
+ Description: 'Prefer `freeze_time` over `travel_to` with an argument of the current time.'
490
+ StyleGuide: 'https://rails.rubystyle.guide/#freeze-time'
491
+ Enabled: pending
492
+ VersionAdded: '2.16'
493
+ SafeAutoCorrect: false
494
+
417
495
  Rails/HasAndBelongsToMany:
418
496
  Description: 'Prefer has_many :through to has_and_belongs_to_many.'
419
497
  StyleGuide: 'https://rails.rubystyle.guide#has-many-through'
@@ -462,7 +540,7 @@ Rails/I18nLazyLookup:
462
540
  Enabled: pending
463
541
  VersionAdded: '2.14'
464
542
  Include:
465
- - 'controllers/**/*'
543
+ - 'app/controllers/**/*.rb'
466
544
 
467
545
  Rails/I18nLocaleAssignment:
468
546
  Description: 'Prefer the usage of `I18n.with_locale` instead of manually updating `I18n.locale` value.'
@@ -478,6 +556,13 @@ Rails/I18nLocaleTexts:
478
556
  Enabled: pending
479
557
  VersionAdded: '2.14'
480
558
 
559
+ Rails/IgnoredColumnsAssignment:
560
+ Description: 'Looks for assignments of `ignored_columns` that override previous assignments.'
561
+ StyleGuide: 'https://rails.rubystyle.guide/#append-ignored-columns'
562
+ Enabled: pending
563
+ SafeAutoCorrect: false
564
+ VersionAdded: '2.17'
565
+
481
566
  Rails/IgnoredSkipActionFilterOption:
482
567
  Description: 'Checks that `if` and `only` (or `except`) are not used together as options of `skip_*` action filter.'
483
568
  Reference: 'https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options'
@@ -785,6 +870,12 @@ Rails/RootJoinChain:
785
870
  Enabled: pending
786
871
  VersionAdded: '2.13'
787
872
 
873
+ Rails/RootPathnameMethods:
874
+ Description: 'Use `Rails.root` IO methods instead of passing it to `File`.'
875
+ Enabled: pending
876
+ SafeAutoCorrect: false
877
+ VersionAdded: '2.16'
878
+
788
879
  Rails/RootPublicPath:
789
880
  Description: "Favor `Rails.public_path` over `Rails.root` with `'public'`."
790
881
  Enabled: pending
@@ -937,6 +1028,18 @@ Rails/ToFormattedS:
937
1028
  - to_formatted_s
938
1029
  VersionAdded: '2.15'
939
1030
 
1031
+ Rails/ToSWithArgument:
1032
+ Description: 'Identifies passing any argument to `#to_s`.'
1033
+ Enabled: pending
1034
+ Safe: false
1035
+ VersionAdded: '2.16'
1036
+
1037
+ Rails/TopLevelHashWithIndifferentAccess:
1038
+ Description: 'Identifies top-level `HashWithIndifferentAccess`.'
1039
+ Reference: 'https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#top-level-hashwithindifferentaccess-is-soft-deprecated'
1040
+ Enabled: pending
1041
+ VersionAdded: '2.16'
1042
+
940
1043
  Rails/TransactionExitStatement:
941
1044
  Description: 'Avoid the usage of `return`, `break` and `throw` in transaction blocks.'
942
1045
  Enabled: pending
@@ -1003,12 +1106,29 @@ Rails/WhereExists:
1003
1106
  VersionAdded: '2.7'
1004
1107
  VersionChanged: '2.10'
1005
1108
 
1109
+ Rails/WhereMissing:
1110
+ Description: 'Use `where.missing(...)` to find missing relationship records.'
1111
+ StyleGuide: 'https://rails.rubystyle.guide/#finding-missing-relationship-records'
1112
+ Enabled: pending
1113
+ VersionAdded: '2.16'
1114
+
1006
1115
  Rails/WhereNot:
1007
1116
  Description: 'Use `where.not(...)` instead of manually constructing negated SQL in `where`.'
1008
1117
  StyleGuide: 'https://rails.rubystyle.guide/#hash-conditions'
1009
1118
  Enabled: 'pending'
1010
1119
  VersionAdded: '2.8'
1011
1120
 
1121
+ Rails/WhereNotWithMultipleConditions:
1122
+ Description: 'Do not use `where.not(...)` with multiple conditions.'
1123
+ Enabled: 'pending'
1124
+ VersionAdded: '2.17'
1125
+
1012
1126
  # Accept `redirect_to(...) and return` and similar cases.
1013
1127
  Style/AndOr:
1014
1128
  EnforcedStyle: conditionals
1129
+
1130
+ Style/SymbolProc:
1131
+ AllowedMethods:
1132
+ - define_method
1133
+ - mail
1134
+ - respond_to
@@ -5,3 +5,13 @@
5
5
  #
6
6
  extracted:
7
7
  Rails/*: ~
8
+
9
+ # Cop parameters that have been changed
10
+ # Can be treated as a warning instead of a failure with `severity: warning`
11
+ changed_parameters:
12
+ - cops: Rails/FindEach
13
+ parameters: IgnoredMethods
14
+ alternatives:
15
+ - AllowedMethods
16
+ - AllowedPatterns
17
+ severity: warning
@@ -10,8 +10,8 @@ module RuboCop
10
10
 
11
11
  def_node_matcher :active_record?, <<~PATTERN
12
12
  {
13
- (const nil? :ApplicationRecord)
14
- (const (const nil? :ActiveRecord) :Base)
13
+ (const {nil? cbase} :ApplicationRecord)
14
+ (const (const {nil? cbase} :ActiveRecord) :Base)
15
15
  }
16
16
  PATTERN
17
17
 
@@ -48,10 +48,7 @@ module RuboCop
48
48
 
49
49
  class_nodes = class_node.defined_module.each_node
50
50
  namespaces = class_node.each_ancestor(:class, :module).map(&:identifier)
51
- [*class_nodes, *namespaces]
52
- .reverse
53
- .map { |node| node.children[1] }.join('_')
54
- .tableize
51
+ [*class_nodes, *namespaces].reverse.map { |node| node.children[1] }.join('_').tableize
55
52
  end
56
53
 
57
54
  # Resolve relation into column name.
@@ -10,9 +10,7 @@ module RuboCop
10
10
  bigint binary boolean date datetime decimal float integer json string
11
11
  text time timestamp virtual
12
12
  ].freeze
13
- RAILS_ABSTRACT_SCHEMA_DEFINITIONS_HELPERS = %i[
14
- column references belongs_to primary_key numeric
15
- ].freeze
13
+ RAILS_ABSTRACT_SCHEMA_DEFINITIONS_HELPERS = %i[column references belongs_to primary_key numeric].freeze
16
14
  POSTGRES_SCHEMA_DEFINITIONS = %i[
17
15
  bigserial bit bit_varying cidr citext daterange hstore inet interval
18
16
  int4range int8range jsonb ltree macaddr money numrange oid point line
@@ -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) # rubocop:todo InternalAffairs/NumblockHandler
10
10
  on_bad_each_with_object(node) do |*match|
11
11
  handle_possible_offense(node, match, 'each_with_object')
12
12
  end
@@ -98,10 +98,7 @@ module RuboCop
98
98
 
99
99
  captures = extract_captures(correction.match)
100
100
  correction.set_new_arg_name(captures.transformed_argname, corrector)
101
- correction.set_new_body_expression(
102
- captures.transforming_body_expr,
103
- corrector
104
- )
101
+ correction.set_new_body_expression(captures.transforming_body_expr, corrector)
105
102
  end
106
103
 
107
104
  # Internal helper class to hold match data
@@ -110,8 +107,7 @@ module RuboCop
110
107
  :transforming_body_expr
111
108
  ) do
112
109
  def noop_transformation?
113
- transforming_body_expr.lvar_type? &&
114
- transforming_body_expr.children == [transformed_argname]
110
+ transforming_body_expr.lvar_type? && transforming_body_expr.children == [transformed_argname]
115
111
  end
116
112
  end
117
113
 
@@ -138,7 +134,7 @@ module RuboCop
138
134
  end
139
135
 
140
136
  def self.from_hash_brackets_map(node, match)
141
- new(match, node.children.last, 'Hash['.length, ']'.length)
137
+ new(match, node.children.last, "#{node.receiver.source}[".length, ']'.length)
142
138
  end
143
139
 
144
140
  def strip_prefix_and_suffix(node, corrector)
@@ -157,17 +153,11 @@ module RuboCop
157
153
  end
158
154
 
159
155
  def set_new_arg_name(transformed_argname, corrector)
160
- corrector.replace(
161
- block_node.arguments.loc.expression,
162
- "|#{transformed_argname}|"
163
- )
156
+ corrector.replace(block_node.arguments.loc.expression, "|#{transformed_argname}|")
164
157
  end
165
158
 
166
159
  def set_new_body_expression(transforming_body_expr, corrector)
167
- corrector.replace(
168
- block_node.body.loc.expression,
169
- transforming_body_expr.loc.expression.source
170
- )
160
+ corrector.replace(block_node.body.loc.expression, transforming_body_expr.loc.expression.source)
171
161
  end
172
162
  end
173
163
  end
@@ -8,7 +8,7 @@ module RuboCop
8
8
 
9
9
  def_node_matcher :migration_class?, <<~PATTERN
10
10
  (class
11
- (const nil? _)
11
+ (const {nil? cbase} _)
12
12
  (send
13
13
  (const (const {nil? cbase} :ActiveRecord) :Migration)
14
14
  :[]
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Using `flash` assignment before `render` in Rails controllers will persist the message for too long.
7
+ # Check https://guides.rubyonrails.org/action_controller_overview.html#flash-now
8
+ #
9
+ # @safety
10
+ # This cop's autocorrection is unsafe because it replaces `flash` by `flash.now`.
11
+ # Even though it is usually a mistake, it might be used intentionally.
12
+ #
13
+ # @example
14
+ #
15
+ # # bad
16
+ # class HomeController < ApplicationController
17
+ # def create
18
+ # flash[:alert] = "msg"
19
+ # render :index
20
+ # end
21
+ # end
22
+ #
23
+ # # good
24
+ # class HomeController < ApplicationController
25
+ # def create
26
+ # flash.now[:alert] = "msg"
27
+ # render :index
28
+ # end
29
+ # end
30
+ #
31
+ class ActionControllerFlashBeforeRender < Base
32
+ extend AutoCorrector
33
+
34
+ MSG = 'Use `flash.now` before `render`.'
35
+
36
+ def_node_search :flash_assignment?, <<~PATTERN
37
+ ^(send (send nil? :flash) :[]= ...)
38
+ PATTERN
39
+
40
+ def_node_search :render?, <<~PATTERN
41
+ (send nil? :render ...)
42
+ PATTERN
43
+
44
+ def_node_search :action_controller?, <<~PATTERN
45
+ {
46
+ (const {nil? cbase} :ApplicationController)
47
+ (const (const {nil? cbase} :ActionController) :Base)
48
+ }
49
+ PATTERN
50
+
51
+ RESTRICT_ON_SEND = [:flash].freeze
52
+
53
+ def on_send(flash_node)
54
+ return unless flash_assignment?(flash_node)
55
+
56
+ return unless followed_by_render?(flash_node)
57
+
58
+ return unless instance_method_or_block?(flash_node)
59
+
60
+ return unless inherit_action_controller_base?(flash_node)
61
+
62
+ add_offense(flash_node) do |corrector|
63
+ corrector.replace(flash_node, 'flash.now')
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def followed_by_render?(flash_node)
70
+ flash_assigment_node = find_ancestor(flash_node, type: :send)
71
+ context = flash_assigment_node
72
+ if (if_node = context.each_ancestor(:if).first)
73
+ context = if_node
74
+ elsif context.right_siblings.empty?
75
+ return true
76
+ end
77
+ context = context.right_siblings
78
+
79
+ context.compact.any? do |node|
80
+ render?(node)
81
+ end
82
+ end
83
+
84
+ def inherit_action_controller_base?(node)
85
+ class_node = find_ancestor(node, type: :class)
86
+ return unless class_node
87
+
88
+ action_controller?(class_node)
89
+ end
90
+
91
+ def instance_method_or_block?(node)
92
+ def_node = find_ancestor(node, type: :def)
93
+ block_node = find_ancestor(node, type: :block)
94
+
95
+ def_node || block_node
96
+ end
97
+
98
+ def find_ancestor(node, type:)
99
+ node.each_ancestor(type).first
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -30,8 +30,8 @@ module RuboCop
30
30
 
31
31
  def_node_matcher :action_controller_test_case?, <<~PATTERN
32
32
  (class
33
- (const nil? _)
34
- (const (const {nil? cbase} :ActionController) :TestCase) nil?)
33
+ (const {nil? cbase} _)
34
+ (const (const {nil? cbase} :ActionController) :TestCase) _)
35
35
  PATTERN
36
36
 
37
37
  def on_class(node)
@@ -69,7 +69,7 @@ module RuboCop
69
69
 
70
70
  RESTRICT_ON_SEND = FILTER_METHODS + ACTION_METHODS
71
71
 
72
- def on_block(node)
72
+ def on_block(node) # rubocop:disable InternalAffairs/NumblockHandler
73
73
  check_method_node(node.send_node)
74
74
  end
75
75
 
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Enforces consistent ordering of the standard Rails RESTful controller actions.
7
+ #
8
+ # The cop is configurable and can enforce any ordering of the standard actions.
9
+ # All other methods are ignored. So, the actions specified in `ExpectedOrder` should be
10
+ # defined before actions not specified.
11
+ #
12
+ # [source,yaml]
13
+ # ----
14
+ # Rails/ActionOrder:
15
+ # ExpectedOrder:
16
+ # - index
17
+ # - show
18
+ # - new
19
+ # - edit
20
+ # - create
21
+ # - update
22
+ # - destroy
23
+ # ----
24
+ #
25
+ # @example
26
+ # # bad
27
+ # def index; end
28
+ # def destroy; end
29
+ # def show; end
30
+ #
31
+ # # good
32
+ # def index; end
33
+ # def show; end
34
+ # def destroy; end
35
+ class ActionOrder < Base
36
+ extend AutoCorrector
37
+ include VisibilityHelp
38
+ include DefNode
39
+ include RangeHelp
40
+
41
+ MSG = 'Action `%<current>s` should appear before `%<previous>s`.'
42
+
43
+ def_node_search :action_declarations, '(def {%1} ...)'
44
+
45
+ def on_class(node)
46
+ action_declarations(node, actions).each_cons(2) do |previous, current|
47
+ next if node_visibility(current) != :public || non_public?(current)
48
+ next if find_index(current) >= find_index(previous)
49
+
50
+ register_offense(previous, current)
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ def expected_order
57
+ cop_config['ExpectedOrder'].map(&:to_sym)
58
+ end
59
+
60
+ def actions
61
+ @actions ||= Set.new(expected_order)
62
+ end
63
+
64
+ def find_index(node)
65
+ expected_order.find_index(node.method_name)
66
+ end
67
+
68
+ def register_offense(previous, current)
69
+ message = format(
70
+ MSG,
71
+ expected_order: expected_order.join(', '),
72
+ previous: previous.method_name,
73
+ current: current.method_name
74
+ )
75
+ add_offense(current, message: message) do |corrector|
76
+ current = correction_target(current)
77
+ previous = correction_target(previous)
78
+
79
+ swap_range(corrector, current, previous)
80
+ end
81
+ end
82
+
83
+ def correction_target(def_node)
84
+ range_with_comments_and_lines(def_node.each_ancestor(:if).first || def_node)
85
+ end
86
+
87
+ def add_range(range1, range2)
88
+ range1.with(
89
+ begin_pos: [range1.begin_pos, range2.begin_pos].min,
90
+ end_pos: [range1.end_pos, range2.end_pos].max
91
+ )
92
+ end
93
+
94
+ def range_with_comments(node)
95
+ ranges = [
96
+ node,
97
+ *processed_source.ast_with_comments[node]
98
+ ].map do |element|
99
+ element.location.expression
100
+ end
101
+ ranges.reduce do |result, range|
102
+ add_range(result, range)
103
+ end
104
+ end
105
+
106
+ def range_with_comments_and_lines(node)
107
+ range_by_whole_lines(range_with_comments(node), include_final_newline: true)
108
+ end
109
+
110
+ def swap_range(corrector, range1, range2)
111
+ corrector.insert_before(range2, range1.source)
112
+ corrector.remove(range1)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -21,10 +21,7 @@ module RuboCop
21
21
 
22
22
  MSG = 'Use `%<prefer>s` instead of `%<current>s`.'
23
23
 
24
- ALIASES = {
25
- update_attributes: :update,
26
- update_attributes!: :update!
27
- }.freeze
24
+ ALIASES = { update_attributes: :update, update_attributes!: :update! }.freeze
28
25
 
29
26
  RESTRICT_ON_SEND = ALIASES.keys.freeze
30
27
 
@@ -25,12 +25,9 @@ module RuboCop
25
25
  # end
26
26
  #
27
27
  class ActiveRecordOverride < Base
28
- MSG =
29
- 'Use %<prefer>s callbacks instead of overriding the Active Record ' \
30
- 'method `%<bad>s`.'
28
+ MSG = 'Use %<prefer>s callbacks instead of overriding the Active Record method `%<bad>s`.'
31
29
  BAD_METHODS = %i[create destroy save update].freeze
32
- ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base
33
- ActiveRecord::Base].freeze
30
+ ACTIVE_RECORD_CLASSES = %w[ApplicationRecord ActiveModel::Base ActiveRecord::Base].freeze
34
31
 
35
32
  def on_def(node)
36
33
  return unless BAD_METHODS.include?(node.method_name)