rubocop-rails 2.22.2 → 2.25.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -9
- data/config/default.yml +13 -4
- data/lib/rubocop/cop/mixin/active_record_helper.rb +15 -3
- data/lib/rubocop/cop/mixin/database_type_resolvable.rb +1 -1
- data/lib/rubocop/cop/mixin/target_rails_version.rb +29 -2
- data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +2 -0
- data/lib/rubocop/cop/rails/active_support_aliases.rb +6 -5
- data/lib/rubocop/cop/rails/active_support_on_load.rb +21 -1
- data/lib/rubocop/cop/rails/bulk_change_table.rb +1 -1
- data/lib/rubocop/cop/rails/content_tag.rb +1 -1
- data/lib/rubocop/cop/rails/dangerous_column_names.rb +1 -2
- data/lib/rubocop/cop/rails/expanded_date_range.rb +1 -1
- data/lib/rubocop/cop/rails/find_by.rb +3 -3
- data/lib/rubocop/cop/rails/find_by_id.rb +9 -23
- data/lib/rubocop/cop/rails/http_status.rb +12 -2
- data/lib/rubocop/cop/rails/inquiry.rb +1 -0
- data/lib/rubocop/cop/rails/not_null_column.rb +91 -13
- data/lib/rubocop/cop/rails/pick.rb +10 -5
- data/lib/rubocop/cop/rails/pluck.rb +1 -1
- data/lib/rubocop/cop/rails/pluck_id.rb +2 -1
- data/lib/rubocop/cop/rails/pluck_in_where.rb +18 -5
- data/lib/rubocop/cop/rails/redundant_active_record_all_method.rb +1 -2
- data/lib/rubocop/cop/rails/response_parsed_body.rb +52 -10
- data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
- data/lib/rubocop/cop/rails/save_bang.rb +2 -0
- data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -1
- data/lib/rubocop/cop/rails/time_zone.rb +2 -1
- data/lib/rubocop/cop/rails/uniq_before_pluck.rb +12 -4
- data/lib/rubocop/cop/rails/unknown_env.rb +1 -1
- data/lib/rubocop/cop/rails/unused_ignored_columns.rb +6 -0
- data/lib/rubocop/cop/rails/validation.rb +5 -3
- data/lib/rubocop/cop/rails/where_equals.rb +3 -2
- data/lib/rubocop/cop/rails/where_exists.rb +9 -8
- data/lib/rubocop/cop/rails/where_missing.rb +6 -2
- data/lib/rubocop/cop/rails/where_not.rb +8 -6
- data/lib/rubocop/cop/rails/where_range.rb +157 -0
- data/lib/rubocop/cop/rails_cops.rb +1 -0
- data/lib/rubocop/rails/schema_loader/schema.rb +1 -0
- data/lib/rubocop/rails/schema_loader.rb +5 -15
- data/lib/rubocop/rails/version.rb +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cad5e6d0c6f188b6ff87adb04fbfb73c7c574b901de45256eb7fa6e50b7a136d
|
4
|
+
data.tar.gz: c8ab8f1d1c3284054af5847231dd996df24ee5441f638f95bc7e32420a3baf04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ea0ebe45e988d115aa45d7bdba2b728b0583e1e2d996d43af424eb8abc17ced35b528741fcc47b8b258de52edd2fb7bc1c92dd609b49ddeeaaaf26bce123e783
|
7
|
+
data.tar.gz: 7eb06cfce19f2a4ba78c6d571c65cf386e211b48ca2c9b5b9ca436ec9055e49f9737cbb3f9ce1b44ab432de87121295439effc59f093446cea88199bd08ba8a4
|
data/README.md
CHANGED
@@ -66,17 +66,15 @@ end
|
|
66
66
|
## Rails configuration tip
|
67
67
|
|
68
68
|
If you are using Rails 6.1 or newer, add the following `config.generators.after_generate` setting to
|
69
|
-
your config/
|
69
|
+
your `config/environments/development.rb` to apply RuboCop autocorrection to code generated by `bin/rails g`.
|
70
70
|
|
71
71
|
```ruby
|
72
|
-
# config/
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true)
|
79
|
-
end
|
72
|
+
# config/environments/development.rb
|
73
|
+
Rails.application.configure do
|
74
|
+
config.generators.after_generate do |files|
|
75
|
+
parsable_files = files.filter { |file| file.end_with?('.rb') }
|
76
|
+
unless parsable_files.empty?
|
77
|
+
system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true)
|
80
78
|
end
|
81
79
|
end
|
82
80
|
end
|
data/config/default.yml
CHANGED
@@ -165,6 +165,7 @@ Rails/ActiveSupportOnLoad:
|
|
165
165
|
- 'https://guides.rubyonrails.org/engines.html#available-load-hooks'
|
166
166
|
SafeAutoCorrect: false
|
167
167
|
VersionAdded: '2.16'
|
168
|
+
VersionChanged: '2.24'
|
168
169
|
|
169
170
|
Rails/AddColumnIndex:
|
170
171
|
Description: >-
|
@@ -445,9 +446,10 @@ Rails/EnvironmentVariableAccess:
|
|
445
446
|
# TODO: Set to `pending` status in RuboCop Rails 2 series when migration doc will be written.
|
446
447
|
Enabled: false
|
447
448
|
VersionAdded: '2.10'
|
448
|
-
VersionChanged: '2.
|
449
|
+
VersionChanged: '2.24'
|
449
450
|
Include:
|
450
451
|
- app/**/*.rb
|
452
|
+
- config/initializers/**/*.rb
|
451
453
|
- lib/**/*.rb
|
452
454
|
Exclude:
|
453
455
|
- lib/**/*.rake
|
@@ -691,7 +693,7 @@ Rails/NegateInclude:
|
|
691
693
|
VersionChanged: '2.9'
|
692
694
|
|
693
695
|
Rails/NotNullColumn:
|
694
|
-
Description: 'Do not add a NOT NULL column without a default value.'
|
696
|
+
Description: 'Do not add a NOT NULL column without a default value to existing tables.'
|
695
697
|
Enabled: true
|
696
698
|
VersionAdded: '0.43'
|
697
699
|
VersionChanged: '2.20'
|
@@ -902,7 +904,7 @@ Rails/RequireDependency:
|
|
902
904
|
VersionAdded: '2.10'
|
903
905
|
|
904
906
|
Rails/ResponseParsedBody:
|
905
|
-
Description: Prefer `response.parsed_body` to `
|
907
|
+
Description: Prefer `response.parsed_body` to custom parsing logic for `response.body`.
|
906
908
|
Enabled: pending
|
907
909
|
Safe: false
|
908
910
|
VersionAdded: '2.18'
|
@@ -1161,8 +1163,9 @@ Rails/UnknownEnv:
|
|
1161
1163
|
|
1162
1164
|
Rails/UnusedIgnoredColumns:
|
1163
1165
|
Description: 'Remove a column that does not exist from `ignored_columns`.'
|
1164
|
-
Enabled:
|
1166
|
+
Enabled: false
|
1165
1167
|
VersionAdded: '2.11'
|
1168
|
+
VersionChanged: '2.25'
|
1166
1169
|
Include:
|
1167
1170
|
- app/models/**/*.rb
|
1168
1171
|
|
@@ -1219,6 +1222,12 @@ Rails/WhereNotWithMultipleConditions:
|
|
1219
1222
|
VersionAdded: '2.17'
|
1220
1223
|
VersionChanged: '2.18'
|
1221
1224
|
|
1225
|
+
Rails/WhereRange:
|
1226
|
+
Description: 'Use ranges in `where` instead of manually constructing SQL.'
|
1227
|
+
StyleGuide: 'https://rails.rubystyle.guide/#where-ranges'
|
1228
|
+
Enabled: pending
|
1229
|
+
VersionAdded: '2.25'
|
1230
|
+
|
1222
1231
|
# Accept `redirect_to(...) and return` and similar cases.
|
1223
1232
|
Style/AndOr:
|
1224
1233
|
EnforcedStyle: conditionals
|
@@ -39,7 +39,12 @@ module RuboCop
|
|
39
39
|
end
|
40
40
|
|
41
41
|
def schema
|
42
|
-
RuboCop
|
42
|
+
# For compatibility with RuboCop 1.61.0 or lower.
|
43
|
+
if respond_to?(:parser_engine)
|
44
|
+
RuboCop::Rails::SchemaLoader.load(target_ruby_version, parser_engine)
|
45
|
+
else
|
46
|
+
RuboCop::Rails::SchemaLoader.load(target_ruby_version, :parser_whitequark)
|
47
|
+
end
|
43
48
|
end
|
44
49
|
|
45
50
|
def table_name(class_node)
|
@@ -98,8 +103,15 @@ module RuboCop
|
|
98
103
|
end
|
99
104
|
|
100
105
|
def in_where?(node)
|
101
|
-
send_node = node.each_ancestor(:send).first
|
102
|
-
|
106
|
+
send_node = node.each_ancestor(:send, :csend).first
|
107
|
+
return false unless send_node
|
108
|
+
|
109
|
+
return true if WHERE_METHODS.include?(send_node.method_name)
|
110
|
+
|
111
|
+
receiver = send_node.receiver
|
112
|
+
return false unless receiver&.send_type?
|
113
|
+
|
114
|
+
send_node.method?(:not) && WHERE_METHODS.include?(receiver.method_name)
|
103
115
|
end
|
104
116
|
end
|
105
117
|
end
|
@@ -4,13 +4,40 @@ module RuboCop
|
|
4
4
|
module Cop
|
5
5
|
# Common functionality for checking target rails version.
|
6
6
|
module TargetRailsVersion
|
7
|
+
# Informs the base RuboCop gem that it the Rails version is checked via `requires_gem` API,
|
8
|
+
# without needing to call this `#support_target_rails_version` method.
|
9
|
+
USES_REQUIRES_GEM_API = true
|
10
|
+
|
7
11
|
def minimum_target_rails_version(version)
|
8
|
-
|
12
|
+
if respond_to?(:requires_gem)
|
13
|
+
case version
|
14
|
+
when Integer, Float then requires_gem(TARGET_GEM_NAME, ">= #{version}")
|
15
|
+
when String then requires_gem(TARGET_GEM_NAME, version)
|
16
|
+
end
|
17
|
+
else
|
18
|
+
# Fallback path for previous versions of RuboCop which don't support the `requires_gem` API yet.
|
19
|
+
@minimum_target_rails_version = version
|
20
|
+
end
|
9
21
|
end
|
10
22
|
|
11
23
|
def support_target_rails_version?(version)
|
12
|
-
|
24
|
+
if respond_to?(:requires_gem)
|
25
|
+
return false unless gem_requirements
|
26
|
+
|
27
|
+
gem_requirement = gem_requirements[TARGET_GEM_NAME]
|
28
|
+
return true unless gem_requirement # If we have no requirement, then we support all versions
|
29
|
+
|
30
|
+
gem_requirement.satisfied_by?(Gem::Version.new(version))
|
31
|
+
else
|
32
|
+
# Fallback path for previous versions of RuboCop which don't support the `requires_gem` API yet.
|
33
|
+
@minimum_target_rails_version <= version
|
34
|
+
end
|
13
35
|
end
|
36
|
+
|
37
|
+
# Look for `railties` instead of `rails`, to support apps that only use a subset of `rails`
|
38
|
+
# See https://github.com/rubocop/rubocop/pull/11289
|
39
|
+
TARGET_GEM_NAME = 'railties'
|
40
|
+
private_constant :TARGET_GEM_NAME
|
14
41
|
end
|
15
42
|
end
|
16
43
|
end
|
@@ -99,6 +99,8 @@ module RuboCop
|
|
99
99
|
|
100
100
|
def use_redirect_to?(context)
|
101
101
|
context.right_siblings.compact.any? do |sibling|
|
102
|
+
# Unwrap `return redirect_to :index`
|
103
|
+
sibling = sibling.children.first if sibling.return_type? && sibling.children.one?
|
102
104
|
sibling.send_type? && sibling.method?(:redirect_to)
|
103
105
|
end
|
104
106
|
end
|
@@ -27,13 +27,13 @@ module RuboCop
|
|
27
27
|
|
28
28
|
ALIASES = {
|
29
29
|
starts_with?: {
|
30
|
-
original: :start_with?, matcher: '(
|
30
|
+
original: :start_with?, matcher: '(call str :starts_with? _)'
|
31
31
|
},
|
32
32
|
ends_with?: {
|
33
|
-
original: :end_with?, matcher: '(
|
33
|
+
original: :end_with?, matcher: '(call str :ends_with? _)'
|
34
34
|
},
|
35
|
-
append: { original: :<<, matcher: '(
|
36
|
-
prepend: { original: :unshift, matcher: '(
|
35
|
+
append: { original: :<<, matcher: '(call array :append _)' },
|
36
|
+
prepend: { original: :unshift, matcher: '(call array :prepend _)' }
|
37
37
|
}.freeze
|
38
38
|
|
39
39
|
ALIASES.each do |aliased_method, options|
|
@@ -47,13 +47,14 @@ module RuboCop
|
|
47
47
|
preferred_method = ALIASES[aliased_method][:original]
|
48
48
|
message = format(MSG, prefer: preferred_method, current: aliased_method)
|
49
49
|
|
50
|
-
add_offense(node, message: message) do |corrector|
|
50
|
+
add_offense(node.loc.selector.join(node.source_range.end), message: message) do |corrector|
|
51
51
|
next if append(node)
|
52
52
|
|
53
53
|
corrector.replace(node.loc.selector, preferred_method)
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
57
|
+
alias on_csend on_send
|
57
58
|
end
|
58
59
|
end
|
59
60
|
end
|
@@ -55,15 +55,35 @@ module RuboCop
|
|
55
55
|
'ActiveSupport::TestCase' => 'active_support_test_case'
|
56
56
|
}.freeze
|
57
57
|
|
58
|
+
RAILS_5_2_LOAD_HOOKS = {
|
59
|
+
'ActiveRecord::ConnectionAdapters::SQLite3Adapter' => 'active_record_sqlite3adapter'
|
60
|
+
}.freeze
|
61
|
+
|
62
|
+
RAILS_7_1_LOAD_HOOKS = {
|
63
|
+
'ActiveRecord::TestFixtures' => 'active_record_fixtures',
|
64
|
+
'ActiveModel::Model' => 'active_model',
|
65
|
+
'ActionText::EncryptedRichText' => 'action_text_encrypted_rich_text',
|
66
|
+
'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter' => 'active_record_postgresqladapter',
|
67
|
+
'ActiveRecord::ConnectionAdapters::Mysql2Adapter' => 'active_record_mysql2adapter',
|
68
|
+
'ActiveRecord::ConnectionAdapters::TrilogyAdapter' => 'active_record_trilogyadapter'
|
69
|
+
}.freeze
|
70
|
+
|
58
71
|
def on_send(node)
|
59
72
|
receiver, method, arguments = *node # rubocop:disable InternalAffairs/NodeDestructuring
|
60
|
-
return unless
|
73
|
+
return unless arguments && (hook = hook_for_const(receiver&.const_name))
|
61
74
|
|
62
75
|
preferred = "ActiveSupport.on_load(:#{hook}) { #{method} #{arguments.source} }"
|
63
76
|
add_offense(node, message: format(MSG, prefer: preferred, current: node.source)) do |corrector|
|
64
77
|
corrector.replace(node, preferred)
|
65
78
|
end
|
66
79
|
end
|
80
|
+
|
81
|
+
def hook_for_const(const_name)
|
82
|
+
hook = LOAD_HOOKS[const_name]
|
83
|
+
hook ||= RAILS_5_2_LOAD_HOOKS[const_name] if target_rails_version >= 5.2
|
84
|
+
hook ||= RAILS_7_1_LOAD_HOOKS[const_name] if target_rails_version >= 7.1
|
85
|
+
hook
|
86
|
+
end
|
67
87
|
end
|
68
88
|
end
|
69
89
|
end
|
@@ -14,7 +14,7 @@ module RuboCop
|
|
14
14
|
# automatically detect an adapter from `development` environment
|
15
15
|
# in `config/database.yml` or the environment variable `DATABASE_URL`
|
16
16
|
# when the `Database` option is not set.
|
17
|
-
# If the adapter is not `mysql2`, `trilogy`, or `
|
17
|
+
# If the adapter is not `mysql2`, `trilogy`, `postgresql`, or `postgis`,
|
18
18
|
# this Cop ignores offenses.
|
19
19
|
#
|
20
20
|
# @example
|
@@ -7,7 +7,7 @@ module RuboCop
|
|
7
7
|
#
|
8
8
|
# NOTE: Allow `tag` when the first argument is a variable because
|
9
9
|
# `tag(name)` is simpler rather than `tag.public_send(name)`.
|
10
|
-
# And this cop will be renamed to something like `LegacyTag` in the future. (e.g. RuboCop Rails
|
10
|
+
# And this cop will be renamed to something like `LegacyTag` in the future. (e.g. RuboCop Rails 3.0)
|
11
11
|
#
|
12
12
|
# @example
|
13
13
|
# # bad
|
@@ -31,7 +31,7 @@ module RuboCop
|
|
31
31
|
time
|
32
32
|
].to_set.freeze
|
33
33
|
|
34
|
-
# Generated from `ActiveRecord::AttributeMethods.dangerous_attribute_methods` on activerecord 7.1.
|
34
|
+
# Generated from `ActiveRecord::AttributeMethods.dangerous_attribute_methods` on activerecord 7.1.3.
|
35
35
|
# rubocop:disable Metrics/CollectionLiteralLength
|
36
36
|
DANGEROUS_COLUMN_NAMES = %w[
|
37
37
|
__callbacks
|
@@ -290,7 +290,6 @@ module RuboCop
|
|
290
290
|
new_record
|
291
291
|
no_touching
|
292
292
|
normalize_reflection_attribute
|
293
|
-
object_id
|
294
293
|
partial_inserts
|
295
294
|
partial_updates
|
296
295
|
perform_validations
|
@@ -51,7 +51,7 @@ module RuboCop
|
|
51
51
|
return if allow?(begin_node, end_node)
|
52
52
|
|
53
53
|
preferred_method = preferred_method(begin_node)
|
54
|
-
if begin_node.method?(:beginning_of_week) && begin_node.arguments.one?
|
54
|
+
if begin_node.method?(:beginning_of_week) && begin_node.arguments.one? && end_node.arguments.one?
|
55
55
|
return unless same_argument?(begin_node, end_node)
|
56
56
|
|
57
57
|
preferred_method << "(#{begin_node.first_argument.source})"
|
@@ -28,7 +28,7 @@ module RuboCop
|
|
28
28
|
include RangeHelp
|
29
29
|
extend AutoCorrector
|
30
30
|
|
31
|
-
MSG = 'Use `find_by` instead of `where
|
31
|
+
MSG = 'Use `find_by` instead of `where%<dot>s%<method>s`.'
|
32
32
|
RESTRICT_ON_SEND = %i[first take].freeze
|
33
33
|
|
34
34
|
def on_send(node)
|
@@ -37,7 +37,7 @@ module RuboCop
|
|
37
37
|
|
38
38
|
range = offense_range(node)
|
39
39
|
|
40
|
-
add_offense(range, message: format(MSG, method: node.method_name)) do |corrector|
|
40
|
+
add_offense(range, message: format(MSG, dot: node.loc.dot.source, method: node.method_name)) do |corrector|
|
41
41
|
autocorrect(corrector, node)
|
42
42
|
end
|
43
43
|
end
|
@@ -59,7 +59,7 @@ module RuboCop
|
|
59
59
|
return if node.method?(:first)
|
60
60
|
|
61
61
|
where_loc = node.receiver.loc.selector
|
62
|
-
first_loc = range_between(node.
|
62
|
+
first_loc = range_between(node.receiver.source_range.end_pos, node.loc.selector.end_pos)
|
63
63
|
|
64
64
|
corrector.replace(where_loc, 'find_by')
|
65
65
|
corrector.replace(first_loc, '')
|
@@ -24,40 +24,39 @@ module RuboCop
|
|
24
24
|
RESTRICT_ON_SEND = %i[take! find_by_id! find_by!].freeze
|
25
25
|
|
26
26
|
def_node_matcher :where_take?, <<~PATTERN
|
27
|
-
(
|
28
|
-
$(
|
27
|
+
(call
|
28
|
+
$(call _ :where
|
29
29
|
(hash
|
30
30
|
(pair (sym :id) $_))) :take!)
|
31
31
|
PATTERN
|
32
32
|
|
33
33
|
def_node_matcher :find_by?, <<~PATTERN
|
34
34
|
{
|
35
|
-
(
|
36
|
-
(
|
35
|
+
(call _ :find_by_id! $_)
|
36
|
+
(call _ :find_by! (hash (pair (sym :id) $_)))
|
37
37
|
}
|
38
38
|
PATTERN
|
39
39
|
|
40
40
|
def on_send(node)
|
41
41
|
where_take?(node) do |where, id_value|
|
42
42
|
range = where_take_offense_range(node, where)
|
43
|
-
bad_method = build_where_take_bad_method(id_value)
|
44
43
|
|
45
|
-
register_offense(range, id_value
|
44
|
+
register_offense(range, id_value)
|
46
45
|
end
|
47
46
|
|
48
47
|
find_by?(node) do |id_value|
|
49
48
|
range = find_by_offense_range(node)
|
50
|
-
bad_method = build_find_by_bad_method(node, id_value)
|
51
49
|
|
52
|
-
register_offense(range, id_value
|
50
|
+
register_offense(range, id_value)
|
53
51
|
end
|
54
52
|
end
|
53
|
+
alias on_csend on_send
|
55
54
|
|
56
55
|
private
|
57
56
|
|
58
|
-
def register_offense(range, id_value
|
57
|
+
def register_offense(range, id_value)
|
59
58
|
good_method = build_good_method(id_value)
|
60
|
-
message = format(MSG, good_method: good_method, bad_method:
|
59
|
+
message = format(MSG, good_method: good_method, bad_method: range.source)
|
61
60
|
|
62
61
|
add_offense(range, message: message) do |corrector|
|
63
62
|
corrector.replace(range, good_method)
|
@@ -75,19 +74,6 @@ module RuboCop
|
|
75
74
|
def build_good_method(id_value)
|
76
75
|
"find(#{id_value.source})"
|
77
76
|
end
|
78
|
-
|
79
|
-
def build_where_take_bad_method(id_value)
|
80
|
-
"where(id: #{id_value.source}).take!"
|
81
|
-
end
|
82
|
-
|
83
|
-
def build_find_by_bad_method(node, id_value)
|
84
|
-
case node.method_name
|
85
|
-
when :find_by_id!
|
86
|
-
"find_by_id!(#{id_value.source})"
|
87
|
-
when :find_by!
|
88
|
-
"find_by!(id: #{id_value.source})"
|
89
|
-
end
|
90
|
-
end
|
91
77
|
end
|
92
78
|
end
|
93
79
|
end
|
@@ -13,6 +13,8 @@ module RuboCop
|
|
13
13
|
# render plain: 'foo/bar', status: 304
|
14
14
|
# redirect_to root_url, status: 301
|
15
15
|
# head 200
|
16
|
+
# assert_response 200
|
17
|
+
# assert_redirected_to '/some/path', status: 301
|
16
18
|
#
|
17
19
|
# # good
|
18
20
|
# render :foo, status: :ok
|
@@ -20,6 +22,8 @@ module RuboCop
|
|
20
22
|
# render plain: 'foo/bar', status: :not_modified
|
21
23
|
# redirect_to root_url, status: :moved_permanently
|
22
24
|
# head :ok
|
25
|
+
# assert_response :ok
|
26
|
+
# assert_redirected_to '/some/path', status: :moved_permanently
|
23
27
|
#
|
24
28
|
# @example EnforcedStyle: numeric
|
25
29
|
# # bad
|
@@ -28,6 +32,8 @@ module RuboCop
|
|
28
32
|
# render plain: 'foo/bar', status: :not_modified
|
29
33
|
# redirect_to root_url, status: :moved_permanently
|
30
34
|
# head :ok
|
35
|
+
# assert_response :ok
|
36
|
+
# assert_redirected_to '/some/path', status: :moved_permanently
|
31
37
|
#
|
32
38
|
# # good
|
33
39
|
# render :foo, status: 200
|
@@ -35,18 +41,22 @@ module RuboCop
|
|
35
41
|
# render plain: 'foo/bar', status: 304
|
36
42
|
# redirect_to root_url, status: 301
|
37
43
|
# head 200
|
44
|
+
# assert_response 200
|
45
|
+
# assert_redirected_to '/some/path', status: 301
|
38
46
|
#
|
39
47
|
class HttpStatus < Base
|
40
48
|
include ConfigurableEnforcedStyle
|
41
49
|
extend AutoCorrector
|
42
50
|
|
43
|
-
RESTRICT_ON_SEND = %i[render redirect_to head].freeze
|
51
|
+
RESTRICT_ON_SEND = %i[render redirect_to head assert_response assert_redirected_to].freeze
|
44
52
|
|
45
53
|
def_node_matcher :http_status, <<~PATTERN
|
46
54
|
{
|
47
55
|
(send nil? {:render :redirect_to} _ $hash)
|
48
56
|
(send nil? {:render :redirect_to} $hash)
|
49
|
-
(send nil? :head ${int sym} ...)
|
57
|
+
(send nil? {:head :assert_response} ${int sym} ...)
|
58
|
+
(send nil? :assert_redirected_to _ $hash ...)
|
59
|
+
(send nil? :assert_redirected_to $hash ...)
|
50
60
|
}
|
51
61
|
PATTERN
|
52
62
|
|
@@ -3,24 +3,42 @@
|
|
3
3
|
module RuboCop
|
4
4
|
module Cop
|
5
5
|
module Rails
|
6
|
-
# Checks for add_column
|
6
|
+
# Checks for add_column calls with a NOT NULL constraint without a default
|
7
|
+
# value.
|
7
8
|
#
|
8
|
-
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
9
|
+
# This cop only applies when adding a column to an existing table, since
|
10
|
+
# existing records will not have a value for the new column. New tables
|
11
|
+
# can freely use NOT NULL columns without defaults, since there are no
|
12
|
+
# records that could violate the constraint.
|
13
|
+
#
|
14
|
+
# If you need to add a NOT NULL column to an existing table, you must add
|
15
|
+
# it as nullable first, back-fill the data, and then use
|
16
|
+
# `change_column_null`. Alternatively, you could add the column with a
|
17
|
+
# default first to have the database automatically backfill existing rows,
|
18
|
+
# and then use `change_column_default` to remove the default.
|
19
|
+
#
|
20
|
+
# `TEXT` cannot have a default value in MySQL.
|
21
|
+
# The cop will automatically detect an adapter from `development`
|
22
|
+
# environment in `config/database.yml` or the environment variable
|
23
|
+
# `DATABASE_URL` when the `Database` option is not set. If the database
|
24
|
+
# is MySQL, this cop ignores offenses for `TEXT` columns.
|
13
25
|
#
|
14
26
|
# @example
|
15
27
|
# # bad
|
16
28
|
# add_column :users, :name, :string, null: false
|
17
29
|
# add_reference :products, :category, null: false
|
30
|
+
# change_table :users do |t|
|
31
|
+
# t.string :name, null: false
|
32
|
+
# end
|
18
33
|
#
|
19
34
|
# # good
|
20
35
|
# add_column :users, :name, :string, null: true
|
21
36
|
# add_column :users, :name, :string, null: false, default: ''
|
37
|
+
# change_table :users do |t|
|
38
|
+
# t.string :name, null: false, default: ''
|
39
|
+
# end
|
22
40
|
# add_reference :products, :category
|
23
|
-
#
|
41
|
+
# change_column_null :products, :category_id, false
|
24
42
|
class NotNullColumn < Base
|
25
43
|
include DatabaseTypeResolvable
|
26
44
|
|
@@ -35,6 +53,22 @@ module RuboCop
|
|
35
53
|
(send nil? :add_reference _ _ (hash $...))
|
36
54
|
PATTERN
|
37
55
|
|
56
|
+
def_node_matcher :change_table?, <<~PATTERN
|
57
|
+
(block (send nil? :change_table ...) (args (arg $_)) _)
|
58
|
+
PATTERN
|
59
|
+
|
60
|
+
def_node_matcher :add_not_null_column_in_change_table?, <<~PATTERN
|
61
|
+
(send (lvar $_) :column _ $_ (hash $...))
|
62
|
+
PATTERN
|
63
|
+
|
64
|
+
def_node_matcher :add_not_null_column_via_shortcut_in_change_table?, <<~PATTERN
|
65
|
+
(send (lvar $_) $_ _ (hash $...))
|
66
|
+
PATTERN
|
67
|
+
|
68
|
+
def_node_matcher :add_not_null_reference_in_change_table?, <<~PATTERN
|
69
|
+
(send (lvar $_) :add_reference _ _ (hash $...))
|
70
|
+
PATTERN
|
71
|
+
|
38
72
|
def_node_matcher :null_false?, <<~PATTERN
|
39
73
|
(pair (sym :null) (false))
|
40
74
|
PATTERN
|
@@ -48,16 +82,25 @@ module RuboCop
|
|
48
82
|
check_add_reference(node)
|
49
83
|
end
|
50
84
|
|
85
|
+
def on_block(node)
|
86
|
+
check_change_table(node)
|
87
|
+
end
|
88
|
+
alias on_numblock on_block
|
89
|
+
|
51
90
|
private
|
52
91
|
|
92
|
+
def check_column(type, pairs)
|
93
|
+
if type.respond_to?(:value)
|
94
|
+
return if type.value == :virtual || type.value == 'virtual'
|
95
|
+
return if (type.value == :text || type.value == 'text') && database == MYSQL
|
96
|
+
end
|
97
|
+
|
98
|
+
check_pairs(pairs)
|
99
|
+
end
|
100
|
+
|
53
101
|
def check_add_column(node)
|
54
102
|
add_not_null_column?(node) do |type, pairs|
|
55
|
-
|
56
|
-
return if type.value == :virtual || type.value == 'virtual'
|
57
|
-
return if (type.value == :text || type.value == 'text') && database == MYSQL
|
58
|
-
end
|
59
|
-
|
60
|
-
check_pairs(pairs)
|
103
|
+
check_column(type, pairs)
|
61
104
|
end
|
62
105
|
end
|
63
106
|
|
@@ -67,6 +110,41 @@ module RuboCop
|
|
67
110
|
end
|
68
111
|
end
|
69
112
|
|
113
|
+
def check_add_column_in_change_table(node, table)
|
114
|
+
add_not_null_column_in_change_table?(node) do |receiver, type, pairs|
|
115
|
+
next unless receiver == table
|
116
|
+
|
117
|
+
check_column(type, pairs)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def check_add_column_via_shortcut_in_change_table(node, table)
|
122
|
+
add_not_null_column_via_shortcut_in_change_table?(node) do |receiver, type, pairs|
|
123
|
+
next unless receiver == table
|
124
|
+
|
125
|
+
check_column(type, pairs)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def check_add_reference_in_change_table(node, table)
|
130
|
+
add_not_null_reference_in_change_table?(node) do |receiver, pairs|
|
131
|
+
next unless receiver == table
|
132
|
+
|
133
|
+
check_pairs(pairs)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def check_change_table(node)
|
138
|
+
change_table?(node) do |table|
|
139
|
+
children = node.body.begin_type? ? node.body.children : [node.body]
|
140
|
+
children.each do |child|
|
141
|
+
check_add_column_in_change_table(child, table)
|
142
|
+
check_add_column_via_shortcut_in_change_table(child, table)
|
143
|
+
check_add_reference_in_change_table(child, table)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
70
148
|
def check_pairs(pairs)
|
71
149
|
return if pairs.any? { |pair| default_option?(pair) }
|
72
150
|
|