rubocop-rails 2.22.2 → 2.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/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
|
|