rubocop-rails 2.20.2 → 2.22.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -2
- data/config/default.yml +68 -8
- data/lib/rubocop/cop/mixin/database_type_resolvable.rb +66 -0
- data/lib/rubocop/cop/mixin/index_method.rb +2 -2
- data/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +1 -1
- data/lib/rubocop/cop/rails/action_controller_test_case.rb +2 -2
- data/lib/rubocop/cop/rails/action_filter.rb +3 -0
- data/lib/rubocop/cop/rails/bulk_change_table.rb +5 -38
- data/lib/rubocop/cop/rails/dangerous_column_names.rb +447 -0
- data/lib/rubocop/cop/rails/date.rb +1 -1
- data/lib/rubocop/cop/rails/duplicate_association.rb +69 -12
- data/lib/rubocop/cop/rails/dynamic_find_by.rb +3 -3
- data/lib/rubocop/cop/rails/env_local.rb +46 -0
- data/lib/rubocop/cop/rails/file_path.rb +4 -1
- data/lib/rubocop/cop/rails/freeze_time.rb +1 -1
- data/lib/rubocop/cop/rails/has_many_or_has_one_dependent.rb +1 -1
- data/lib/rubocop/cop/rails/helper_instance_variable.rb +1 -1
- data/lib/rubocop/cop/rails/http_status.rb +4 -3
- data/lib/rubocop/cop/rails/i18n_lazy_lookup.rb +63 -13
- data/lib/rubocop/cop/rails/lexically_scoped_action_filter.rb +7 -8
- data/lib/rubocop/cop/rails/not_null_column.rb +13 -3
- data/lib/rubocop/cop/rails/output.rb +3 -2
- data/lib/rubocop/cop/rails/rake_environment.rb +20 -4
- data/lib/rubocop/cop/rails/redundant_active_record_all_method.rb +207 -0
- data/lib/rubocop/cop/rails/redundant_presence_validation_on_belongs_to.rb +7 -0
- data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
- data/lib/rubocop/cop/rails/root_pathname_methods.rb +38 -4
- data/lib/rubocop/cop/rails/save_bang.rb +9 -4
- data/lib/rubocop/cop/rails/schema_comment.rb +16 -10
- data/lib/rubocop/cop/rails/select_map.rb +78 -0
- data/lib/rubocop/cop/rails/time_zone.rb +12 -5
- data/lib/rubocop/cop/rails/transaction_exit_statement.rb +29 -10
- data/lib/rubocop/cop/rails/unique_validation_without_index.rb +1 -1
- data/lib/rubocop/cop/rails/unknown_env.rb +5 -1
- data/lib/rubocop/cop/rails/unused_render_content.rb +67 -0
- data/lib/rubocop/cop/rails/where_exists.rb +0 -1
- data/lib/rubocop/cop/rails_cops.rb +6 -0
- data/lib/rubocop/rails/schema_loader.rb +1 -1
- data/lib/rubocop/rails/version.rb +1 -1
- data/lib/rubocop-rails.rb +8 -0
- metadata +9 -3
@@ -0,0 +1,447 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Avoid dangerous column names.
|
7
|
+
#
|
8
|
+
# Some column names are considered dangerous because they would overwrite methods already defined.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# # bad
|
12
|
+
# add_column :users, :save
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# add_column :users, :saved
|
16
|
+
class DangerousColumnNames < Base # rubocop:disable Metrics/ClassLength
|
17
|
+
COLUMN_TYPE_METHOD_NAMES = %i[
|
18
|
+
bigint
|
19
|
+
binary
|
20
|
+
blob
|
21
|
+
boolean
|
22
|
+
date
|
23
|
+
datetime
|
24
|
+
decimal
|
25
|
+
float
|
26
|
+
integer
|
27
|
+
numeric
|
28
|
+
primary_key
|
29
|
+
string
|
30
|
+
text
|
31
|
+
time
|
32
|
+
].to_set.freeze
|
33
|
+
|
34
|
+
# Generated from `ActiveRecord::AttributeMethods.dangerous_attribute_methods` on activerecord 7.1.0.
|
35
|
+
# rubocop:disable Metrics/CollectionLiteralLength
|
36
|
+
DANGEROUS_COLUMN_NAMES = %w[
|
37
|
+
__callbacks
|
38
|
+
__id__
|
39
|
+
_assign_attribute
|
40
|
+
_assign_attributes
|
41
|
+
_before_commit_callbacks
|
42
|
+
_commit_callbacks
|
43
|
+
_committed_already_called
|
44
|
+
_create_callbacks
|
45
|
+
_create_record
|
46
|
+
_delete_row
|
47
|
+
_destroy
|
48
|
+
_destroy_callbacks
|
49
|
+
_ensure_no_duplicate_errors
|
50
|
+
_find_callbacks
|
51
|
+
_find_record
|
52
|
+
_has_attribute
|
53
|
+
_initialize_callbacks
|
54
|
+
_lock_value_for_database
|
55
|
+
_merge_attributes
|
56
|
+
_primary_key_constraints_hash
|
57
|
+
_raise_readonly_record_error
|
58
|
+
_raise_record_not_destroyed
|
59
|
+
_raise_record_not_touched_error
|
60
|
+
_read_attribute
|
61
|
+
_record_changed
|
62
|
+
_reflections
|
63
|
+
_rollback_callbacks
|
64
|
+
_run_before_commit_callbacks
|
65
|
+
_run_commit_callbacks
|
66
|
+
_run_create_callbacks
|
67
|
+
_run_destroy_callbacks
|
68
|
+
_run_find_callbacks
|
69
|
+
_run_initialize_callbacks
|
70
|
+
_run_rollback_callbacks
|
71
|
+
_run_save_callbacks
|
72
|
+
_run_touch_callbacks
|
73
|
+
_run_update_callbacks
|
74
|
+
_run_validate_callbacks
|
75
|
+
_run_validation_callbacks
|
76
|
+
_save_callbacks
|
77
|
+
_touch_callbacks
|
78
|
+
_touch_row
|
79
|
+
_trigger_destroy_callback
|
80
|
+
_trigger_update_callback
|
81
|
+
_update_callbacks
|
82
|
+
_update_record
|
83
|
+
_update_row
|
84
|
+
_validate_callbacks
|
85
|
+
_validation_callbacks
|
86
|
+
_validators
|
87
|
+
_write_attribute
|
88
|
+
[]
|
89
|
+
[]=
|
90
|
+
accessed_fields
|
91
|
+
add_to_transaction
|
92
|
+
aggregate_reflections
|
93
|
+
all_timestamp_attributes_in_model
|
94
|
+
allow_destroy
|
95
|
+
apply_scoping
|
96
|
+
around_save_collection_association
|
97
|
+
assign_attributes
|
98
|
+
assign_multiparameter_attributes
|
99
|
+
assign_nested_attributes_for_collection_association
|
100
|
+
assign_nested_attributes_for_one_to_one_association
|
101
|
+
assign_nested_parameter_attributes
|
102
|
+
assign_to_or_mark_for_destruction
|
103
|
+
associated_records_to_validate_or_save
|
104
|
+
association
|
105
|
+
association_cached
|
106
|
+
association_foreign_key_changed
|
107
|
+
association_instance_get
|
108
|
+
association_instance_set
|
109
|
+
association_valid
|
110
|
+
attachment_changes
|
111
|
+
attachment_reflections
|
112
|
+
attribute
|
113
|
+
attribute_aliases
|
114
|
+
attribute_before_last_save
|
115
|
+
attribute_before_type_cast
|
116
|
+
attribute_came_from_user
|
117
|
+
attribute_change
|
118
|
+
attribute_change_to_be_saved
|
119
|
+
attribute_changed
|
120
|
+
attribute_changed_in_place
|
121
|
+
attribute_for_database
|
122
|
+
attribute_for_inspect
|
123
|
+
attribute_in_database
|
124
|
+
attribute_method
|
125
|
+
attribute_method_matchers
|
126
|
+
attribute_missing
|
127
|
+
attribute_names
|
128
|
+
attribute_names_for_partial_inserts
|
129
|
+
attribute_names_for_partial_updates
|
130
|
+
attribute_names_for_serialization
|
131
|
+
attribute_present
|
132
|
+
attribute_previous_change
|
133
|
+
attribute_previously_changed
|
134
|
+
attribute_previously_was
|
135
|
+
attribute_was
|
136
|
+
attribute_will_change
|
137
|
+
attribute=
|
138
|
+
attributes
|
139
|
+
attributes_before_type_cast
|
140
|
+
attributes_for_create
|
141
|
+
attributes_for_database
|
142
|
+
attributes_for_update
|
143
|
+
attributes_in_database
|
144
|
+
attributes_with_values
|
145
|
+
attributes=
|
146
|
+
automatic_scope_inversing
|
147
|
+
becomes
|
148
|
+
before_committed
|
149
|
+
belongs_to_touch_method
|
150
|
+
broadcast_action
|
151
|
+
broadcast_action_later
|
152
|
+
broadcast_action_later_to
|
153
|
+
broadcast_action_to
|
154
|
+
broadcast_after_to
|
155
|
+
broadcast_append
|
156
|
+
broadcast_append_later
|
157
|
+
broadcast_append_later_to
|
158
|
+
broadcast_append_to
|
159
|
+
broadcast_before_to
|
160
|
+
broadcast_prepend
|
161
|
+
broadcast_prepend_later
|
162
|
+
broadcast_prepend_later_to
|
163
|
+
broadcast_prepend_to
|
164
|
+
broadcast_remove
|
165
|
+
broadcast_remove_to
|
166
|
+
broadcast_render
|
167
|
+
broadcast_render_later
|
168
|
+
broadcast_render_later_to
|
169
|
+
broadcast_render_to
|
170
|
+
broadcast_rendering_with_defaults
|
171
|
+
broadcast_replace
|
172
|
+
broadcast_replace_later
|
173
|
+
broadcast_replace_later_to
|
174
|
+
broadcast_replace_to
|
175
|
+
broadcast_target_default
|
176
|
+
broadcast_update
|
177
|
+
broadcast_update_later
|
178
|
+
broadcast_update_later_to
|
179
|
+
broadcast_update_to
|
180
|
+
build_decrypt_attribute_assignments
|
181
|
+
build_encrypt_attribute_assignments
|
182
|
+
cache_key
|
183
|
+
cache_key_with_version
|
184
|
+
cache_timestamp_format
|
185
|
+
cache_version
|
186
|
+
cache_versioning
|
187
|
+
call_reject_if
|
188
|
+
can_use_fast_cache_version
|
189
|
+
cant_modify_encrypted_attributes_when_frozen
|
190
|
+
changed
|
191
|
+
changed_attribute_names_to_save
|
192
|
+
changed_attributes
|
193
|
+
changed_for_autosave
|
194
|
+
changes
|
195
|
+
changes_applied
|
196
|
+
changes_to_save
|
197
|
+
check_record_limit
|
198
|
+
ciphertext_for
|
199
|
+
class
|
200
|
+
clear_attribute_change
|
201
|
+
clear_attribute_changes
|
202
|
+
clear_changes_information
|
203
|
+
clear_timestamp_attributes
|
204
|
+
clear_transaction_record_state
|
205
|
+
clone
|
206
|
+
collection_cache_versioning
|
207
|
+
column_for_attribute
|
208
|
+
committed
|
209
|
+
connection_handler
|
210
|
+
create_or_update
|
211
|
+
current_time_from_proper_timezone
|
212
|
+
custom_inspect_method_defined
|
213
|
+
custom_validation_context
|
214
|
+
decrement
|
215
|
+
decrypt
|
216
|
+
decrypt_attributes
|
217
|
+
decrypt_rich_texts
|
218
|
+
default_connection_handler
|
219
|
+
default_role
|
220
|
+
default_scope_override
|
221
|
+
default_scopes
|
222
|
+
default_shard
|
223
|
+
default_validation_context
|
224
|
+
defined_enums
|
225
|
+
delete
|
226
|
+
destroy
|
227
|
+
destroy_association_async_job
|
228
|
+
destroy_associations
|
229
|
+
destroy_row
|
230
|
+
destroyed
|
231
|
+
destroyed_by_association
|
232
|
+
destroyed_by_association=
|
233
|
+
dup
|
234
|
+
each_counter_cached_associations
|
235
|
+
encode_with
|
236
|
+
encrypt
|
237
|
+
encrypt_attributes
|
238
|
+
encrypt_rich_texts
|
239
|
+
encryptable_rich_texts
|
240
|
+
encrypted_attribute
|
241
|
+
encrypted_attributes
|
242
|
+
encrypted_attributes=
|
243
|
+
ensure_proper_type
|
244
|
+
errors
|
245
|
+
execute_callstack_for_multiparameter_attributes
|
246
|
+
extract_callstack_for_multiparameter_attributes
|
247
|
+
find_parameter_position
|
248
|
+
forget_attribute_assignments
|
249
|
+
format_for_inspect
|
250
|
+
freeze
|
251
|
+
from_json
|
252
|
+
frozen?
|
253
|
+
halted_callback_hook
|
254
|
+
has_attribute
|
255
|
+
has_changes_to_save
|
256
|
+
has_defer_touch_attrs
|
257
|
+
has_destroy_flag
|
258
|
+
has_encrypted_attributes
|
259
|
+
has_encrypted_rich_texts
|
260
|
+
has_transactional_callbacks
|
261
|
+
hash
|
262
|
+
id
|
263
|
+
id_before_type_cast
|
264
|
+
id_for_database
|
265
|
+
id_in_database
|
266
|
+
id_was
|
267
|
+
id=
|
268
|
+
include_root_in_json
|
269
|
+
increment
|
270
|
+
init_internals
|
271
|
+
init_with
|
272
|
+
init_with_attributes
|
273
|
+
initialize_internals_callback
|
274
|
+
inspection_filter
|
275
|
+
invalid
|
276
|
+
lock
|
277
|
+
lock_optimistically
|
278
|
+
locking_enabled
|
279
|
+
logger
|
280
|
+
mark_for_destruction
|
281
|
+
marked_for_destruction
|
282
|
+
matched_attribute_method
|
283
|
+
max_updated_column_timestamp
|
284
|
+
missing_attribute
|
285
|
+
model_name
|
286
|
+
mutations_before_last_save
|
287
|
+
mutations_from_database
|
288
|
+
nested_attributes_options
|
289
|
+
nested_records_changed_for_autosave
|
290
|
+
new_record
|
291
|
+
no_touching
|
292
|
+
normalize_reflection_attribute
|
293
|
+
object_id
|
294
|
+
partial_inserts
|
295
|
+
partial_updates
|
296
|
+
perform_validations
|
297
|
+
persisted
|
298
|
+
pk_attribute
|
299
|
+
pluralize_table_names
|
300
|
+
populate_with_current_scope_attributes
|
301
|
+
previous_changes
|
302
|
+
previously_new_record
|
303
|
+
previously_persisted
|
304
|
+
primary_key_prefix_type
|
305
|
+
query_attribute
|
306
|
+
raise_nested_attributes_record_not_found
|
307
|
+
raise_validation_error
|
308
|
+
raw_timestamp_to_cache_version
|
309
|
+
read_attribute
|
310
|
+
read_attribute_before_type_cast
|
311
|
+
read_attribute_for_serialization
|
312
|
+
read_attribute_for_validation
|
313
|
+
read_store_attribute
|
314
|
+
readonly
|
315
|
+
record_timestamps
|
316
|
+
record_timestamps=
|
317
|
+
reject_new_record
|
318
|
+
reload
|
319
|
+
remember_transaction_record_state
|
320
|
+
respond_to_without_attributes
|
321
|
+
restore_attribute
|
322
|
+
restore_attributes
|
323
|
+
restore_transaction_record_state
|
324
|
+
rolledback
|
325
|
+
run_callbacks
|
326
|
+
run_validations
|
327
|
+
sanitize_for_mass_assignment
|
328
|
+
sanitize_forbidden_attributes
|
329
|
+
save
|
330
|
+
save_belongs_to_association
|
331
|
+
save_collection_association
|
332
|
+
save_has_one_association
|
333
|
+
saved_change_to_attribute
|
334
|
+
saved_changes
|
335
|
+
serializable_add_includes
|
336
|
+
serializable_attributes
|
337
|
+
serializable_hash
|
338
|
+
should_record_timestamps
|
339
|
+
signed_id
|
340
|
+
signed_id_verifier_secret
|
341
|
+
skip_time_zone_conversion_for_attributes
|
342
|
+
slice
|
343
|
+
store_accessor_for
|
344
|
+
store_full_class_name
|
345
|
+
store_full_sti_class
|
346
|
+
strict_loaded_associations
|
347
|
+
strict_loading
|
348
|
+
strict_loading_mode
|
349
|
+
strict_loading_n_plus_one_only
|
350
|
+
surreptitiously_touch
|
351
|
+
table_name_prefix
|
352
|
+
table_name_suffix
|
353
|
+
time_zone_aware_attributes
|
354
|
+
time_zone_aware_types
|
355
|
+
timestamp_attributes_for_create_in_model
|
356
|
+
timestamp_attributes_for_update_in_model
|
357
|
+
to_ary
|
358
|
+
to_gid
|
359
|
+
to_gid_param
|
360
|
+
to_global_id
|
361
|
+
to_key
|
362
|
+
to_model
|
363
|
+
to_partial_path
|
364
|
+
to_sgid
|
365
|
+
to_sgid_param
|
366
|
+
to_signed_global_id
|
367
|
+
toggle
|
368
|
+
touch
|
369
|
+
touch_deferred_attributes
|
370
|
+
touch_later
|
371
|
+
transaction
|
372
|
+
transaction_include_any_action
|
373
|
+
trigger_transactional_callbacks
|
374
|
+
type_cast_attribute_value
|
375
|
+
type_for_attribute
|
376
|
+
update
|
377
|
+
update_attribute
|
378
|
+
update_column
|
379
|
+
update_columns
|
380
|
+
valid
|
381
|
+
validate
|
382
|
+
validate_collection_association
|
383
|
+
validate_encryption_allowed
|
384
|
+
validate_single_association
|
385
|
+
validates_absence_of
|
386
|
+
validates_acceptance_of
|
387
|
+
validates_comparison_of
|
388
|
+
validates_confirmation_of
|
389
|
+
validates_exclusion_of
|
390
|
+
validates_format_of
|
391
|
+
validates_inclusion_of
|
392
|
+
validates_length_of
|
393
|
+
validates_numericality_of
|
394
|
+
validates_presence_of
|
395
|
+
validates_size_of
|
396
|
+
validates_with
|
397
|
+
validation_context
|
398
|
+
validation_context=
|
399
|
+
values_at
|
400
|
+
verify_readonly_attribute
|
401
|
+
will_be_destroyed
|
402
|
+
will_save_change_to_attribute
|
403
|
+
with_lock
|
404
|
+
with_transaction_returning_status
|
405
|
+
write_attribute
|
406
|
+
write_store_attribute
|
407
|
+
].freeze
|
408
|
+
# rubocop:enable Metrics/CollectionLiteralLength
|
409
|
+
|
410
|
+
MSG = 'Avoid dangerous column names.'
|
411
|
+
|
412
|
+
RESTRICT_ON_SEND = [:add_column, :rename, :rename_column, *COLUMN_TYPE_METHOD_NAMES].freeze
|
413
|
+
|
414
|
+
def on_send(node)
|
415
|
+
column_name_node = column_name_node_from(node)
|
416
|
+
return false unless column_name_node
|
417
|
+
return false unless dangerous_column_name_node?(column_name_node)
|
418
|
+
|
419
|
+
add_offense(column_name_node)
|
420
|
+
end
|
421
|
+
|
422
|
+
private
|
423
|
+
|
424
|
+
def column_name_node_from(node)
|
425
|
+
case node.method_name
|
426
|
+
when :add_column, :rename
|
427
|
+
node.arguments[1]
|
428
|
+
when :rename_column
|
429
|
+
node.arguments[2]
|
430
|
+
when *COLUMN_TYPE_METHOD_NAMES
|
431
|
+
node.arguments[0]
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
def dangerous_column_name_node?(node)
|
436
|
+
return false unless node.respond_to?(:value)
|
437
|
+
|
438
|
+
dangerous_column_name?(node.value.to_s)
|
439
|
+
end
|
440
|
+
|
441
|
+
def dangerous_column_name?(column_name)
|
442
|
+
DANGEROUS_COLUMN_NAMES.include?(column_name)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
end
|
446
|
+
end
|
447
|
+
end
|
@@ -20,35 +20,92 @@ module RuboCop
|
|
20
20
|
# belongs_to :bar
|
21
21
|
# has_one :foo
|
22
22
|
#
|
23
|
+
# # bad
|
24
|
+
# has_many :foo, class_name: 'Foo'
|
25
|
+
# has_many :bar, class_name: 'Foo'
|
26
|
+
# has_one :baz
|
27
|
+
#
|
28
|
+
# # good
|
29
|
+
# has_many :bar, class_name: 'Foo'
|
30
|
+
# has_one :foo
|
31
|
+
#
|
23
32
|
class DuplicateAssociation < Base
|
24
33
|
include RangeHelp
|
25
34
|
extend AutoCorrector
|
26
35
|
include ClassSendNodeHelper
|
36
|
+
include ActiveRecordHelper
|
27
37
|
|
28
38
|
MSG = "Association `%<name>s` is defined multiple times. Don't repeat associations."
|
39
|
+
MSG_CLASS_NAME = "Association `class_name: %<name>s` is defined multiple times. Don't repeat associations."
|
29
40
|
|
30
41
|
def_node_matcher :association, <<~PATTERN
|
31
|
-
(send nil? {:belongs_to :has_one :has_many :has_and_belongs_to_many} ({sym str} $_)
|
42
|
+
(send nil? {:belongs_to :has_one :has_many :has_and_belongs_to_many} ({sym str} $_) $...)
|
43
|
+
PATTERN
|
44
|
+
|
45
|
+
def_node_matcher :class_name, <<~PATTERN
|
46
|
+
(hash (pair (sym :class_name) $_))
|
32
47
|
PATTERN
|
33
48
|
|
34
49
|
def on_class(class_node)
|
35
|
-
|
36
|
-
nodes.each do |node|
|
37
|
-
add_offense(node, message: format(MSG, name: name)) do |corrector|
|
38
|
-
next if same_line?(nodes.last, node)
|
50
|
+
return unless active_record?(class_node.parent_class)
|
39
51
|
|
40
|
-
|
41
|
-
|
42
|
-
|
52
|
+
association_nodes = association_nodes(class_node)
|
53
|
+
|
54
|
+
duplicated_association_name_nodes(association_nodes).each do |name, nodes|
|
55
|
+
register_offense(name, nodes, MSG)
|
56
|
+
end
|
57
|
+
|
58
|
+
duplicated_class_name_nodes(association_nodes).each do |class_name, nodes|
|
59
|
+
register_offense(class_name, nodes, MSG_CLASS_NAME)
|
43
60
|
end
|
44
61
|
end
|
45
62
|
|
46
63
|
private
|
47
64
|
|
48
|
-
def
|
49
|
-
|
50
|
-
|
51
|
-
|
65
|
+
def register_offense(name, nodes, message_template)
|
66
|
+
nodes.each do |node|
|
67
|
+
add_offense(node, message: format(message_template, name: name)) do |corrector|
|
68
|
+
next if same_line?(nodes.last, node)
|
69
|
+
|
70
|
+
corrector.remove(range_by_whole_lines(node.source_range, include_final_newline: true))
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def association_nodes(class_node)
|
76
|
+
class_send_nodes(class_node).select do |node|
|
77
|
+
association(node)&.first
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def duplicated_association_name_nodes(association_nodes)
|
82
|
+
grouped_associations = association_nodes.group_by do |node|
|
83
|
+
association(node).first.to_sym
|
84
|
+
end
|
85
|
+
|
86
|
+
leave_duplicated_association(grouped_associations)
|
87
|
+
end
|
88
|
+
|
89
|
+
def duplicated_class_name_nodes(association_nodes)
|
90
|
+
filtered_nodes = association_nodes.reject { |node| node.method?(:belongs_to) }
|
91
|
+
grouped_associations = filtered_nodes.group_by do |node|
|
92
|
+
arguments = association(node).last
|
93
|
+
next unless arguments.count == 1
|
94
|
+
|
95
|
+
if (class_name = class_name(arguments.first))
|
96
|
+
class_name.source
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
grouped_associations.delete(nil)
|
101
|
+
|
102
|
+
leave_duplicated_association(grouped_associations)
|
103
|
+
end
|
104
|
+
|
105
|
+
def leave_duplicated_association(grouped_associations)
|
106
|
+
grouped_associations.select do |_, nodes|
|
107
|
+
nodes.length > 1
|
108
|
+
end
|
52
109
|
end
|
53
110
|
end
|
54
111
|
end
|
@@ -74,13 +74,13 @@ module RuboCop
|
|
74
74
|
end
|
75
75
|
|
76
76
|
def allowed_method?(node)
|
77
|
-
return unless cop_config['AllowedMethods']
|
77
|
+
return false unless cop_config['AllowedMethods']
|
78
78
|
|
79
79
|
cop_config['AllowedMethods'].include?(node.method_name.to_s)
|
80
80
|
end
|
81
81
|
|
82
82
|
def allowed_receiver?(node)
|
83
|
-
return unless cop_config['AllowedReceivers'] && node.receiver
|
83
|
+
return false unless cop_config['AllowedReceivers'] && node.receiver
|
84
84
|
|
85
85
|
cop_config['AllowedReceivers'].include?(node.receiver.source)
|
86
86
|
end
|
@@ -88,7 +88,7 @@ module RuboCop
|
|
88
88
|
# config option `WhiteList` will be deprecated soon
|
89
89
|
def whitelisted?(node)
|
90
90
|
whitelist_config = cop_config['Whitelist']
|
91
|
-
return unless whitelist_config
|
91
|
+
return false unless whitelist_config
|
92
92
|
|
93
93
|
whitelist_config.include?(node.method_name.to_s)
|
94
94
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RuboCop
|
4
|
+
module Cop
|
5
|
+
module Rails
|
6
|
+
# Checks for usage of `Rails.env.development? || Rails.env.test?` which
|
7
|
+
# can be replaced with `Rails.env.local?`, introduced in Rails 7.1.
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
#
|
11
|
+
# # bad
|
12
|
+
# Rails.env.development? || Rails.env.test?
|
13
|
+
#
|
14
|
+
# # good
|
15
|
+
# Rails.env.local?
|
16
|
+
#
|
17
|
+
class EnvLocal < Base
|
18
|
+
extend AutoCorrector
|
19
|
+
extend TargetRailsVersion
|
20
|
+
|
21
|
+
MSG = 'Use `Rails.env.local?` instead.'
|
22
|
+
LOCAL_ENVIRONMENTS = %i[development? test?].to_set.freeze
|
23
|
+
|
24
|
+
minimum_target_rails_version 7.1
|
25
|
+
|
26
|
+
# @!method rails_env_local_candidate?(node)
|
27
|
+
def_node_matcher :rails_env_local_candidate?, <<~PATTERN
|
28
|
+
(or
|
29
|
+
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
|
30
|
+
(send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS)
|
31
|
+
)
|
32
|
+
PATTERN
|
33
|
+
|
34
|
+
def on_or(node)
|
35
|
+
rails_env_local_candidate?(node) do |*environments|
|
36
|
+
next unless environments.to_set == LOCAL_ENVIRONMENTS
|
37
|
+
|
38
|
+
add_offense(node) do |corrector|
|
39
|
+
corrector.replace(node, 'Rails.env.local?')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -180,6 +180,9 @@ module RuboCop
|
|
180
180
|
side: :right
|
181
181
|
)
|
182
182
|
)
|
183
|
+
node.arguments.filter(&:str_type?).each do |argument|
|
184
|
+
corrector.replace(argument, argument.value.delete_prefix('/').inspect)
|
185
|
+
end
|
183
186
|
corrector.insert_after(node, '.to_s')
|
184
187
|
end
|
185
188
|
|
@@ -230,7 +233,7 @@ module RuboCop
|
|
230
233
|
end
|
231
234
|
|
232
235
|
def extension_node?(node)
|
233
|
-
node&.str_type? && node.source.
|
236
|
+
node&.str_type? && node.source.match?(/\A\.[A-Za-z]+/)
|
234
237
|
end
|
235
238
|
end
|
236
239
|
end
|
@@ -69,7 +69,7 @@ module RuboCop
|
|
69
69
|
return false unless CONVERT_METHODS.include?(method_name)
|
70
70
|
|
71
71
|
child_node, child_method_name, time_argument = *node.children
|
72
|
-
return if time_argument
|
72
|
+
return false if time_argument
|
73
73
|
|
74
74
|
current_time?(child_node, child_method_name)
|
75
75
|
end
|
@@ -6,7 +6,7 @@ module RuboCop
|
|
6
6
|
# Checks for use of the helper methods which reference
|
7
7
|
# instance variables.
|
8
8
|
#
|
9
|
-
# Relying on instance variables makes it difficult to
|
9
|
+
# Relying on instance variables makes it difficult to reuse helper
|
10
10
|
# methods.
|
11
11
|
#
|
12
12
|
# If it seems awkward to explicitly pass in each dependent
|