rubocop-rails 2.14.2 → 2.19.1

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.
Files changed (142) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +23 -2
  4. data/config/default.yml +190 -12
  5. data/config/obsoletion.yml +10 -0
  6. data/lib/rubocop/cop/mixin/active_record_helper.rb +3 -6
  7. data/lib/rubocop/cop/mixin/active_record_migrations_helper.rb +1 -3
  8. data/lib/rubocop/cop/mixin/enforce_superclass.rb +1 -1
  9. data/lib/rubocop/cop/mixin/index_method.rb +7 -17
  10. data/lib/rubocop/cop/mixin/migrations_helper.rb +1 -1
  11. data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +112 -0
  12. data/lib/rubocop/cop/rails/action_controller_test_case.rb +2 -2
  13. data/lib/rubocop/cop/rails/action_filter.rb +2 -2
  14. data/lib/rubocop/cop/rails/action_order.rb +116 -0
  15. data/lib/rubocop/cop/rails/active_record_aliases.rb +3 -4
  16. data/lib/rubocop/cop/rails/active_record_callbacks_order.rb +7 -4
  17. data/lib/rubocop/cop/rails/active_record_override.rb +2 -5
  18. data/lib/rubocop/cop/rails/active_support_aliases.rb +1 -1
  19. data/lib/rubocop/cop/rails/active_support_on_load.rb +70 -0
  20. data/lib/rubocop/cop/rails/add_column_index.rb +3 -6
  21. data/lib/rubocop/cop/rails/after_commit_override.rb +1 -1
  22. data/lib/rubocop/cop/rails/application_controller.rb +2 -2
  23. data/lib/rubocop/cop/rails/application_job.rb +3 -3
  24. data/lib/rubocop/cop/rails/application_mailer.rb +2 -2
  25. data/lib/rubocop/cop/rails/application_record.rb +2 -2
  26. data/lib/rubocop/cop/rails/arel_star.rb +2 -2
  27. data/lib/rubocop/cop/rails/assert_not.rb +1 -1
  28. data/lib/rubocop/cop/rails/attribute_default_block_value.rb +1 -1
  29. data/lib/rubocop/cop/rails/belongs_to.rb +2 -5
  30. data/lib/rubocop/cop/rails/blank.rb +10 -11
  31. data/lib/rubocop/cop/rails/bulk_change_table.rb +8 -25
  32. data/lib/rubocop/cop/rails/compact_blank.rb +6 -2
  33. data/lib/rubocop/cop/rails/content_tag.rb +6 -7
  34. data/lib/rubocop/cop/rails/create_table_with_timestamps.rb +16 -3
  35. data/lib/rubocop/cop/rails/date.rb +12 -17
  36. data/lib/rubocop/cop/rails/default_scope.rb +1 -1
  37. data/lib/rubocop/cop/rails/delegate.rb +24 -18
  38. data/lib/rubocop/cop/rails/delegate_allow_blank.rb +2 -2
  39. data/lib/rubocop/cop/rails/deprecated_active_model_errors_methods.rb +63 -3
  40. data/lib/rubocop/cop/rails/dot_separated_keys.rb +71 -0
  41. data/lib/rubocop/cop/rails/duplicate_association.rb +2 -2
  42. data/lib/rubocop/cop/rails/duplicate_scope.rb +1 -1
  43. data/lib/rubocop/cop/rails/duration_arithmetic.rb +4 -4
  44. data/lib/rubocop/cop/rails/dynamic_find_by.rb +26 -14
  45. data/lib/rubocop/cop/rails/eager_evaluation_log_message.rb +6 -2
  46. data/lib/rubocop/cop/rails/enum_hash.rb +3 -4
  47. data/lib/rubocop/cop/rails/enum_uniqueness.rb +3 -6
  48. data/lib/rubocop/cop/rails/environment_comparison.rb +3 -4
  49. data/lib/rubocop/cop/rails/environment_variable_access.rb +1 -1
  50. data/lib/rubocop/cop/rails/exit.rb +1 -1
  51. data/lib/rubocop/cop/rails/expanded_date_range.rb +39 -23
  52. data/lib/rubocop/cop/rails/file_path.rb +41 -24
  53. data/lib/rubocop/cop/rails/find_by.rb +1 -1
  54. data/lib/rubocop/cop/rails/find_by_id.rb +3 -3
  55. data/lib/rubocop/cop/rails/find_each.rb +14 -4
  56. data/lib/rubocop/cop/rails/freeze_time.rb +79 -0
  57. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +1 -1
  58. data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +14 -8
  59. data/lib/rubocop/cop/rails/helper_instance_variable.rb +3 -3
  60. data/lib/rubocop/cop/rails/http_positional_arguments.rb +23 -12
  61. data/lib/rubocop/cop/rails/http_status.rb +6 -11
  62. data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +3 -1
  63. data/lib/rubocop/cop/rails/i18n_locale_assignment.rb +1 -1
  64. data/lib/rubocop/cop/rails/i18n_locale_texts.rb +2 -2
  65. data/lib/rubocop/cop/rails/ignored_columns_assignment.rb +50 -0
  66. data/lib/rubocop/cop/rails/ignored_skip_action_filter_option.rb +5 -14
  67. data/lib/rubocop/cop/rails/index_by.rb +2 -2
  68. data/lib/rubocop/cop/rails/index_with.rb +2 -2
  69. data/lib/rubocop/cop/rails/inquiry.rb +1 -1
  70. data/lib/rubocop/cop/rails/inverse_of.rb +4 -10
  71. data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +22 -16
  72. data/lib/rubocop/cop/rails/link_to_blank.rb +2 -5
  73. data/lib/rubocop/cop/rails/mailer_name.rb +5 -5
  74. data/lib/rubocop/cop/rails/match_route.rb +1 -1
  75. data/lib/rubocop/cop/rails/migration_class_name.rb +2 -2
  76. data/lib/rubocop/cop/rails/negate_include.rb +2 -2
  77. data/lib/rubocop/cop/rails/not_null_column.rb +10 -7
  78. data/lib/rubocop/cop/rails/order_by_id.rb +2 -3
  79. data/lib/rubocop/cop/rails/output.rb +7 -9
  80. data/lib/rubocop/cop/rails/output_safety.rb +6 -2
  81. data/lib/rubocop/cop/rails/pick.rb +1 -1
  82. data/lib/rubocop/cop/rails/pluck.rb +45 -13
  83. data/lib/rubocop/cop/rails/pluck_id.rb +2 -2
  84. data/lib/rubocop/cop/rails/pluck_in_where.rb +1 -1
  85. data/lib/rubocop/cop/rails/pluralization_grammar.rb +2 -3
  86. data/lib/rubocop/cop/rails/presence.rb +22 -13
  87. data/lib/rubocop/cop/rails/present.rb +10 -13
  88. data/lib/rubocop/cop/rails/rake_environment.rb +3 -3
  89. data/lib/rubocop/cop/rails/read_write_attribute.rb +2 -2
  90. data/lib/rubocop/cop/rails/redundant_allow_nil.rb +5 -7
  91. data/lib/rubocop/cop/rails/redundant_foreign_key.rb +3 -3
  92. data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +3 -3
  93. data/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +31 -27
  94. data/lib/rubocop/cop/rails/redundant_travel_back.rb +1 -1
  95. data/lib/rubocop/cop/rails/reflection_class_name.rb +35 -2
  96. data/lib/rubocop/cop/rails/refute_methods.rb +1 -5
  97. data/lib/rubocop/cop/rails/relative_date_constant.rb +5 -8
  98. data/lib/rubocop/cop/rails/render_inline.rb +1 -1
  99. data/lib/rubocop/cop/rails/render_plain_text.rb +1 -1
  100. data/lib/rubocop/cop/rails/request_referer.rb +2 -3
  101. data/lib/rubocop/cop/rails/require_dependency.rb +2 -2
  102. data/lib/rubocop/cop/rails/response_parsed_body.rb +57 -0
  103. data/lib/rubocop/cop/rails/reversible_migration.rb +15 -63
  104. data/lib/rubocop/cop/rails/reversible_migration_method_definition.rb +5 -6
  105. data/lib/rubocop/cop/rails/root_join_chain.rb +1 -1
  106. data/lib/rubocop/cop/rails/root_pathname_methods.rb +238 -0
  107. data/lib/rubocop/cop/rails/root_public_path.rb +59 -0
  108. data/lib/rubocop/cop/rails/safe_navigation.rb +8 -13
  109. data/lib/rubocop/cop/rails/safe_navigation_with_blank.rb +2 -4
  110. data/lib/rubocop/cop/rails/save_bang.rb +12 -24
  111. data/lib/rubocop/cop/rails/schema_comment.rb +1 -1
  112. data/lib/rubocop/cop/rails/scope_args.rb +1 -1
  113. data/lib/rubocop/cop/rails/short_i18n.rb +3 -6
  114. data/lib/rubocop/cop/rails/skips_model_validations.rb +3 -4
  115. data/lib/rubocop/cop/rails/squished_sql_heredocs.rb +10 -7
  116. data/lib/rubocop/cop/rails/strip_heredoc.rb +56 -0
  117. data/lib/rubocop/cop/rails/table_name_assignment.rb +1 -1
  118. data/lib/rubocop/cop/rails/three_state_boolean_column.rb +73 -0
  119. data/lib/rubocop/cop/rails/time_zone.rb +34 -32
  120. data/lib/rubocop/cop/rails/time_zone_assignment.rb +4 -4
  121. data/lib/rubocop/cop/rails/to_formatted_s.rb +46 -0
  122. data/lib/rubocop/cop/rails/to_s_with_argument.rb +78 -0
  123. data/lib/rubocop/cop/rails/top_level_hash_with_indifferent_access.rb +49 -0
  124. data/lib/rubocop/cop/rails/transaction_exit_statement.rb +17 -12
  125. data/lib/rubocop/cop/rails/uniq_before_pluck.rb +3 -6
  126. data/lib/rubocop/cop/rails/unique_validation_without_index.rb +14 -7
  127. data/lib/rubocop/cop/rails/unknown_env.rb +3 -5
  128. data/lib/rubocop/cop/rails/unused_ignored_columns.rb +7 -2
  129. data/lib/rubocop/cop/rails/validation.rb +5 -13
  130. data/lib/rubocop/cop/rails/where_equals.rb +2 -2
  131. data/lib/rubocop/cop/rails/where_exists.rb +3 -3
  132. data/lib/rubocop/cop/rails/where_missing.rb +118 -0
  133. data/lib/rubocop/cop/rails/where_not.rb +2 -2
  134. data/lib/rubocop/cop/rails/where_not_with_multiple_conditions.rb +55 -0
  135. data/lib/rubocop/cop/rails_cops.rb +16 -0
  136. data/lib/rubocop/rails/schema_loader/schema.rb +8 -5
  137. data/lib/rubocop/rails/version.rb +1 -1
  138. data/lib/rubocop/rails.rb +1 -1
  139. data/lib/rubocop-rails.rb +19 -0
  140. metadata +23 -9
  141. data/bin/console +0 -11
  142. data/bin/setup +0 -7
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop looks for `has_many` or `has_one` associations that don't
6
+ # Looks for `has_many` or `has_one` associations that don't
7
7
  # specify a `:dependent` option.
8
8
  #
9
9
  # It doesn't register an offense if `:through` or `dependent: nil`
@@ -37,15 +37,15 @@ module RuboCop
37
37
  RESTRICT_ON_SEND = %i[has_many has_one].freeze
38
38
 
39
39
  def_node_search :active_resource_class?, <<~PATTERN
40
- (const (const nil? :ActiveResource) :Base)
40
+ (const (const {nil? cbase} :ActiveResource) :Base)
41
41
  PATTERN
42
42
 
43
43
  def_node_matcher :association_without_options?, <<~PATTERN
44
- (send nil? {:has_many :has_one} _)
44
+ (send _ {:has_many :has_one} _)
45
45
  PATTERN
46
46
 
47
47
  def_node_matcher :association_with_options?, <<~PATTERN
48
- (send nil? {:has_many :has_one} ... (hash $...))
48
+ (send _ {:has_many :has_one} ... (hash $...))
49
49
  PATTERN
50
50
 
51
51
  def_node_matcher :dependent_option?, <<~PATTERN
@@ -105,9 +105,7 @@ module RuboCop
105
105
 
106
106
  return false unless node.parent
107
107
 
108
- return true if contain_valid_options_in_with_options_block?(
109
- node.parent.parent
110
- )
108
+ return true if contain_valid_options_in_with_options_block?(node.parent.parent)
111
109
  end
112
110
 
113
111
  false
@@ -116,7 +114,7 @@ module RuboCop
116
114
  def valid_options?(options)
117
115
  return false if options.nil?
118
116
 
119
- options = options.first.children.first.pairs if options.first.kwsplat_type?
117
+ options = extract_option_if_kwsplat(options)
120
118
 
121
119
  return true unless options
122
120
  return true if options.any? do |o|
@@ -126,6 +124,14 @@ module RuboCop
126
124
  false
127
125
  end
128
126
 
127
+ def extract_option_if_kwsplat(options)
128
+ if options.first.kwsplat_type? && options.first.children.first.hash_type?
129
+ return options.first.children.first.pairs
130
+ end
131
+
132
+ options
133
+ end
134
+
129
135
  def active_resource?(node)
130
136
  return false if node.nil?
131
137
 
@@ -3,14 +3,14 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for use of the helper methods which reference
6
+ # Checks for use of the helper methods which reference
7
7
  # instance variables.
8
8
  #
9
9
  # Relying on instance variables makes it difficult to re-use helper
10
10
  # methods.
11
11
  #
12
12
  # If it seems awkward to explicitly pass in each dependent
13
- # variable, consider moving the behaviour elsewhere, for
13
+ # variable, consider moving the behavior elsewhere, for
14
14
  # example to a model, decorator or presenter.
15
15
  #
16
16
  # Provided that a class inherits `ActionView::Helpers::FormBuilder`,
@@ -37,7 +37,7 @@ module RuboCop
37
37
  def_node_matcher :form_builder_class?, <<~PATTERN
38
38
  (const
39
39
  (const
40
- (const nil? :ActionView) :Helpers) :FormBuilder)
40
+ (const {nil? cbase} :ActionView) :Helpers) :FormBuilder)
41
41
  PATTERN
42
42
 
43
43
  def on_ivar(node)
@@ -3,13 +3,16 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop is used to identify usages of http methods like `get`, `post`,
6
+ # Identifies usages of http methods like `get`, `post`,
7
7
  # `put`, `patch` without the usage of keyword arguments in your tests and
8
8
  # change them to use keyword args. This cop only applies to Rails >= 5.
9
9
  # If you are running Rails < 5 you should disable the
10
10
  # Rails/HttpPositionalArguments cop or set your TargetRailsVersion in your
11
11
  # .rubocop.yml file to 4.2.
12
12
  #
13
+ # NOTE: It does not detect any cases where `include Rack::Test::Methods` is used
14
+ # which makes the http methods incompatible behavior.
15
+ #
13
16
  # @example
14
17
  # # bad
15
18
  # get :new, { user_id: 1}
@@ -22,11 +25,8 @@ module RuboCop
22
25
  extend AutoCorrector
23
26
  extend TargetRailsVersion
24
27
 
25
- MSG = 'Use keyword arguments instead of ' \
26
- 'positional arguments for http call: `%<verb>s`.'
27
- KEYWORD_ARGS = %i[
28
- method params session body flash xhr as headers env to
29
- ].freeze
28
+ MSG = 'Use keyword arguments instead of positional arguments for http call: `%<verb>s`.'
29
+ KEYWORD_ARGS = %i[method params session body flash xhr as headers env to].freeze
30
30
  ROUTING_METHODS = %i[draw routes].freeze
31
31
  RESTRICT_ON_SEND = %i[get post put patch delete head].freeze
32
32
 
@@ -40,8 +40,15 @@ module RuboCop
40
40
  (hash (kwsplat _))
41
41
  PATTERN
42
42
 
43
+ def_node_matcher :include_rack_test_methods?, <<~PATTERN
44
+ (send nil? :include
45
+ (const
46
+ (const
47
+ (const {nil? cbase} :Rack) :Test) :Methods))
48
+ PATTERN
49
+
43
50
  def on_send(node)
44
- return if in_routing_block?(node)
51
+ return if in_routing_block?(node) || use_rack_test_methods?
45
52
 
46
53
  http_request?(node) do |data|
47
54
  return unless needs_conversion?(data)
@@ -59,7 +66,7 @@ module RuboCop
59
66
  # that represents the path/action on the Rails controller
60
67
  # the data is the http parameters and environment sent in
61
68
  # the Rails 5 http call
62
- corrector.replace(node.loc.expression, correction(node))
69
+ corrector.replace(node, correction(node))
63
70
  end
64
71
  end
65
72
  end
@@ -70,13 +77,18 @@ module RuboCop
70
77
  !!node.each_ancestor(:block).detect { |block| ROUTING_METHODS.include?(block.method_name) }
71
78
  end
72
79
 
80
+ def use_rack_test_methods?
81
+ processed_source.ast.each_descendant(:send).any? do |node|
82
+ include_rack_test_methods?(node)
83
+ end
84
+ end
85
+
73
86
  def needs_conversion?(data)
74
87
  return true unless data.hash_type?
75
88
  return false if kwsplat_hash?(data)
76
89
 
77
90
  data.each_pair.none? do |pair|
78
- special_keyword_arg?(pair.key) ||
79
- (format_arg?(pair.key) && data.pairs.one?)
91
+ special_keyword_arg?(pair.key) || (format_arg?(pair.key) && data.pairs.one?)
80
92
  end
81
93
  end
82
94
 
@@ -98,8 +110,7 @@ module RuboCop
98
110
  return '' if data.hash_type? && data.empty?
99
111
 
100
112
  hash_data = if data.hash_type?
101
- format('{ %<data>s }',
102
- data: data.pairs.map(&:source).join(', '))
113
+ format('{ %<data>s }', data: data.pairs.map(&:source).join(', '))
103
114
  else
104
115
  # user supplies an object,
105
116
  # no need to surround with braces
@@ -66,7 +66,7 @@ module RuboCop
66
66
  return unless checker.offensive?
67
67
 
68
68
  add_offense(checker.node, message: checker.message) do |corrector|
69
- corrector.replace(checker.node.loc.expression, checker.preferred_style)
69
+ corrector.replace(checker.node, checker.preferred_style)
70
70
  end
71
71
  end
72
72
  end
@@ -84,10 +84,8 @@ module RuboCop
84
84
 
85
85
  # :nodoc:
86
86
  class SymbolicStyleChecker
87
- MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
88
- 'to define HTTP status code.'
89
- DEFAULT_MSG = 'Prefer `symbolic` over `numeric` ' \
90
- 'to define HTTP status code.'
87
+ MSG = 'Prefer `%<prefer>s` over `%<current>s` to define HTTP status code.'
88
+ DEFAULT_MSG = 'Prefer `symbolic` over `numeric` to define HTTP status code.'
91
89
 
92
90
  attr_reader :node
93
91
 
@@ -118,17 +116,14 @@ module RuboCop
118
116
  end
119
117
 
120
118
  def custom_http_status_code?
121
- node.int_type? &&
122
- !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
119
+ node.int_type? && !::Rack::Utils::SYMBOL_TO_STATUS_CODE.value?(number)
123
120
  end
124
121
  end
125
122
 
126
123
  # :nodoc:
127
124
  class NumericStyleChecker
128
- MSG = 'Prefer `%<prefer>s` over `%<current>s` ' \
129
- 'to define HTTP status code.'
130
- DEFAULT_MSG = 'Prefer `numeric` over `symbolic` ' \
131
- 'to define HTTP status code.'
125
+ MSG = 'Prefer `%<prefer>s` over `%<current>s` to define HTTP status code.'
126
+ DEFAULT_MSG = 'Prefer `numeric` over `symbolic` to define HTTP status code.'
132
127
  PERMITTED_STATUS = %i[error success missing redirect].freeze
133
128
 
134
129
  attr_reader :node
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for places where I18n "lazy" lookup can be used.
6
+ # Checks for places where I18n "lazy" lookup can be used.
7
7
  #
8
8
  # @example
9
9
  # # en.yml
@@ -34,6 +34,8 @@ module RuboCop
34
34
 
35
35
  MSG = 'Use "lazy" lookup for the text used in controllers.'
36
36
 
37
+ RESTRICT_ON_SEND = %i[translate t].freeze
38
+
37
39
  def_node_matcher :translate_call?, <<~PATTERN
38
40
  (send nil? {:translate :t} ${sym_type? str_type?} ...)
39
41
  PATTERN
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for the use of `I18n.locale=` method.
6
+ # Checks for the use of `I18n.locale=` method.
7
7
  #
8
8
  # The `locale` attribute persists for the rest of the Ruby runtime, potentially causing
9
9
  # unexpected behavior at a later time.
@@ -69,7 +69,7 @@ module RuboCop
69
69
  class I18nLocaleTexts < Base
70
70
  MSG = 'Move locale texts to the locale files in the `config/locales` directory.'
71
71
 
72
- RESTRICT_ON_SEND = %i[validates redirect_to []= mail].freeze
72
+ RESTRICT_ON_SEND = %i[validates redirect_to redirect_back []= mail].freeze
73
73
 
74
74
  def_node_search :validation_message, <<~PATTERN
75
75
  (pair (sym :message) $str)
@@ -94,7 +94,7 @@ module RuboCop
94
94
  add_offense(text_node)
95
95
  end
96
96
  return
97
- when :redirect_to
97
+ when :redirect_to, :redirect_back
98
98
  text_node = redirect_to_flash(node).to_a.last
99
99
  when :[]=
100
100
  text_node = flash_assignment?(node)
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Rails
6
+ # Looks for assignments of `ignored_columns` that may override previous
7
+ # assignments.
8
+ #
9
+ # Overwriting previous assignments is usually a mistake, since it will
10
+ # un-ignore the first set of columns. Since duplicate column names is not
11
+ # a problem, it is better to simply append to the list.
12
+ #
13
+ # @example
14
+ #
15
+ # # bad
16
+ # class User < ActiveRecord::Base
17
+ # self.ignored_columns = [:one]
18
+ # end
19
+ #
20
+ # # bad
21
+ # class User < ActiveRecord::Base
22
+ # self.ignored_columns = [:one, :two]
23
+ # end
24
+ #
25
+ # # good
26
+ # class User < ActiveRecord::Base
27
+ # self.ignored_columns += [:one, :two]
28
+ # end
29
+ #
30
+ # # good
31
+ # class User < ActiveRecord::Base
32
+ # self.ignored_columns += [:one]
33
+ # self.ignored_columns += [:two]
34
+ # end
35
+ #
36
+ class IgnoredColumnsAssignment < Base
37
+ extend AutoCorrector
38
+
39
+ MSG = 'Use `+=` instead of `=`.'
40
+ RESTRICT_ON_SEND = %i[ignored_columns=].freeze
41
+
42
+ def on_send(node)
43
+ add_offense(node.loc.operator) do |corrector|
44
+ corrector.replace(node.loc.operator, '+=')
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that `if` and `only` (or `except`) are not used together
6
+ # Checks that `if` and `only` (or `except`) are not used together
7
7
  # as options of `skip_*` action filter.
8
8
  #
9
9
  # The `if` option will be ignored when `if` and `only` are used together.
@@ -35,19 +35,12 @@ module RuboCop
35
35
  # skip_before_action :login_required,
36
36
  # if: -> { trusted_origin? && action_name != "admin" }
37
37
  # end
38
- #
39
- # @see https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options
40
38
  class IgnoredSkipActionFilterOption < Base
41
39
  MSG = <<~MSG.chomp.freeze
42
40
  `%<ignore>s` option will be ignored when `%<prefer>s` and `%<ignore>s` are used together.
43
41
  MSG
44
42
 
45
- RESTRICT_ON_SEND = %i[
46
- skip_after_action
47
- skip_around_action
48
- skip_before_action
49
- skip_action_callback
50
- ].freeze
43
+ RESTRICT_ON_SEND = %i[skip_after_action skip_around_action skip_before_action skip_action_callback].freeze
51
44
 
52
45
  FILTERS = RESTRICT_ON_SEND.map { |method_name| ":#{method_name}" }
53
46
 
@@ -67,11 +60,9 @@ module RuboCop
67
60
  options = options_hash(options)
68
61
 
69
62
  if if_and_only?(options)
70
- add_offense(options[:if],
71
- message: format(MSG, prefer: :only, ignore: :if))
63
+ add_offense(options[:if], message: format(MSG, prefer: :only, ignore: :if))
72
64
  elsif if_and_except?(options)
73
- add_offense(options[:except],
74
- message: format(MSG, prefer: :if, ignore: :except))
65
+ add_offense(options[:except], message: format(MSG, prefer: :if, ignore: :except))
75
66
  end
76
67
  end
77
68
 
@@ -80,7 +71,7 @@ module RuboCop
80
71
  def options_hash(options)
81
72
  options.pairs
82
73
  .select { |pair| pair.key.sym_type? }
83
- .map { |pair| [pair.key.value, pair] }.to_h
74
+ .to_h { |pair| [pair.key.value, pair] }
84
75
  end
85
76
 
86
77
  def if_and_only?(options)
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop looks for uses of `each_with_object({}) { ... }`,
6
+ # Looks for uses of `each_with_object({}) { ... }`,
7
7
  # `map { ... }.to_h`, and `Hash[map { ... }]` that are transforming
8
8
  # an enumerable into a hash where the values are the original elements.
9
9
  # Rails provides the `index_by` method for this purpose.
@@ -46,7 +46,7 @@ module RuboCop
46
46
 
47
47
  def_node_matcher :on_bad_hash_brackets_map, <<~PATTERN
48
48
  (send
49
- (const _ :Hash)
49
+ (const {nil? cbase} :Hash)
50
50
  :[]
51
51
  (block
52
52
  (call _ {:map :collect})
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop looks for uses of `each_with_object({}) { ... }`,
6
+ # Looks for uses of `each_with_object({}) { ... }`,
7
7
  # `map { ... }.to_h`, and `Hash[map { ... }]` that are transforming
8
8
  # an enumerable into a hash where the keys are the original elements.
9
9
  # Rails provides the `index_with` method for this purpose.
@@ -49,7 +49,7 @@ module RuboCop
49
49
 
50
50
  def_node_matcher :on_bad_hash_brackets_map, <<~PATTERN
51
51
  (send
52
- (const _ :Hash)
52
+ (const {nil? cbase} :Hash)
53
53
  :[]
54
54
  (block
55
55
  (call _ {:map :collect})
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that Active Support's `inquiry` method is not used.
6
+ # Checks that Active Support's `inquiry` method is not used.
7
7
  #
8
8
  # @example
9
9
  # # bad - String#inquiry
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop looks for has_(one|many) and belongs_to associations where
6
+ # Looks for has_(one|many) and belongs_to associations where
7
7
  # Active Record can't automatically determine the inverse association
8
8
  # because of a scope or the options used. Using the blog with order scope
9
9
  # example below, traversing the a Blog's association in both directions
@@ -137,9 +137,6 @@ module RuboCop
137
137
  # class Blog < ApplicationRecord
138
138
  # has_many :posts, -> { order(published_at: :desc) }
139
139
  # end
140
- #
141
- # @see https://guides.rubyonrails.org/association_basics.html#bi-directional-associations
142
- # @see https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses
143
140
  class InverseOf < Base
144
141
  SPECIFY_MSG = 'Specify an `:inverse_of` option.'
145
142
  NIL_MSG = 'You specified `inverse_of: nil`, you probably meant to use `inverse_of: false`.'
@@ -192,8 +189,7 @@ module RuboCop
192
189
  end
193
190
  return if options_ignoring_inverse_of?(options)
194
191
 
195
- return unless scope?(arguments) ||
196
- options_requiring_inverse_of?(options)
192
+ return unless scope?(arguments) || options_requiring_inverse_of?(options)
197
193
 
198
194
  return if options_contain_inverse_of?(options)
199
195
 
@@ -206,8 +202,7 @@ module RuboCop
206
202
 
207
203
  def options_requiring_inverse_of?(options)
208
204
  required = options.any? do |opt|
209
- conditions_option?(opt) ||
210
- foreign_key_option?(opt)
205
+ conditions_option?(opt) || foreign_key_option?(opt)
211
206
  end
212
207
 
213
208
  return required if target_rails_version >= 5.2
@@ -227,8 +222,7 @@ module RuboCop
227
222
 
228
223
  def with_options_arguments(recv, node)
229
224
  blocks = node.each_ancestor(:block).select do |block|
230
- block.send_node.command?(:with_options) &&
231
- same_context_in_with_options?(block.arguments.first, recv)
225
+ block.send_node.command?(:with_options) && same_context_in_with_options?(block.arguments.first, recv)
232
226
  end
233
227
  blocks.flat_map { |n| n.send_node.arguments }
234
228
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks that methods specified in the filter's `only` or
6
+ # Checks that methods specified in the filter's `only` or
7
7
  # `except` options are defined within the same class or module.
8
8
  #
9
9
  # @safety
@@ -12,7 +12,7 @@ module RuboCop
12
12
  # methods that are defined in other classes or modules, you should
13
13
  # define the filter in that class or module.
14
14
  #
15
- # If you rely on behaviour defined in the superclass actions, you must
15
+ # If you rely on behavior defined in the superclass actions, you must
16
16
  # remember to invoke `super` in the subclass actions.
17
17
  #
18
18
  # @example
@@ -71,7 +71,7 @@ module RuboCop
71
71
  # class ArticlesController < ContentController
72
72
  # before_action :load_article, only: [:update]
73
73
  #
74
- # # the cop requires this method, but it relies on behaviour defined
74
+ # # the cop requires this method, but it relies on behavior defined
75
75
  # # in the superclass, so needs to invoke `super`
76
76
  # def update
77
77
  # super
@@ -144,19 +144,29 @@ module RuboCop
144
144
  end
145
145
 
146
146
  def aliased_action_methods(node, defined_methods)
147
- alias_methods = node.each_child_node(:send).select { |send_node| send_node.method?(:alias_method) }
148
-
149
- hash_of_alias_methods = alias_methods.each_with_object({}) do |alias_method, result|
150
- result[alias_method.last_argument.value] = alias_method.first_argument.value
151
- end
152
-
147
+ alias_methods = alias_methods(node)
153
148
  defined_methods.each_with_object([]) do |defined_method, aliased_method|
154
- if (new_method_name = hash_of_alias_methods[defined_method])
149
+ if (new_method_name = alias_methods[defined_method])
155
150
  aliased_method << new_method_name
156
151
  end
157
152
  end
158
153
  end
159
154
 
155
+ def alias_methods(node)
156
+ result = {}
157
+ node.each_child_node(:send, :alias) do |child_node|
158
+ case child_node.type
159
+ when :send
160
+ if child_node.method?(:alias_method)
161
+ result[child_node.last_argument.value] = child_node.first_argument.value
162
+ end
163
+ when :alias
164
+ result[child_node.old_identifier.value] = child_node.new_identifier.value
165
+ end
166
+ end
167
+ result
168
+ end
169
+
160
170
  # @param node [RuboCop::AST::Node]
161
171
  # @return [Array<Symbol>]
162
172
  def array_values(node) # rubocop:disable Metrics/MethodLength
@@ -184,13 +194,9 @@ module RuboCop
184
194
  # @return [String]
185
195
  def message(methods, parent)
186
196
  if methods.size == 1
187
- format(MSG,
188
- action: "`#{methods[0]}` is",
189
- type: parent.type)
197
+ format(MSG, action: "`#{methods[0]}` is", type: parent.type)
190
198
  else
191
- format(MSG,
192
- action: "`#{methods.join('`, `')}` are",
193
- type: parent.type)
199
+ format(MSG, action: "`#{methods.join('`, `')}` are", type: parent.type)
194
200
  end
195
201
  end
196
202
  end
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop checks for calls to `link_to` that contain a
6
+ # Checks for calls to `link_to` that contain a
7
7
  # `target: '_blank'` but no `rel: 'noopener'`. This can be a security
8
8
  # risk as the loaded page will have control over the previous page
9
9
  # and could change its location for phishing purposes.
@@ -68,10 +68,7 @@ module RuboCop
68
68
 
69
69
  def append_to_rel(rel_node, corrector)
70
70
  existing_rel = rel_node.children.last.value
71
- str_range = rel_node.children.last.loc.expression.adjust(
72
- begin_pos: 1,
73
- end_pos: -1
74
- )
71
+ str_range = rel_node.children.last.source_range.adjust(begin_pos: 1, end_pos: -1)
75
72
  corrector.replace(str_range, "#{existing_rel} noopener")
76
73
  end
77
74
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop enforces that mailer names end with `Mailer` suffix.
6
+ # Enforces that mailer names end with `Mailer` suffix.
7
7
  #
8
8
  # Without the `Mailer` suffix it isn't immediately apparent what's a mailer
9
9
  # and which views are related to the mailer.
@@ -34,8 +34,8 @@ module RuboCop
34
34
 
35
35
  def_node_matcher :mailer_base_class?, <<~PATTERN
36
36
  {
37
- (const (const nil? :ActionMailer) :Base)
38
- (const nil? :ApplicationMailer)
37
+ (const (const {nil? cbase} :ActionMailer) :Base)
38
+ (const {nil? cbase} :ApplicationMailer)
39
39
  }
40
40
  PATTERN
41
41
 
@@ -44,7 +44,7 @@ module RuboCop
44
44
  PATTERN
45
45
 
46
46
  def_node_matcher :class_new_definition?, <<~PATTERN
47
- (send (const nil? :Class) :new #mailer_base_class?)
47
+ (send (const {nil? cbase} :Class) :new #mailer_base_class?)
48
48
  PATTERN
49
49
 
50
50
  def on_class(node)
@@ -77,7 +77,7 @@ module RuboCop
77
77
  corrector.replace(node.loc.name, "#{name}Mailer")
78
78
  else
79
79
  name = node.children.last
80
- corrector.replace(node.source_range, "#{name}Mailer")
80
+ corrector.replace(node, "#{name}Mailer")
81
81
  end
82
82
  end
83
83
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop identifies places where defining routes with `match`
6
+ # Identifies places where defining routes with `match`
7
7
  # can be replaced with a specific HTTP method.
8
8
  #
9
9
  # Don't use `match` to define any routes unless there is a need to map multiple request types
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop makes sure that each migration file defines a migration class
6
+ # Makes sure that each migration file defines a migration class
7
7
  # whose name matches the file name.
8
8
  # (e.g. `20220224111111_create_users.rb` should define `CreateUsers` class.)
9
9
  #
@@ -29,7 +29,7 @@ module RuboCop
29
29
 
30
30
  basename = basename_without_timestamp_and_suffix(processed_source.file_path)
31
31
 
32
- class_identifier = node.identifier
32
+ class_identifier = node.identifier.location.name
33
33
  camelized_basename = camelize(basename)
34
34
  return if class_identifier.source.casecmp(camelized_basename).zero?
35
35
 
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  module Cop
5
5
  module Rails
6
- # This cop enforces the use of `collection.exclude?(obj)`
6
+ # Enforces the use of `collection.exclude?(obj)`
7
7
  # over `!collection.include?(obj)`.
8
8
  #
9
9
  # @safety
@@ -26,7 +26,7 @@ module RuboCop
26
26
  RESTRICT_ON_SEND = %i[!].freeze
27
27
 
28
28
  def_node_matcher :negate_include_call?, <<~PATTERN
29
- (send (send $_ :include? $_) :!)
29
+ (send (send $!nil? :include? $_) :!)
30
30
  PATTERN
31
31
 
32
32
  def on_send(node)