From d87632352e571be56cbfef475a0e3212c20ed5e1 Mon Sep 17 00:00:00 2001 From: r7kamura Date: Thu, 11 May 2023 04:04:58 +0900 Subject: [PATCH 01/52] Change `Rails/RootPathnameMethods` to detect offenses on `Dir.[]` --- ...e_methods_to_detect_offenses_on_dir_index.md | 1 + lib/rubocop/cop/rails/root_pathname_methods.rb | 10 +++++----- .../cop/rails/root_pathname_methods_spec.rb | 17 ++++++++++++++--- 3 files changed, 20 insertions(+), 8 deletions(-) create mode 100644 changelog/change_rails_root_pathname_methods_to_detect_offenses_on_dir_index.md diff --git a/changelog/change_rails_root_pathname_methods_to_detect_offenses_on_dir_index.md b/changelog/change_rails_root_pathname_methods_to_detect_offenses_on_dir_index.md new file mode 100644 index 0000000000..30a32029f1 --- /dev/null +++ b/changelog/change_rails_root_pathname_methods_to_detect_offenses_on_dir_index.md @@ -0,0 +1 @@ +* [#1003](https://github.com/rubocop/rubocop-rails/pull/1003): Change `Rails/RootPathnameMethods` to detect offenses on `Dir.[]`. ([@r7kamura][]) diff --git a/lib/rubocop/cop/rails/root_pathname_methods.rb b/lib/rubocop/cop/rails/root_pathname_methods.rb index da308656a4..233b1744d0 100644 --- a/lib/rubocop/cop/rails/root_pathname_methods.rb +++ b/lib/rubocop/cop/rails/root_pathname_methods.rb @@ -38,7 +38,7 @@ class RootPathnameMethods < Base # rubocop:disable Metrics/ClassLength MSG = '`%s` is a `Pathname` so you can just append `#%s`.' - DIR_GLOB_METHODS = %i[glob].to_set.freeze + DIR_GLOB_METHODS = %i[[] glob].to_set.freeze DIR_NON_GLOB_METHODS = %i[ children @@ -171,7 +171,7 @@ class RootPathnameMethods < Base # rubocop:disable Metrics/ClassLength def_node_matcher :dir_glob?, <<~PATTERN (send - (const {cbase nil?} :Dir) :glob ...) + (const {cbase nil?} :Dir) DIR_GLOB_METHODS ...) PATTERN def_node_matcher :rails_root_pathname?, <<~PATTERN @@ -190,7 +190,7 @@ def on_send(node) evidence(node) do |method, path, args, rails_root| add_offense(node, message: format(MSG, method: method, rails_root: rails_root.source)) do |corrector| replacement = if dir_glob?(node) - build_path_glob_replacement(path, method) + build_path_glob_replacement(path) else build_path_replacement(path, method, args) end @@ -217,12 +217,12 @@ def pathname_method(node) end end - def build_path_glob_replacement(path, method) + def build_path_glob_replacement(path) receiver = range_between(path.source_range.begin_pos, path.children.first.loc.selector.end_pos).source argument = path.arguments.one? ? path.first_argument.source : join_arguments(path.arguments) - "#{receiver}.#{method}(#{argument})" + "#{receiver}.glob(#{argument})" end def build_path_replacement(path, method, args) diff --git a/spec/rubocop/cop/rails/root_pathname_methods_spec.rb b/spec/rubocop/cop/rails/root_pathname_methods_spec.rb index fdeeeba603..04b9508073 100644 --- a/spec/rubocop/cop/rails/root_pathname_methods_spec.rb +++ b/spec/rubocop/cop/rails/root_pathname_methods_spec.rb @@ -2,15 +2,13 @@ RSpec.describe RuboCop::Cop::Rails::RootPathnameMethods, :config do { - Dir: described_class::DIR_METHODS, + Dir: described_class::DIR_NON_GLOB_METHODS, File: described_class::FILE_METHODS, FileTest: described_class::FILE_TEST_METHODS, FileUtils: described_class::FILE_UTILS_METHODS, IO: described_class::FILE_METHODS }.each do |receiver, methods| methods.each do |method| - next if method == :glob - it "registers an offense when using `#{receiver}.#{method}(Rails.public_path)` (if arity exists)" do expect_offense(<<~RUBY, receiver: receiver, method: method) %{receiver}.%{method}(Rails.public_path) @@ -143,6 +141,19 @@ end end + context 'when using Dir.[] on Ruby 2.5 or higher', :ruby25 do + it 'registers offense when using `Dir[Rails.root.join(...)]`' do + expect_offense(<<~RUBY) + Dir[Rails.root.join('spec/support/**/*.rb')] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#[]`. + RUBY + + expect_correction(<<~RUBY) + Rails.root.glob('spec/support/**/*.rb') + RUBY + end + end + # This is handled by `Rails/RootJoinChain` it 'does not register an offense when using `File.read(Rails.root.join(...).join(...))`' do expect_no_offenses(<<~RUBY) From 78c6796e93a20ad4642d7c35f1aaeb0416c569fe Mon Sep 17 00:00:00 2001 From: ytjmt <46666464+ytjmt@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:18:49 +0900 Subject: [PATCH 02/52] Support Rails 7 syntax for Rails/EnumHash cop --- ..._rails_7_syntax_for_rails_enum_hash_cop.md | 1 + lib/rubocop/cop/rails/enum_hash.rb | 39 +- spec/rubocop/cop/rails/enum_hash_spec.rb | 431 +++++++++++++----- 3 files changed, 354 insertions(+), 117 deletions(-) create mode 100644 changelog/new_support_rails_7_syntax_for_rails_enum_hash_cop.md diff --git a/changelog/new_support_rails_7_syntax_for_rails_enum_hash_cop.md b/changelog/new_support_rails_7_syntax_for_rails_enum_hash_cop.md new file mode 100644 index 0000000000..355a76dd25 --- /dev/null +++ b/changelog/new_support_rails_7_syntax_for_rails_enum_hash_cop.md @@ -0,0 +1 @@ +* [#1309](https://github.com/rubocop/rubocop-rails/pull/1309): Support Rails 7 syntax for `Rails/EnumHash` cop. ([@ytjmt][]) diff --git a/lib/rubocop/cop/rails/enum_hash.rb b/lib/rubocop/cop/rails/enum_hash.rb index 2b69e2e2ee..8fa54c1749 100644 --- a/lib/rubocop/cop/rails/enum_hash.rb +++ b/lib/rubocop/cop/rails/enum_hash.rb @@ -12,6 +12,12 @@ module Rails # # @example # # bad + # enum :status, [:active, :archived] + # + # # good + # enum :status, { active: 0, archived: 1 } + # + # # bad # enum status: [:active, :archived] # # # good @@ -23,7 +29,11 @@ class EnumHash < Base MSG = 'Enum defined as an array found in `%s` enum declaration. Use hash syntax instead.' RESTRICT_ON_SEND = %i[enum].freeze - def_node_matcher :enum?, <<~PATTERN + def_node_matcher :enum_with_array?, <<~PATTERN + (send nil? :enum $_ ${array} ...) + PATTERN + + def_node_matcher :enum_with_old_syntax?, <<~PATTERN (send nil? :enum (hash $...)) PATTERN @@ -32,17 +42,19 @@ class EnumHash < Base PATTERN def on_send(node) - enum?(node) do |pairs| + target_rails_version >= 7.0 && enum_with_array?(node) do |key, array| + add_offense(array, message: message(key)) do |corrector| + corrector.replace(array, build_hash(array)) + end + end + + enum_with_old_syntax?(node) do |pairs| pairs.each do |pair| key, array = array_pair?(pair) next unless key - add_offense(array, message: format(MSG, enum: enum_name(key))) do |corrector| - hash = array.children.each_with_index.map do |elem, index| - "#{source(elem)} => #{index}" - end.join(', ') - - corrector.replace(array, "{#{hash}}") + add_offense(array, message: message(key)) do |corrector| + corrector.replace(array, build_hash(array)) end end end @@ -50,6 +62,10 @@ def on_send(node) private + def message(key) + format(MSG, enum: enum_name(key)) + end + def enum_name(key) case key.type when :sym, :str @@ -69,6 +85,13 @@ def source(elem) elem.source end end + + def build_hash(array) + hash = array.children.each_with_index.map do |elem, index| + "#{source(elem)} => #{index}" + end.join(', ') + "{#{hash}}" + end end end end diff --git a/spec/rubocop/cop/rails/enum_hash_spec.rb b/spec/rubocop/cop/rails/enum_hash_spec.rb index d3aff4388c..6ad8a0f52a 100644 --- a/spec/rubocop/cop/rails/enum_hash_spec.rb +++ b/spec/rubocop/cop/rails/enum_hash_spec.rb @@ -1,162 +1,375 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Rails::EnumHash, :config do - context 'when array syntax is used' do - context 'with %i[] syntax' do - it 'registers an offense' do + context 'when Rails 7 syntax is used', :rails70 do + context 'when array syntax is used' do + context 'with %i[] syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum :status, %i[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {:active => 0, :archived => 1} + RUBY + end + end + + context 'with %w[] syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum :status, %w[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {"active" => 0, "archived" => 1} + RUBY + end + end + + context 'with %i() syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum :status, %i(active archived) + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {:active => 0, :archived => 1} + RUBY + end + end + + context 'with %w() syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum :status, %w(active archived) + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {"active" => 0, "archived" => 1} + RUBY + end + end + + context 'with [] syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum :status, [:active, :archived] + ^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {:active => 0, :archived => 1} + RUBY + end + end + + context 'when the enum name is a string' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum "status", %i[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum "status", {:active => 0, :archived => 1} + RUBY + end + end + + context 'when the enum name is not a literal' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum KEY, %i[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `KEY` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum KEY, {:active => 0, :archived => 1} + RUBY + end + end + + it 'autocorrects' do expect_offense(<<~RUBY) - enum status: %i[active archived] - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + enum :status, [:old, :"very active", "is archived", 42] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {:old => 0, :"very active" => 1, "is archived" => 2, 42 => 3} RUBY end - end - context 'with %w[] syntax' do - it 'registers an offense' do + it 'autocorrects constants' do expect_offense(<<~RUBY) - enum status: %w[active archived] - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + enum :status, [OLD, ACTIVE] + ^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {OLD => 0, ACTIVE => 1} RUBY end - end - context 'with %i() syntax' do - it 'registers an offense' do + it 'autocorrects nested constants' do expect_offense(<<~RUBY) - enum status: %i(active archived) - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + enum :status, [STATUS::OLD, STATUS::ACTIVE] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {STATUS::OLD => 0, STATUS::ACTIVE => 1} RUBY end - end - context 'with %w() syntax' do - it 'registers an offense' do + it 'autocorrects %w[] syntax' do expect_offense(<<~RUBY) - enum status: %w(active archived) - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + enum :status, %w[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {"active" => 0, "archived" => 1} RUBY end - end - context 'with [] syntax' do - it 'registers an offense' do + it 'autocorrect %w() syntax' do expect_offense(<<~RUBY) - enum status: [:active, :archived] - ^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + enum :status, %w(active archived) + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {"active" => 0, "archived" => 1} RUBY end - end - context 'when the enum name is a string' do - it 'registers an offense' do + it 'autocorrect %i[] syntax' do expect_offense(<<~RUBY) - enum "status" => %i[active archived] - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + enum :status, %i[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {:active => 0, :archived => 1} RUBY end - end - context 'when the enum name is not a literal' do - it 'registers an offense' do + it 'autocorrect %i() syntax' do expect_offense(<<~RUBY) - enum KEY => %i[active archived] - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `KEY` enum declaration. Use hash syntax instead. + enum :status, %i(active archived) + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, {:active => 0, :archived => 1} RUBY end end - context 'with multiple enum definition for a `enum` method call' do - it 'registers an offense' do - expect_offense(<<~RUBY) - enum status: %i[active archived], - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. - role: %i[owner member guest] - ^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `role` enum declaration. Use hash syntax instead. - RUBY + context 'when hash syntax is used' do + it 'does not register an offense' do + expect_no_offenses('enum :status, { active: 0, archived: 1 }') end end + end - it 'autocorrects' do - expect_offense(<<~RUBY) - enum status: [:old, :"very active", "is archived", 42] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. - RUBY + context 'when old syntax is used' do + context 'when array syntax is used' do + context 'with %i[] syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum status: %i[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY - expect_correction(<<~RUBY) - enum status: {:old => 0, :"very active" => 1, "is archived" => 2, 42 => 3} - RUBY - end + expect_correction(<<~RUBY) + enum status: {:active => 0, :archived => 1} + RUBY + end + end - it 'autocorrects constants' do - expect_offense(<<~RUBY) - enum status: [OLD, ACTIVE] - ^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. - RUBY + context 'with %w[] syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum status: %w[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY - expect_correction(<<~RUBY) - enum status: {OLD => 0, ACTIVE => 1} - RUBY - end + expect_correction(<<~RUBY) + enum status: {"active" => 0, "archived" => 1} + RUBY + end + end - it 'autocorrects nested constants' do - expect_offense(<<~RUBY) - enum status: [STATUS::OLD, STATUS::ACTIVE] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. - RUBY + context 'with %i() syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum status: %i(active archived) + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY - expect_correction(<<~RUBY) - enum status: {STATUS::OLD => 0, STATUS::ACTIVE => 1} - RUBY - end + expect_correction(<<~RUBY) + enum status: {:active => 0, :archived => 1} + RUBY + end + end - it 'autocorrects %w[] syntax' do - expect_offense(<<~RUBY) - enum status: %w[active archived] - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. - RUBY + context 'with %w() syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum status: %w(active archived) + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY - expect_correction(<<~RUBY) - enum status: {"active" => 0, "archived" => 1} - RUBY - end + expect_correction(<<~RUBY) + enum status: {"active" => 0, "archived" => 1} + RUBY + end + end - it 'autocorrect %w() syntax' do - expect_offense(<<~RUBY) - enum status: %w(active archived) - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. - RUBY + context 'with [] syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum status: [:active, :archived] + ^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY - expect_correction(<<~RUBY) - enum status: {"active" => 0, "archived" => 1} - RUBY - end + expect_correction(<<~RUBY) + enum status: {:active => 0, :archived => 1} + RUBY + end + end - it 'autocorrect %i[] syntax' do - expect_offense(<<~RUBY) - enum status: %i[active archived] - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. - RUBY + context 'when the enum name is a string' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum "status" => %i[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY - expect_correction(<<~RUBY) - enum status: {:active => 0, :archived => 1} - RUBY - end + expect_correction(<<~RUBY) + enum "status" => {:active => 0, :archived => 1} + RUBY + end + end + + context 'when the enum name is not a literal' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum KEY => %i[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `KEY` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum KEY => {:active => 0, :archived => 1} + RUBY + end + end + + context 'with multiple enum definition for a `enum` method call' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum status: %i[active archived], + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + role: %i[owner member guest] + ^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `role` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum status: {:active => 0, :archived => 1}, + role: {:owner => 0, :member => 1, :guest => 2} + RUBY + end + end + + it 'autocorrects' do + expect_offense(<<~RUBY) + enum status: [:old, :"very active", "is archived", 42] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum status: {:old => 0, :"very active" => 1, "is archived" => 2, 42 => 3} + RUBY + end + + it 'autocorrects constants' do + expect_offense(<<~RUBY) + enum status: [OLD, ACTIVE] + ^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum status: {OLD => 0, ACTIVE => 1} + RUBY + end + + it 'autocorrects nested constants' do + expect_offense(<<~RUBY) + enum status: [STATUS::OLD, STATUS::ACTIVE] + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum status: {STATUS::OLD => 0, STATUS::ACTIVE => 1} + RUBY + end + + it 'autocorrects %w[] syntax' do + expect_offense(<<~RUBY) + enum status: %w[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum status: {"active" => 0, "archived" => 1} + RUBY + end + + it 'autocorrect %w() syntax' do + expect_offense(<<~RUBY) + enum status: %w(active archived) + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY - it 'autocorrect %i() syntax' do - expect_offense(<<~RUBY) - enum status: %i(active archived) - ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. - RUBY + expect_correction(<<~RUBY) + enum status: {"active" => 0, "archived" => 1} + RUBY + end - expect_correction(<<~RUBY) - enum status: {:active => 0, :archived => 1} - RUBY + it 'autocorrect %i[] syntax' do + expect_offense(<<~RUBY) + enum status: %i[active archived] + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum status: {:active => 0, :archived => 1} + RUBY + end + + it 'autocorrect %i() syntax' do + expect_offense(<<~RUBY) + enum status: %i(active archived) + ^^^^^^^^^^^^^^^^^^^ Enum defined as an array found in `status` enum declaration. Use hash syntax instead. + RUBY + + expect_correction(<<~RUBY) + enum status: {:active => 0, :archived => 1} + RUBY + end end - end - context 'when hash syntax is used' do - it 'does not register an offense' do - expect_no_offenses('enum status: { active: 0, archived: 1 }') + context 'when hash syntax is used' do + it 'does not register an offense' do + expect_no_offenses('enum status: { active: 0, archived: 1 }') + end end end end From 482779255b43a01646a58569935fc2273b2f55f2 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Mon, 12 Aug 2024 13:32:52 +0200 Subject: [PATCH 03/52] Fix wrong autocorrect for `Rails/FilePath` when passing an array to `File.join` `File.join` actually accepts nested arrays and will unflatten them as necessary. Don't bother implementing autocorrect for these cases, seems complicated and not worth the effort. The current correction for these testcases look like this: ```rb Rails.root.join().to_s ``` --- ...x_wrong_autocorrect_for_rails_file_path.md | 1 + lib/rubocop/cop/rails/file_path.rb | 2 +- spec/rubocop/cop/rails/file_path_spec.rb | 20 +++++++++++++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_wrong_autocorrect_for_rails_file_path.md diff --git a/changelog/fix_wrong_autocorrect_for_rails_file_path.md b/changelog/fix_wrong_autocorrect_for_rails_file_path.md new file mode 100644 index 0000000000..10b2da3ae5 --- /dev/null +++ b/changelog/fix_wrong_autocorrect_for_rails_file_path.md @@ -0,0 +1 @@ +* [#1326](https://github.com/rubocop/rubocop-rails/pull/1326): Fix wrong autocorrect for `Rails/FilePath` when passing an array to `File.join`. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/file_path.rb b/lib/rubocop/cop/rails/file_path.rb index f98f37076f..02459031a9 100644 --- a/lib/rubocop/cop/rails/file_path.rb +++ b/lib/rubocop/cop/rails/file_path.rb @@ -97,7 +97,7 @@ def check_for_file_join_with_rails_root(node) return unless node.arguments.any? { |e| rails_root_nodes?(e) } register_offense(node, require_to_s: true) do |corrector| - autocorrect_file_join(corrector, node) + autocorrect_file_join(corrector, node) unless node.first_argument.array_type? end end diff --git a/spec/rubocop/cop/rails/file_path_spec.rb b/spec/rubocop/cop/rails/file_path_spec.rb index 1993e66ba4..3bec9ded2c 100644 --- a/spec/rubocop/cop/rails/file_path_spec.rb +++ b/spec/rubocop/cop/rails/file_path_spec.rb @@ -114,6 +114,26 @@ end end + context 'when using File.join with an array' do + it 'registers an offense' do + expect_offense(<<~RUBY) + File.join([Rails.root, 'foo']) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `Rails.root.join('path/to').to_s`. + RUBY + + expect_no_corrections + end + + it 'registers an offense for nested arrays' do + expect_offense(<<~RUBY) + File.join([Rails.root, 'foo', ['bar']]) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer `Rails.root.join('path/to').to_s`. + RUBY + + expect_no_corrections + end + end + context 'when using Rails.root.join with slash separated path string' do it 'does not register an offense' do expect_no_offenses("Rails.root.join('app/models/goober')") From eecc2bb41c380d762a2212b9a4ce19a8b54c453c Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Mon, 12 Aug 2024 18:25:52 +0200 Subject: [PATCH 04/52] Fix an error for `Rails/RenderPlainText` when the content type is passed as a constant Or other nodes that don't respond to `value` like local variables --- changelog/fix_error_rails_render_plain_text_constant.md | 1 + lib/rubocop/cop/rails/render_plain_text.rb | 9 ++++++--- spec/rubocop/cop/rails/render_plain_text_spec.rb | 6 ++++++ 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 changelog/fix_error_rails_render_plain_text_constant.md diff --git a/changelog/fix_error_rails_render_plain_text_constant.md b/changelog/fix_error_rails_render_plain_text_constant.md new file mode 100644 index 0000000000..0fbab1d458 --- /dev/null +++ b/changelog/fix_error_rails_render_plain_text_constant.md @@ -0,0 +1 @@ +* [#1325](https://github.com/rubocop/rubocop-rails/pull/1325): Fix an error for `Rails/RenderPlainText` when the content type is passed as a constant. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/render_plain_text.rb b/lib/rubocop/cop/rails/render_plain_text.rb index 0736bb3c28..ebf69b742c 100644 --- a/lib/rubocop/cop/rails/render_plain_text.rb +++ b/lib/rubocop/cop/rails/render_plain_text.rb @@ -53,9 +53,12 @@ def find_content_type(node) node.pairs.find { |p| p.key.value.to_sym == :content_type } end - def compatible_content_type?(node) - (node && node.value.value == 'text/plain') || - (!node && !cop_config['ContentTypeCompatibility']) + def compatible_content_type?(pair_node) + if pair_node.nil? + !cop_config['ContentTypeCompatibility'] + elsif pair_node.value.respond_to?(:value) + pair_node.value.value == 'text/plain' + end end def replacement(rest_options, option_value) diff --git a/spec/rubocop/cop/rails/render_plain_text_spec.rb b/spec/rubocop/cop/rails/render_plain_text_spec.rb index 4d69c6edeb..084df4b8f3 100644 --- a/spec/rubocop/cop/rails/render_plain_text_spec.rb +++ b/spec/rubocop/cop/rails/render_plain_text_spec.rb @@ -19,6 +19,12 @@ RUBY end + it 'does not register an offense when `content_type` is a constant' do + expect_no_offenses(<<~RUBY) + render text: 'Ruby!', content_type: Foo + RUBY + end + it 'does not register an offense when using `render plain:`' do expect_no_offenses(<<~RUBY) render plain: 'Ruby!' From 26b18c5091a467b4d0809c5ebef132b83a4075bd Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:59:31 +0200 Subject: [PATCH 05/52] Fix an error for `Rails/WhereNot` without second argument This is basically #401 again, and a bit of #1321 --- .../fix_error_rails_where_not_no_second_argument.md | 1 + lib/rubocop/cop/rails/where_not.rb | 10 +++++----- spec/rubocop/cop/rails/where_not_spec.rb | 12 ++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 changelog/fix_error_rails_where_not_no_second_argument.md diff --git a/changelog/fix_error_rails_where_not_no_second_argument.md b/changelog/fix_error_rails_where_not_no_second_argument.md new file mode 100644 index 0000000000..437da24eb6 --- /dev/null +++ b/changelog/fix_error_rails_where_not_no_second_argument.md @@ -0,0 +1 @@ +* [#1330](https://github.com/rubocop/rubocop-rails/pull/1330): Fix an error for `Rails/WhereNot` when using placeholder without second argument. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/where_not.rb b/lib/rubocop/cop/rails/where_not.rb index 742fc56073..96762f5e47 100644 --- a/lib/rubocop/cop/rails/where_not.rb +++ b/lib/rubocop/cop/rails/where_not.rb @@ -43,10 +43,10 @@ def on_send(node) range = offense_range(node) - column_and_value = extract_column_and_value(template_node, value_node) - return unless column_and_value + column, value = extract_column_and_value(template_node, value_node) + return unless value - good_method = build_good_method(node.loc.dot&.source, *column_and_value) + good_method = build_good_method(node.loc.dot&.source, column, value) message = format(MSG, good_method: good_method) add_offense(range, message: message) do |corrector| @@ -72,9 +72,9 @@ def extract_column_and_value(template_node, value_node) value = case template_node.value when NOT_EQ_ANONYMOUS_RE, NOT_IN_ANONYMOUS_RE - value_node.source + value_node&.source when NOT_EQ_NAMED_RE, NOT_IN_NAMED_RE - return unless value_node.hash_type? + return unless value_node&.hash_type? pair = value_node.pairs.find { |p| p.key.value.to_sym == Regexp.last_match(2).to_sym } pair.value.source diff --git a/spec/rubocop/cop/rails/where_not_spec.rb b/spec/rubocop/cop/rails/where_not_spec.rb index d0dfd4ce2a..84d8aeded0 100644 --- a/spec/rubocop/cop/rails/where_not_spec.rb +++ b/spec/rubocop/cop/rails/where_not_spec.rb @@ -12,6 +12,12 @@ RUBY end + it 'registers no offense when using `!=` and anonymous placeholder without second argument' do + expect_no_offenses(<<~RUBY) + User.where('name != ?') + RUBY + end + it 'registers an offense and corrects when using `!=` and anonymous placeholder with safe navigation' do expect_offense(<<~RUBY) User&.where('name != ?', 'Gabe') @@ -89,6 +95,12 @@ RUBY end + it 'registers no offense when using `NOT IN` and named placeholder without second argument' do + expect_no_offenses(<<~RUBY) + User.where("name NOT IN (:names)") + RUBY + end + it 'registers an offense and corrects when using `!=` and namespaced columns' do expect_offense(<<~RUBY) Course.where('enrollments.student_id != ?', student.id) From 3885fcce786fc6df9bfb2a84d3b6e9399ab90c2b Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:53:24 +0200 Subject: [PATCH 06/52] [Fix #1199] Make `Rails/WhereEquals` aware of `where.not(...)` This copies a bit of logic from `WhereRange` but they need slighly different handling and it doesn't seem worth to extract yet. --- ...ix_make_rails_where_equals_aware_of_not.md | 1 + config/default.yml | 4 +-- lib/rubocop/cop/rails/where_equals.rb | 27 +++++++++++++------ spec/rubocop/cop/rails/where_equals_spec.rb | 17 ++++++++++++ 4 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 changelog/fix_make_rails_where_equals_aware_of_not.md diff --git a/changelog/fix_make_rails_where_equals_aware_of_not.md b/changelog/fix_make_rails_where_equals_aware_of_not.md new file mode 100644 index 0000000000..1a61ab42f3 --- /dev/null +++ b/changelog/fix_make_rails_where_equals_aware_of_not.md @@ -0,0 +1 @@ +* [#1199](https://github.com/rubocop/rubocop-rails/issues/1199): Make `Rails/WhereEquals` aware of `where.not(...)`. ([@earlopain][]) diff --git a/config/default.yml b/config/default.yml index 561b36484a..1f3b5376dc 100644 --- a/config/default.yml +++ b/config/default.yml @@ -1185,12 +1185,12 @@ Rails/Validation: - app/models/**/*.rb Rails/WhereEquals: - Description: 'Pass conditions to `where` as a hash instead of manually constructing SQL.' + Description: 'Pass conditions to `where` and `where.not` as a hash instead of manually constructing SQL.' StyleGuide: 'https://rails.rubystyle.guide/#hash-conditions' Enabled: 'pending' SafeAutoCorrect: false VersionAdded: '2.9' - VersionChanged: '2.10' + VersionChanged: <> Rails/WhereExists: Description: 'Prefer `exists?(...)` over `where(...).exists?`.' diff --git a/lib/rubocop/cop/rails/where_equals.rb b/lib/rubocop/cop/rails/where_equals.rb index ce5b6d2a58..b1d56b7c24 100644 --- a/lib/rubocop/cop/rails/where_equals.rb +++ b/lib/rubocop/cop/rails/where_equals.rb @@ -4,7 +4,8 @@ module RuboCop module Cop module Rails # Identifies places where manually constructed SQL - # in `where` can be replaced with `where(attribute: value)`. + # in `where` and `where.not` can be replaced with + # `where(attribute: value)` and `where.not(attribute: value)`. # # @safety # This cop's autocorrection is unsafe because is may change SQL. @@ -13,6 +14,7 @@ module Rails # @example # # bad # User.where('name = ?', 'Gabe') + # User.where.not('name = ?', 'Gabe') # User.where('name = :name', name: 'Gabe') # User.where('name IS NULL') # User.where('name IN (?)', ['john', 'jane']) @@ -21,6 +23,7 @@ module Rails # # # good # User.where(name: 'Gabe') + # User.where.not(name: 'Gabe') # User.where(name: nil) # User.where(name: ['john', 'jane']) # User.where(users: { name: 'Gabe' }) @@ -29,16 +32,18 @@ class WhereEquals < Base extend AutoCorrector MSG = 'Use `%s` instead of manually constructing SQL.' - RESTRICT_ON_SEND = %i[where].freeze + RESTRICT_ON_SEND = %i[where not].freeze def_node_matcher :where_method_call?, <<~PATTERN { - (call _ :where (array $str_type? $_ ?)) - (call _ :where $str_type? $_ ?) + (call _ {:where :not} (array $str_type? $_ ?)) + (call _ {:where :not} $str_type? $_ ?) } PATTERN def on_send(node) + return if node.method?(:not) && !where_not?(node) + where_method_call?(node) do |template_node, value_node| value_node = value_node.first @@ -47,7 +52,7 @@ def on_send(node) column, value = extract_column_and_value(template_node, value_node) return unless value - good_method = build_good_method(column, value) + good_method = build_good_method(node.method_name, column, value) message = format(MSG, good_method: good_method) add_offense(range, message: message) do |corrector| @@ -88,15 +93,21 @@ def extract_column_and_value(template_node, value_node) [Regexp.last_match(1), value] end - def build_good_method(column, value) + def build_good_method(method_name, column, value) if column.include?('.') table, column = column.split('.') - "where(#{table}: { #{column}: #{value} })" + "#{method_name}(#{table}: { #{column}: #{value} })" else - "where(#{column}: #{value})" + "#{method_name}(#{column}: #{value})" end end + + def where_not?(node) + return false unless (receiver = node.receiver) + + receiver.send_type? && receiver.method?(:where) + end end end end diff --git a/spec/rubocop/cop/rails/where_equals_spec.rb b/spec/rubocop/cop/rails/where_equals_spec.rb index 11083179f9..1af170ebff 100644 --- a/spec/rubocop/cop/rails/where_equals_spec.rb +++ b/spec/rubocop/cop/rails/where_equals_spec.rb @@ -12,6 +12,17 @@ RUBY end + it 'registers an offense and corrects when using `=` and anonymous placeholder with not' do + expect_offense(<<~RUBY) + User.where.not('name = ?', 'Gabe') + ^^^^^^^^^^^^^^^^^^^^^^^ Use `not(name: 'Gabe')` instead of manually constructing SQL. + RUBY + + expect_correction(<<~RUBY) + User.where.not(name: 'Gabe') + RUBY + end + it 'registers an offense and corrects when using `=` and anonymous placeholder with safe navigation' do expect_offense(<<~RUBY) User&.where('name = ?', 'Gabe') @@ -200,4 +211,10 @@ User.where("name IN (:names)", ) RUBY end + + it 'does not register an offense when using `not` not preceded by `where`' do + expect_no_offenses(<<~RUBY) + users.not('name = ?', 'Gabe') + RUBY + end end From 7616bde4415eff0671c6f92f1bab60020b68e17d Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sun, 18 Aug 2024 00:20:56 +0900 Subject: [PATCH 07/52] Update a changelog file name Follow https://github.com/rubocop/rubocop-rails/pull/1323#issuecomment-2294855342. --- ...e_of_not.md => change_make_rails_where_equals_aware_of_not.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename changelog/{fix_make_rails_where_equals_aware_of_not.md => change_make_rails_where_equals_aware_of_not.md} (100%) diff --git a/changelog/fix_make_rails_where_equals_aware_of_not.md b/changelog/change_make_rails_where_equals_aware_of_not.md similarity index 100% rename from changelog/fix_make_rails_where_equals_aware_of_not.md rename to changelog/change_make_rails_where_equals_aware_of_not.md From 9241cbea69407240af34c8acfc2eb8816f0aea53 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Wed, 21 Aug 2024 12:25:55 +0200 Subject: [PATCH 08/52] Don't use deprecated `Cop.registry` in specs Also update cop filtering for https://github.com/rubocop/rubocop/pull/13123 --- spec/project_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/project_spec.rb b/spec/project_spec.rb index 2b50ae0a0f..0e48135a52 100644 --- a/spec/project_spec.rb +++ b/spec/project_spec.rb @@ -251,7 +251,7 @@ end let(:existing_cop_names) do - RuboCop::Cop::Cop.registry.without_department(:Test).without_department(:Test2).cops.to_set(&:cop_name) + RuboCop::Cop::Registry.global.reject { |cop| cop.cop_name.start_with?('Test/') }.to_set(&:cop_name) end let(:legacy_cop_names) do From 83b185f52d575efaf46a58b0ab65702b1b1efa26 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Wed, 21 Aug 2024 17:36:28 +0200 Subject: [PATCH 09/52] Fix an error for `Rails/BulkChangeTable` when the block for `change_table` is empty --- .../fix_error_rails_bulk_change_table.md | 1 + lib/rubocop/cop/rails/bulk_change_table.rb | 4 +-- .../cop/rails/bulk_change_table_spec.rb | 25 +++++++++++++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 changelog/fix_error_rails_bulk_change_table.md diff --git a/changelog/fix_error_rails_bulk_change_table.md b/changelog/fix_error_rails_bulk_change_table.md new file mode 100644 index 0000000000..3b01fd4dbe --- /dev/null +++ b/changelog/fix_error_rails_bulk_change_table.md @@ -0,0 +1 @@ +* [#1335](https://github.com/rubocop/rubocop-rails/pull/1335): Fix an error for `Rails/BulkChangeTable` when the block for `change_table` is empty. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/bulk_change_table.rb b/lib/rubocop/cop/rails/bulk_change_table.rb index 09a4b930f2..83ebb9b70e 100644 --- a/lib/rubocop/cop/rails/bulk_change_table.rb +++ b/lib/rubocop/cop/rails/bulk_change_table.rb @@ -140,9 +140,9 @@ def on_send(node) return unless support_bulk_alter? return unless node.command?(:change_table) return if include_bulk_options?(node) - return unless node.block_node + return unless (body = node.block_node&.body) - send_nodes = send_nodes_from_change_table_block(node.block_node.body) + send_nodes = send_nodes_from_change_table_block(body) add_offense_for_change_table(node) if count_transformations(send_nodes) > 1 end diff --git a/spec/rubocop/cop/rails/bulk_change_table_spec.rb b/spec/rubocop/cop/rails/bulk_change_table_spec.rb index 28bd5b6ce6..931afb6b99 100644 --- a/spec/rubocop/cop/rails/bulk_change_table_spec.rb +++ b/spec/rubocop/cop/rails/bulk_change_table_spec.rb @@ -25,6 +25,25 @@ def change end end + shared_examples 'wrong arguments' do + it 'does not register an offense for `change_table` with no block' do + expect_no_offenses(<<~RUBY) + def up + change_table(:users) + end + RUBY + end + + it 'does not register an offense for `change_table` with empty block' do + expect_no_offenses(<<~RUBY) + def up + change_table(:users) do + end + end + RUBY + end + end + shared_examples 'no offense' do it 'does not register an offense when including combinable transformations' do expect_no_offenses(<<~RUBY) @@ -45,6 +64,8 @@ def change end RUBY end + + it_behaves_like 'wrong arguments' end shared_examples 'offense for mysql' do @@ -91,6 +112,8 @@ def change end RUBY end + + it_behaves_like 'wrong arguments' end shared_examples 'offense for postgresql' do @@ -153,6 +176,8 @@ def change end RUBY end + + it_behaves_like 'wrong arguments' end it_behaves_like 'no offense' From a9db5f52d18e0458694ee38950c78c639ea6cd50 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:53:32 +0200 Subject: [PATCH 10/52] Update `Rails/Validation` specs to modern style --- spec/rubocop/cop/rails/validation_spec.rb | 325 +++++++++------------- 1 file changed, 137 insertions(+), 188 deletions(-) diff --git a/spec/rubocop/cop/rails/validation_spec.rb b/spec/rubocop/cop/rails/validation_spec.rb index 20f2fabea3..3aa2b891f9 100644 --- a/spec/rubocop/cop/rails/validation_spec.rb +++ b/spec/rubocop/cop/rails/validation_spec.rb @@ -1,225 +1,174 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Rails::Validation, :config do - it 'accepts new style validations' do - expect_no_offenses('validates :name') - end - - described_class::RESTRICT_ON_SEND.each_with_index do |validation, number| - it "registers an offense for #{validation}" do - offenses = inspect_source("#{validation} :name") - expect(offenses.first.message.include?(described_class::ALLOWLIST[number])).to be(true) + described_class::TYPES.each do |type| + it "registers an offense for with validates_#{type}_of" do + type = 'length' if type == 'size' + expect_offense(<<~RUBY, type: type) + validates_#{type}_of :full_name, :birth_date + ^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`. + RUBY + + expect_correction(<<~RUBY) + validates :full_name, :birth_date, #{type}: true + RUBY end - end - describe '#autocorrect' do - shared_examples 'autocorrects' do - it 'autocorrects' do - expect(autocorrect_source(source)).to eq(autocorrected_source) - end - end + it "registers an offense for with validates_#{type}_of when method arguments are enclosed in parentheses" do + type = 'length' if type == 'size' + expect_offense(<<~RUBY, type: type) + validates_#{type}_of(:full_name, :birth_date) + ^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`. + RUBY - shared_examples 'does not autocorrect' do - it 'does not autocorrect' do - expect(autocorrect_source(source)).to eq(source) - end + expect_correction(<<~RUBY) + validates(:full_name, :birth_date, #{type}: true) + RUBY end - described_class::TYPES.each do |type| - context "with validates_#{type}_of" do - let(:autocorrected_source) do - type = 'length' if type == 'size' - - "validates :full_name, :birth_date, #{type}: true" - end - - let(:source) do - "validates_#{type}_of :full_name, :birth_date" - end - - include_examples 'autocorrects' - end - - context "with validates_#{type}_of when method arguments are enclosed in parentheses" do - let(:autocorrected_source) do - type = 'length' if type == 'size' - - "validates(:full_name, :birth_date, #{type}: true)" - end - - let(:source) do - "validates_#{type}_of(:full_name, :birth_date)" - end - - include_examples 'autocorrects' - end - - context "with validates_#{type}_of when attributes are specified with array literal" do - let(:autocorrected_source) do - type = 'length' if type == 'size' - - "validates :full_name, :birth_date, #{type}: true" - end - - let(:source) do - "validates_#{type}_of [:full_name, :birth_date]" - end - - include_examples 'autocorrects' - end - - context "with validates_#{type}_of when attributes are specified with frozen array literal" do - let(:autocorrected_source) do - type = 'length' if type == 'size' - - "validates :full_name, :birth_date, #{type}: true" - end - - let(:source) do - "validates_#{type}_of [:full_name, :birth_date].freeze" - end - - include_examples 'autocorrects' - end - - context "with validates_#{type}_of when attributes are specified with symbol array literal" do - let(:autocorrected_source) do - type = 'length' if type == 'size' - - "validates :full_name, :birth_date, #{type}: true" - end - - let(:source) do - "validates_#{type}_of %i[full_name birth_date]" - end - - include_examples 'autocorrects' - end - - context "with validates_#{type}_of when attributes are specified with frozen symbol array literal" do - let(:autocorrected_source) do - type = 'length' if type == 'size' + it "registers an offense for with validates_#{type}_of when attributes are specified with array literal" do + type = 'length' if type == 'size' + expect_offense(<<~RUBY, type: type) + validates_#{type}_of [:full_name, :birth_date] + ^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`. + RUBY - "validates :full_name, :birth_date, #{type}: true" - end - - let(:source) do - "validates_#{type}_of %i[full_name birth_date].freeze" - end - - include_examples 'autocorrects' - end + expect_correction(<<~RUBY) + validates :full_name, :birth_date, #{type}: true + RUBY end - context 'with single attribute name' do - let(:autocorrected_source) do - 'validates :a, numericality: true' - end - - let(:source) do - 'validates_numericality_of :a' - end + it "registers an offense for with validates_#{type}_of when attributes are specified with frozen array literal" do + type = 'length' if type == 'size' + expect_offense(<<~RUBY, type: type) + validates_#{type}_of [:full_name, :birth_date].freeze + ^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`. + RUBY - include_examples 'autocorrects' + expect_correction(<<~RUBY) + validates :full_name, :birth_date, #{type}: true + RUBY end - context 'with multi attribute names' do - let(:autocorrected_source) do - 'validates :a, :b, numericality: true' - end + it "registers an offense for with validates_#{type}_of when attributes are specified with symbol array literal" do + type = 'length' if type == 'size' + expect_offense(<<~RUBY, type: type) + validates_#{type}_of %i[full_name birth_date] + ^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`. + RUBY - let(:source) do - 'validates_numericality_of :a, :b' - end - - include_examples 'autocorrects' + expect_correction(<<~RUBY) + validates :full_name, :birth_date, #{type}: true + RUBY end - context 'with non-braced hash literal' do - let(:autocorrected_source) do - 'validates :a, :b, numericality: { minimum: 1 }' - end - - let(:source) do - 'validates_numericality_of :a, :b, minimum: 1' - end - - include_examples 'autocorrects' + it "registers an offense for with validates_#{type}_of when " \ + 'attributes are specified with frozen symbol array literal' do + type = 'length' if type == 'size' + expect_offense(<<~RUBY, type: type) + validates_#{type}_of %i[full_name birth_date].freeze + ^^^^^^^^^^^{type}^^^ Prefer the new style validations `validates :column, #{type}: value` over `validates_#{type}_of`. + RUBY + + expect_correction(<<~RUBY) + validates :full_name, :birth_date, #{type}: true + RUBY end + end - context 'with braced hash literal' do - let(:autocorrected_source) do - 'validates :a, :b, numericality: { minimum: 1 }' - end - - let(:source) do - 'validates_numericality_of :a, :b, { minimum: 1 }' - end + it 'registers an offense with single attribute name' do + expect_offense(<<~RUBY) + validates_numericality_of :a + ^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...] + RUBY - include_examples 'autocorrects' - end + expect_correction(<<~RUBY) + validates :a, numericality: true + RUBY + end - context 'with a proc' do - let(:autocorrected_source) do - 'validates :a, :b, comparison: { greater_than: -> { Time.zone.today } }' - end + it 'registers an offense with multi attribute names' do + expect_offense(<<~RUBY) + validates_numericality_of :a, :b + ^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...] + RUBY - let(:source) do - 'validates_comparison_of :a, :b, greater_than: -> { Time.zone.today }' - end + expect_correction(<<~RUBY) + validates :a, :b, numericality: true + RUBY + end - include_examples 'autocorrects' - end + it 'registers an offense with non-braced hash literal' do + expect_offense(<<~RUBY) + validates_numericality_of :a, :b, minimum: 1 + ^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...] + RUBY - context 'with splat' do - let(:autocorrected_source) do - 'validates :a, *b, numericality: true' - end + expect_correction(<<~RUBY) + validates :a, :b, numericality: { minimum: 1 } + RUBY + end - let(:source) do - 'validates_numericality_of :a, *b' - end + it 'registers an offense with braced hash literal' do + expect_offense(<<~RUBY) + validates_numericality_of :a, :b, { minimum: 1 } + ^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...] + RUBY - include_examples 'autocorrects' - end + expect_correction(<<~RUBY) + validates :a, :b, numericality: { minimum: 1 } + RUBY + end - context 'with splat and options' do - let(:autocorrected_source) do - 'validates :a, *b, :c, numericality: { minimum: 1 }' - end + it 'registers an offense with a proc' do + expect_offense(<<~RUBY) + validates_comparison_of :a, :b, greater_than: -> { Time.zone.today } + ^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...] + RUBY - let(:source) do - 'validates_numericality_of :a, *b, :c, minimum: 1' - end + expect_correction(<<~RUBY) + validates :a, :b, comparison: { greater_than: -> { Time.zone.today } } + RUBY + end - include_examples 'autocorrects' - end + it 'registers an offense with a splat' do + expect_offense(<<~RUBY) + validates_numericality_of :a, *b + ^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...] + RUBY - context 'with trailing send node' do - let(:source) do - 'validates_numericality_of :a, b' - end + expect_correction(<<~RUBY) + validates :a, *b, numericality: true + RUBY + end - include_examples 'does not autocorrect' - end + it 'registers an offense with a splat and options' do + expect_offense(<<~RUBY) + validates_numericality_of :a, *b, :c, minimum: 1 + ^^^^^^^^^^^^^^^^^^^^^^^^^ Prefer the new style [...] + RUBY - context 'with trailing constant' do - let(:source) do - 'validates_numericality_of :a, B' - end + expect_correction(<<~RUBY) + validates :a, *b, :c, numericality: { minimum: 1 } + RUBY + end - include_examples 'does not autocorrect' - end + it 'registers no offense with trailing send node' do + expect_no_offenses(<<~RUBY) + validates_numericality_of :a, b + RUBY + end - context 'with trailing local variable' do - let(:source) do - <<~RUBY - b = { minimum: 1 } - validates_numericality_of :a, b - RUBY - end + it 'registers no offense with trailing constant' do + expect_no_offenses(<<~RUBY) + validates_numericality_of :a, B + RUBY + end - include_examples 'does not autocorrect' - end + it 'registers no offense with trailing local variable' do + expect_no_offenses(<<~RUBY) + b = { minimum: 1 } + validates_numericality_of :a, b + RUBY end end From 5e2237a83ecd3b0277ec9e1ef96ee257af6681d5 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 22 Aug 2024 16:55:52 +0200 Subject: [PATCH 11/52] Fix an error for `Rails/Validation` when passing no arguments --- changelog/fix_error_rails_validation.md | 1 + lib/rubocop/cop/rails/validation.rb | 2 +- spec/rubocop/cop/rails/validation_spec.rb | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_error_rails_validation.md diff --git a/changelog/fix_error_rails_validation.md b/changelog/fix_error_rails_validation.md new file mode 100644 index 0000000000..024d4bf8b9 --- /dev/null +++ b/changelog/fix_error_rails_validation.md @@ -0,0 +1 @@ +* [#1337](https://github.com/rubocop/rubocop-rails/pull/1337): Fix an error for `Rails/Validation` when passing no arguments. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/validation.rb b/lib/rubocop/cop/rails/validation.rb index beaa8f2b6e..bc78b01625 100644 --- a/lib/rubocop/cop/rails/validation.rb +++ b/lib/rubocop/cop/rails/validation.rb @@ -59,11 +59,11 @@ class Validation < Base def on_send(node) return if node.receiver + return unless (last_argument = node.last_argument) range = node.loc.selector add_offense(range, message: message(node)) do |corrector| - last_argument = node.last_argument return if !last_argument.literal? && !last_argument.splat_type? && !frozen_array_argument?(last_argument) corrector.replace(range, 'validates') diff --git a/spec/rubocop/cop/rails/validation_spec.rb b/spec/rubocop/cop/rails/validation_spec.rb index 3aa2b891f9..c178b371d3 100644 --- a/spec/rubocop/cop/rails/validation_spec.rb +++ b/spec/rubocop/cop/rails/validation_spec.rb @@ -171,4 +171,10 @@ validates_numericality_of :a, b RUBY end + + it 'registers no offense when no arguments are passed' do + expect_no_offenses(<<~RUBY) + validates_numericality_of + RUBY + end end From 2201bd878520b25fd9ee04f691dd38ff9021c664 Mon Sep 17 00:00:00 2001 From: Max Prokopiev Date: Fri, 16 Feb 2024 11:02:58 +0100 Subject: [PATCH 12/52] [Fix #1238] Add new `Rails/EnumSyntax` cop Defining enums with keyword arguments is deprecated and will be removed in Rails 8.0. --- .../new_add_new_rails_enum_syntax_cop.md | 1 + config/default.yml | 8 + lib/rubocop/cop/rails/enum_syntax.rb | 126 +++++++++++++ lib/rubocop/cop/rails_cops.rb | 1 + spec/rubocop/cop/rails/enum_syntax_spec.rb | 168 ++++++++++++++++++ 5 files changed, 304 insertions(+) create mode 100644 changelog/new_add_new_rails_enum_syntax_cop.md create mode 100644 lib/rubocop/cop/rails/enum_syntax.rb create mode 100644 spec/rubocop/cop/rails/enum_syntax_spec.rb diff --git a/changelog/new_add_new_rails_enum_syntax_cop.md b/changelog/new_add_new_rails_enum_syntax_cop.md new file mode 100644 index 0000000000..19909d3b66 --- /dev/null +++ b/changelog/new_add_new_rails_enum_syntax_cop.md @@ -0,0 +1 @@ +* [#1238](https://github.com/rubocop/rubocop-rails/issues/1238): Add new `Rails/EnumSyntax` cop. ([@maxprokopiev][], [@koic][]) diff --git a/config/default.yml b/config/default.yml index 1f3b5376dc..f2b87a6367 100644 --- a/config/default.yml +++ b/config/default.yml @@ -424,6 +424,14 @@ Rails/EnumHash: Include: - app/models/**/*.rb +Rails/EnumSyntax: + Description: 'Use positional arguments over keyword arguments when defining enums.' + Enabled: pending + Severity: warning + VersionAdded: '<>' + Include: + - app/models/**/*.rb + Rails/EnumUniqueness: Description: 'Avoid duplicate integers in hash-syntax `enum` declaration.' Enabled: true diff --git a/lib/rubocop/cop/rails/enum_syntax.rb b/lib/rubocop/cop/rails/enum_syntax.rb new file mode 100644 index 0000000000..39501c4331 --- /dev/null +++ b/lib/rubocop/cop/rails/enum_syntax.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # Looks for enums written with keyword arguments syntax. + # + # Defining enums with keyword arguments syntax is deprecated and will be removed in Rails 8.0. + # Positional arguments should be used instead: + # + # @example + # # bad + # enum status: { active: 0, archived: 1 }, _prefix: true + # + # # good + # enum :status, { active: 0, archived: 1 }, prefix: true + # + class EnumSyntax < Base + extend AutoCorrector + extend TargetRailsVersion + + minimum_target_rails_version 7.0 + + MSG = 'Enum defined with keyword arguments in `%s` enum declaration. Use positional arguments instead.' + MSG_OPTIONS = 'Enum defined with deprecated options in `%s` enum declaration. Remove the `_` prefix.' + RESTRICT_ON_SEND = %i[enum].freeze + OPTION_NAMES = %w[prefix suffix scopes default].freeze + + def_node_matcher :enum?, <<~PATTERN + (send nil? :enum (hash $...)) + PATTERN + + def_node_matcher :enum_with_options?, <<~PATTERN + (send nil? :enum $_ ${array hash} $_) + PATTERN + + def_node_matcher :enum_values, <<~PATTERN + (pair $_ ${array hash}) + PATTERN + + def_node_matcher :enum_options, <<~PATTERN + (pair $_ $_) + PATTERN + + def on_send(node) + check_and_correct_keyword_args(node) + check_enum_options(node) + end + + private + + def check_and_correct_keyword_args(node) + enum?(node) do |pairs| + pairs.each do |pair| + key, values = enum_values(pair) + next unless key + + correct_keyword_args(node, key, values, pairs[1..]) + end + end + end + + def check_enum_options(node) + enum_with_options?(node) do |key, _, options| + options.children.each do |option| + name, = enum_options(option) + + add_offense(name, message: format(MSG_OPTIONS, enum: enum_name_value(key))) if name.source[0] == '_' + end + end + end + + def correct_keyword_args(node, key, values, options) + add_offense(values, message: format(MSG, enum: enum_name_value(key))) do |corrector| + # TODO: Multi-line autocorrect could be implemented in the future. + next if multiple_enum_definitions?(node) + + preferred_syntax = "enum #{enum_name(key)}, #{values.source}#{correct_options(options)}" + + corrector.replace(node, preferred_syntax) + end + end + + def multiple_enum_definitions?(node) + keys = node.first_argument.keys.map { |key| key.source.delete_prefix('_') } + filterred_keys = keys.filter { |key| !OPTION_NAMES.include?(key) } + filterred_keys.size >= 2 + end + + def enum_name_value(key) + case key.type + when :sym, :str + key.value + else + key.source + end + end + + def enum_name(elem) + case elem.type + when :str + elem.value.dump + when :sym + elem.value.inspect + else + elem.source + end + end + + def correct_options(options) + corrected_options = options.map do |pair| + name = if pair.key.source[0] == '_' + pair.key.source[1..] + else + pair.key.source + end + + "#{name}: #{pair.value.source}" + end.join(', ') + + ", #{corrected_options}" unless corrected_options.empty? + end + end + end + end +end diff --git a/lib/rubocop/cop/rails_cops.rb b/lib/rubocop/cop/rails_cops.rb index e5173baeb0..b7eddc4fe4 100644 --- a/lib/rubocop/cop/rails_cops.rb +++ b/lib/rubocop/cop/rails_cops.rb @@ -46,6 +46,7 @@ require_relative 'rails/dynamic_find_by' require_relative 'rails/eager_evaluation_log_message' require_relative 'rails/enum_hash' +require_relative 'rails/enum_syntax' require_relative 'rails/enum_uniqueness' require_relative 'rails/env_local' require_relative 'rails/environment_comparison' diff --git a/spec/rubocop/cop/rails/enum_syntax_spec.rb b/spec/rubocop/cop/rails/enum_syntax_spec.rb new file mode 100644 index 0000000000..2abf4e47fa --- /dev/null +++ b/spec/rubocop/cop/rails/enum_syntax_spec.rb @@ -0,0 +1,168 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Rails::EnumSyntax, :config do + context 'Rails >= 7.0', :rails70 do + context 'when keyword arguments are used' do + context 'with %i[] syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum status: %i[active archived], _prefix: true + ^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `status` enum declaration. Use positional arguments instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, %i[active archived], prefix: true + RUBY + end + end + + context 'with %i[] syntax with multiple enum definitions' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum x: %i[foo bar], y: %i[baz qux] + ^^^^^^^^^^^ Enum defined with keyword arguments in `x` enum declaration. Use positional arguments instead. + ^^^^^^^^^^^ Enum defined with keyword arguments in `y` enum declaration. Use positional arguments instead. + RUBY + + # TODO: It could be autocorrected, but it hasn't been implemented yet because it's a rare case. + # + # enum :x, %i[foo bar] + # enum :y, %i[baz qux] + # + expect_no_corrections + end + end + + context 'with hash syntax' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum status: { active: 0, archived: 1 }, _prefix: true + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `status` enum declaration. Use positional arguments instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, { active: 0, archived: 1 }, prefix: true + RUBY + end + end + + context 'with options prefixed with `_`' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum :status, { active: 0, archived: 1 }, _prefix: true, _suffix: true + ^^^^^^^ Enum defined with deprecated options in `status` enum declaration. Remove the `_` prefix. + ^^^^^^^ Enum defined with deprecated options in `status` enum declaration. Remove the `_` prefix. + RUBY + end + end + + context 'when the enum name is a string' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum "status" => { active: 0, archived: 1 } + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `status` enum declaration. Use positional arguments instead. + RUBY + + expect_correction(<<~RUBY) + enum "status", { active: 0, archived: 1 } + RUBY + end + end + + context 'when the enum name is not a literal' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum KEY => { active: 0, archived: 1 } + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `KEY` enum declaration. Use positional arguments instead. + RUBY + + expect_correction(<<~RUBY) + enum KEY, { active: 0, archived: 1 } + RUBY + end + end + + it 'autocorrects' do + expect_offense(<<~RUBY) + enum status: { active: 0, archived: 1 } + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `status` enum declaration. Use positional arguments instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, { active: 0, archived: 1 } + RUBY + end + + it 'autocorrects options too' do + expect_offense(<<~RUBY) + enum status: { active: 0, archived: 1 }, _prefix: true, _suffix: true, _default: :active, _scopes: true + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `status` enum declaration. Use positional arguments instead. + RUBY + + expect_correction(<<~RUBY) + enum :status, { active: 0, archived: 1 }, prefix: true, suffix: true, default: :active, scopes: true + RUBY + end + end + + context 'when positional arguments are used' do + it 'does not register an offense' do + expect_no_offenses('enum :status, { active: 0, archived: 1 }, prefix: true') + end + end + + context 'when enum with no arguments' do + it 'does not register an offense' do + expect_no_offenses('enum') + end + end + end + + context 'Rails <= 6.1', :rails61 do + context 'when keyword arguments are used' do + context 'with %i[] syntax' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + enum status: { active: 0, archived: 1 }, _prefix: true + RUBY + end + end + + context 'with options prefixed with `_`' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + enum :status, { active: 0, archived: 1 }, _prefix: true, _suffix: true + RUBY + end + end + + context 'when the enum name is a string' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + enum "status" => { active: 0, archived: 1 } + RUBY + end + end + + context 'when the enum name is not a literal' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + enum KEY => { active: 0, archived: 1 } + RUBY + end + end + + it 'autocorrects' do + expect_no_offenses(<<~RUBY) + enum status: { active: 0, archived: 1 } + RUBY + end + + it 'autocorrects options too' do + expect_no_offenses(<<~RUBY) + enum status: { active: 0, archived: 1 }, _prefix: true, _suffix: true + RUBY + end + end + end +end From 91c0f30412b7058c5ad8bede8554045f99073294 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 24 Aug 2024 17:07:07 +0900 Subject: [PATCH 13/52] Update Changelog --- CHANGELOG.md | 28 +++++++++++++++++++ ..._compact_blank_to_handle_select_present.md | 1 - ...action_filter_option_multiple_callbacks.md | 1 - ...ge_make_rails_where_equals_aware_of_not.md | 1 - ...methods_to_detect_offenses_on_dir_index.md | 1 - .../fix_error_rails_bulk_change_table.md | 1 - ..._error_rails_render_plain_text_constant.md | 1 - changelog/fix_error_rails_validation.md | 1 - ...rror_rails_where_not_no_second_argument.md | 1 - ...r_action_controller_flash_before_render.md | 1 - ..._false_positive_for_rails_compact_blank.md | 1 - ...ndant_presence_validation_on_belongs_to.md | 1 - ...ke_pluralization_grammar_aware_of_bytes.md | 1 - ...tyle_collection_compact_aware_of_params.md | 1 - changelog/fix_where_equals_error.md | 1 - .../new_add_new_rails_enum_syntax_cop.md | 1 - ..._rails_7_syntax_for_rails_enum_hash_cop.md | 1 - ..._7_syntax_for_rails_enum_uniqueness_cop.md | 1 - 18 files changed, 28 insertions(+), 17 deletions(-) delete mode 100644 changelog/change_compact_blank_to_handle_select_present.md delete mode 100644 changelog/change_ignored_skip_action_filter_option_multiple_callbacks.md delete mode 100644 changelog/change_make_rails_where_equals_aware_of_not.md delete mode 100644 changelog/change_rails_root_pathname_methods_to_detect_offenses_on_dir_index.md delete mode 100644 changelog/fix_error_rails_bulk_change_table.md delete mode 100644 changelog/fix_error_rails_render_plain_text_constant.md delete mode 100644 changelog/fix_error_rails_validation.md delete mode 100644 changelog/fix_error_rails_where_not_no_second_argument.md delete mode 100644 changelog/fix_false_negatives_for_action_controller_flash_before_render.md delete mode 100644 changelog/fix_false_positive_for_rails_compact_blank.md delete mode 100644 changelog/fix_false_positive_for_rails_redundant_presence_validation_on_belongs_to.md delete mode 100644 changelog/fix_make_pluralization_grammar_aware_of_bytes.md delete mode 100644 changelog/fix_make_style_collection_compact_aware_of_params.md delete mode 100644 changelog/fix_where_equals_error.md delete mode 100644 changelog/new_add_new_rails_enum_syntax_cop.md delete mode 100644 changelog/new_support_rails_7_syntax_for_rails_enum_hash_cop.md delete mode 100644 changelog/new_support_rails_7_syntax_for_rails_enum_uniqueness_cop.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 902e57e4e7..b960820286 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,32 @@ ## master (unreleased) +### New features + +* [#1238](https://github.com/rubocop/rubocop-rails/issues/1238): Add new `Rails/EnumSyntax` cop. ([@maxprokopiev][], [@koic][]) +* [#1309](https://github.com/rubocop/rubocop-rails/pull/1309): Support Rails 7 syntax for `Rails/EnumHash` cop. ([@ytjmt][]) +* [#1298](https://github.com/rubocop/rubocop-rails/pull/1298): Support Rails 7 syntax for `Rails/EnumUniqueness` cop. ([@ytjmt][]) + +### Bug fixes + +* [#1335](https://github.com/rubocop/rubocop-rails/pull/1335): Fix an error for `Rails/BulkChangeTable` when the block for `change_table` is empty. ([@earlopain][]) +* [#1325](https://github.com/rubocop/rubocop-rails/pull/1325): Fix an error for `Rails/RenderPlainText` when the content type is passed as a constant. ([@earlopain][]) +* [#1337](https://github.com/rubocop/rubocop-rails/pull/1337): Fix an error for `Rails/Validation` when passing no arguments. ([@earlopain][]) +* [#1330](https://github.com/rubocop/rubocop-rails/pull/1330): Fix an error for `Rails/WhereNot` when using placeholder without second argument. ([@earlopain][]) +* [#1311](https://github.com/rubocop/rubocop-rails/pull/1311): Fix false negatives for `Rails/ActionControllerFlashBeforeRender` when using implicit render or rescue blocks. ([@tldn0718][]) +* [#1313](https://github.com/rubocop/rubocop-rails/pull/1313): Fix false positives for `Rails/CompactBlank` when using `collection.reject!`. ([@koic][]) +* [#1319](https://github.com/rubocop/rubocop-rails/issues/1319): Fix a false positive for `Rails/RedundantPresenceValidationOnBelongsTo` when removing `presence` would leave other non-validation options like `allow_blank` without validations. ([@earlopain][]) +* [#1306](https://github.com/rubocop/rubocop-rails/pull/1306): Make `Rails/PluralizationGrammar` aware of byte methods. ([@earlopain][]) +* [#1302](https://github.com/rubocop/rubocop-rails/pull/1302): Allow `params` receiver by default for `Style/CollectionMethods`. ([@koic][]) +* [#1321](https://github.com/rubocop/rubocop-rails/pull/1321): Fix an error for `Rails/WhereEquals` when the second argument is not yet typed (`where("foo = ?", )`). ([@earlopain][]) + +### Changes + +* [#1308](https://github.com/rubocop/rubocop-rails/issues/1308): Change `Rails/CompactBlank` to handle `select(&:present?)`. ([@fatkodima][]) +* [#1303](https://github.com/rubocop/rubocop-rails/pull/1303): Change `Rails/IgnoredSkipActionFilterOption` to handle multiple callbacks. ([@fatkodima][]) +* [#1199](https://github.com/rubocop/rubocop-rails/issues/1199): Make `Rails/WhereEquals` aware of `where.not(...)`. ([@earlopain][]) +* [#1003](https://github.com/rubocop/rubocop-rails/pull/1003): Change `Rails/RootPathnameMethods` to detect offenses on `Dir.[]`. ([@r7kamura][]) + ## 2.25.1 (2024-06-29) ### Bug fixes @@ -1098,3 +1124,5 @@ [@lukasfroehlich1]: https://github.com/lukasfroehlich1 [@ChaelCodes]: https://github.com/ChaelCodes [@fwolfst]: https://github.com/fwolfst +[@maxprokopiev]: https://github.com/maxprokopiev +[@ytjmt]: https://github.com/ytjmt diff --git a/changelog/change_compact_blank_to_handle_select_present.md b/changelog/change_compact_blank_to_handle_select_present.md deleted file mode 100644 index cec5b9b4f2..0000000000 --- a/changelog/change_compact_blank_to_handle_select_present.md +++ /dev/null @@ -1 +0,0 @@ -* [#1308](https://github.com/rubocop/rubocop-rails/issues/1308): Change `Rails/CompactBlank` to handle `select(&:present?)`. ([@fatkodima][]) diff --git a/changelog/change_ignored_skip_action_filter_option_multiple_callbacks.md b/changelog/change_ignored_skip_action_filter_option_multiple_callbacks.md deleted file mode 100644 index 8bbf59d754..0000000000 --- a/changelog/change_ignored_skip_action_filter_option_multiple_callbacks.md +++ /dev/null @@ -1 +0,0 @@ -* [#1303](https://github.com/rubocop/rubocop-rails/pull/1303): Change `Rails/IgnoredSkipActionFilterOption` to handle multiple callbacks. ([@fatkodima][]) diff --git a/changelog/change_make_rails_where_equals_aware_of_not.md b/changelog/change_make_rails_where_equals_aware_of_not.md deleted file mode 100644 index 1a61ab42f3..0000000000 --- a/changelog/change_make_rails_where_equals_aware_of_not.md +++ /dev/null @@ -1 +0,0 @@ -* [#1199](https://github.com/rubocop/rubocop-rails/issues/1199): Make `Rails/WhereEquals` aware of `where.not(...)`. ([@earlopain][]) diff --git a/changelog/change_rails_root_pathname_methods_to_detect_offenses_on_dir_index.md b/changelog/change_rails_root_pathname_methods_to_detect_offenses_on_dir_index.md deleted file mode 100644 index 30a32029f1..0000000000 --- a/changelog/change_rails_root_pathname_methods_to_detect_offenses_on_dir_index.md +++ /dev/null @@ -1 +0,0 @@ -* [#1003](https://github.com/rubocop/rubocop-rails/pull/1003): Change `Rails/RootPathnameMethods` to detect offenses on `Dir.[]`. ([@r7kamura][]) diff --git a/changelog/fix_error_rails_bulk_change_table.md b/changelog/fix_error_rails_bulk_change_table.md deleted file mode 100644 index 3b01fd4dbe..0000000000 --- a/changelog/fix_error_rails_bulk_change_table.md +++ /dev/null @@ -1 +0,0 @@ -* [#1335](https://github.com/rubocop/rubocop-rails/pull/1335): Fix an error for `Rails/BulkChangeTable` when the block for `change_table` is empty. ([@earlopain][]) diff --git a/changelog/fix_error_rails_render_plain_text_constant.md b/changelog/fix_error_rails_render_plain_text_constant.md deleted file mode 100644 index 0fbab1d458..0000000000 --- a/changelog/fix_error_rails_render_plain_text_constant.md +++ /dev/null @@ -1 +0,0 @@ -* [#1325](https://github.com/rubocop/rubocop-rails/pull/1325): Fix an error for `Rails/RenderPlainText` when the content type is passed as a constant. ([@earlopain][]) diff --git a/changelog/fix_error_rails_validation.md b/changelog/fix_error_rails_validation.md deleted file mode 100644 index 024d4bf8b9..0000000000 --- a/changelog/fix_error_rails_validation.md +++ /dev/null @@ -1 +0,0 @@ -* [#1337](https://github.com/rubocop/rubocop-rails/pull/1337): Fix an error for `Rails/Validation` when passing no arguments. ([@earlopain][]) diff --git a/changelog/fix_error_rails_where_not_no_second_argument.md b/changelog/fix_error_rails_where_not_no_second_argument.md deleted file mode 100644 index 437da24eb6..0000000000 --- a/changelog/fix_error_rails_where_not_no_second_argument.md +++ /dev/null @@ -1 +0,0 @@ -* [#1330](https://github.com/rubocop/rubocop-rails/pull/1330): Fix an error for `Rails/WhereNot` when using placeholder without second argument. ([@earlopain][]) diff --git a/changelog/fix_false_negatives_for_action_controller_flash_before_render.md b/changelog/fix_false_negatives_for_action_controller_flash_before_render.md deleted file mode 100644 index 6d253ae144..0000000000 --- a/changelog/fix_false_negatives_for_action_controller_flash_before_render.md +++ /dev/null @@ -1 +0,0 @@ -* [#1311](https://github.com/rubocop/rubocop-rails/pull/1311): Fix false negatives for `Rails/ActionControllerFlashBeforeRender` when using implicit render or rescue blocks. ([@tldn0718][]) diff --git a/changelog/fix_false_positive_for_rails_compact_blank.md b/changelog/fix_false_positive_for_rails_compact_blank.md deleted file mode 100644 index 9718f82438..0000000000 --- a/changelog/fix_false_positive_for_rails_compact_blank.md +++ /dev/null @@ -1 +0,0 @@ -* [#1313](https://github.com/rubocop/rubocop-rails/pull/1313): Fix false positives for `Rails/CompactBlank` when using `collection.reject!`. ([@koic][]) diff --git a/changelog/fix_false_positive_for_rails_redundant_presence_validation_on_belongs_to.md b/changelog/fix_false_positive_for_rails_redundant_presence_validation_on_belongs_to.md deleted file mode 100644 index 2af6991677..0000000000 --- a/changelog/fix_false_positive_for_rails_redundant_presence_validation_on_belongs_to.md +++ /dev/null @@ -1 +0,0 @@ -* [#1319](https://github.com/rubocop/rubocop-rails/issues/1319): Fix a false positive for `Rails/RedundantPresenceValidationOnBelongsTo` when removing `presence` would leave other non-validation options like `allow_blank` without validations. ([@earlopain][]) diff --git a/changelog/fix_make_pluralization_grammar_aware_of_bytes.md b/changelog/fix_make_pluralization_grammar_aware_of_bytes.md deleted file mode 100644 index 1c34bf1259..0000000000 --- a/changelog/fix_make_pluralization_grammar_aware_of_bytes.md +++ /dev/null @@ -1 +0,0 @@ -* [#1306](https://github.com/rubocop/rubocop-rails/pull/1306): Make `Rails/PluralizationGrammar` aware of byte methods. ([@earlopain][]) diff --git a/changelog/fix_make_style_collection_compact_aware_of_params.md b/changelog/fix_make_style_collection_compact_aware_of_params.md deleted file mode 100644 index f9e7223366..0000000000 --- a/changelog/fix_make_style_collection_compact_aware_of_params.md +++ /dev/null @@ -1 +0,0 @@ -* [#1302](https://github.com/rubocop/rubocop-rails/pull/1302): Allow `params` receiver by default for `Style/CollectionMethods`. ([@koic][]) diff --git a/changelog/fix_where_equals_error.md b/changelog/fix_where_equals_error.md deleted file mode 100644 index 2e1ccc7309..0000000000 --- a/changelog/fix_where_equals_error.md +++ /dev/null @@ -1 +0,0 @@ -* [#1321](https://github.com/rubocop/rubocop-rails/pull/1321): Fix an error for `Rails/WhereEquals` when the second argument is not yet typed (`where("foo = ?", )`). ([@earlopain][]) diff --git a/changelog/new_add_new_rails_enum_syntax_cop.md b/changelog/new_add_new_rails_enum_syntax_cop.md deleted file mode 100644 index 19909d3b66..0000000000 --- a/changelog/new_add_new_rails_enum_syntax_cop.md +++ /dev/null @@ -1 +0,0 @@ -* [#1238](https://github.com/rubocop/rubocop-rails/issues/1238): Add new `Rails/EnumSyntax` cop. ([@maxprokopiev][], [@koic][]) diff --git a/changelog/new_support_rails_7_syntax_for_rails_enum_hash_cop.md b/changelog/new_support_rails_7_syntax_for_rails_enum_hash_cop.md deleted file mode 100644 index 355a76dd25..0000000000 --- a/changelog/new_support_rails_7_syntax_for_rails_enum_hash_cop.md +++ /dev/null @@ -1 +0,0 @@ -* [#1309](https://github.com/rubocop/rubocop-rails/pull/1309): Support Rails 7 syntax for `Rails/EnumHash` cop. ([@ytjmt][]) diff --git a/changelog/new_support_rails_7_syntax_for_rails_enum_uniqueness_cop.md b/changelog/new_support_rails_7_syntax_for_rails_enum_uniqueness_cop.md deleted file mode 100644 index a1707d6c81..0000000000 --- a/changelog/new_support_rails_7_syntax_for_rails_enum_uniqueness_cop.md +++ /dev/null @@ -1 +0,0 @@ -* [#1298](https://github.com/rubocop/rubocop-rails/pull/1298): Support Rails 7 syntax for `Rails/EnumUniqueness` cop. ([@ytjmt][]) From 334861ea2a0b345e347c30aa97283b690713b672 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 24 Aug 2024 17:07:31 +0900 Subject: [PATCH 14/52] Cut 2.26.0 --- CHANGELOG.md | 2 + config/default.yml | 4 +- docs/antora.yml | 2 +- docs/modules/ROOT/pages/cops.adoc | 1 + docs/modules/ROOT/pages/cops_rails.adoc | 109 ++++++++++++++++++++---- lib/rubocop/rails/version.rb | 2 +- relnotes/v2.26.0.md | 33 +++++++ 7 files changed, 133 insertions(+), 20 deletions(-) create mode 100644 relnotes/v2.26.0.md diff --git a/CHANGELOG.md b/CHANGELOG.md index b960820286..8671e1bf72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ## master (unreleased) +## 2.26.0 (2024-08-24) + ### New features * [#1238](https://github.com/rubocop/rubocop-rails/issues/1238): Add new `Rails/EnumSyntax` cop. ([@maxprokopiev][], [@koic][]) diff --git a/config/default.yml b/config/default.yml index f2b87a6367..97b01498b0 100644 --- a/config/default.yml +++ b/config/default.yml @@ -428,7 +428,7 @@ Rails/EnumSyntax: Description: 'Use positional arguments over keyword arguments when defining enums.' Enabled: pending Severity: warning - VersionAdded: '<>' + VersionAdded: '2.26' Include: - app/models/**/*.rb @@ -1198,7 +1198,7 @@ Rails/WhereEquals: Enabled: 'pending' SafeAutoCorrect: false VersionAdded: '2.9' - VersionChanged: <> + VersionChanged: '2.26' Rails/WhereExists: Description: 'Prefer `exists?(...)` over `where(...).exists?`.' diff --git a/docs/antora.yml b/docs/antora.yml index 9e0ff48acb..0e3477f379 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-rails title: RuboCop Rails # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: ~ +version: '2.26' nav: - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/pages/cops.adoc b/docs/modules/ROOT/pages/cops.adoc index 5e87149ded..10c6b8a388 100644 --- a/docs/modules/ROOT/pages/cops.adoc +++ b/docs/modules/ROOT/pages/cops.adoc @@ -53,6 +53,7 @@ based on the https://rails.rubystyle.guide/[Rails Style Guide]. * xref:cops_rails.adoc#railsdynamicfindby[Rails/DynamicFindBy] * xref:cops_rails.adoc#railseagerevaluationlogmessage[Rails/EagerEvaluationLogMessage] * xref:cops_rails.adoc#railsenumhash[Rails/EnumHash] +* xref:cops_rails.adoc#railsenumsyntax[Rails/EnumSyntax] * xref:cops_rails.adoc#railsenumuniqueness[Rails/EnumUniqueness] * xref:cops_rails.adoc#railsenvlocal[Rails/EnvLocal] * xref:cops_rails.adoc#railsenvironmentcomparison[Rails/EnvironmentComparison] diff --git a/docs/modules/ROOT/pages/cops_rails.adoc b/docs/modules/ROOT/pages/cops_rails.adoc index 65cf9a1287..b946879608 100644 --- a/docs/modules/ROOT/pages/cops_rails.adoc +++ b/docs/modules/ROOT/pages/cops_rails.adoc @@ -1084,7 +1084,6 @@ This will work fine when the receiver is a hash object. And `compact_blank!` has different implementations for `Array`, `Hash`, and `ActionController::Parameters`. `Array#compact_blank!`, `Hash#compact_blank!` are equivalent to `delete_if(&:blank?)`. -`ActionController::Parameters#compact_blank!` is equivalent to `reject!(&:blank?)`. If the cop makes a mistake, autocorrected code may get unexpected behavior. === Examples @@ -1094,6 +1093,8 @@ If the cop makes a mistake, autocorrected code may get unexpected behavior. # bad collection.reject(&:blank?) collection.reject { |_k, v| v.blank? } +collection.select(&:present?) +collection.select { |_k, v| v.present? } # good collection.compact_blank @@ -1101,8 +1102,8 @@ collection.compact_blank # bad collection.delete_if(&:blank?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!` collection.delete_if { |_k, v| v.blank? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!` -collection.reject!(&:blank?) # Same behavior as `ActionController::Parameters#compact_blank!` -collection.reject! { |_k, v| v.blank? } # Same behavior as `ActionController::Parameters#compact_blank!` +collection.keep_if(&:present?) # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!` +collection.keep_if { |_k, v| v.present? } # Same behavior as `Array#compact_blank!` and `Hash#compact_blank!` # good collection.compact_blank! @@ -1294,10 +1295,10 @@ Rails time zone. You must use `Time.zone.today` instead. The cop also reports warnings when you are using `to_time` method, because it doesn't know about Rails time zone either. -Two styles are supported for this cop. When `EnforcedStyle` is 'strict' +Two styles are supported for this cop. When `EnforcedStyle` is `strict` then the Date methods `today`, `current`, `yesterday`, and `tomorrow` are prohibited and the usage of both `to_time` -and 'to_time_in_current_zone' are reported as warning. +and `to_time_in_current_zone` are reported as warning. When `EnforcedStyle` is `flexible` then only `Date.today` is prohibited. @@ -1881,6 +1882,12 @@ value for each key prevents this from happening. [source,ruby] ---- +# bad +enum :status, [:active, :archived] + +# good +enum :status, { active: 0, archived: 1 } + # bad enum status: [:active, :archived] @@ -1902,6 +1909,48 @@ enum status: { active: 0, archived: 1 } * https://rails.rubystyle.guide#enums +== Rails/EnumSyntax + +|=== +| Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed + +| Pending +| Yes +| Always +| 2.26 +| - +|=== + +Looks for enums written with keyword arguments syntax. + +Defining enums with keyword arguments syntax is deprecated and will be removed in Rails 8.0. +Positional arguments should be used instead: + +=== Examples + +[source,ruby] +---- +# bad +enum status: { active: 0, archived: 1 }, _prefix: true + +# good +enum :status, { active: 0, archived: 1 }, prefix: true +---- + +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Severity +| `warning` +| String + +| Include +| `+app/models/**/*.rb+` +| Array +|=== + == Rails/EnumUniqueness |=== @@ -1920,6 +1969,18 @@ Looks for duplicate values in enum declarations. [source,ruby] ---- +# bad +enum :status, { active: 0, archived: 0 } + +# good +enum :status, { active: 0, archived: 1 } + +# bad +enum :status, [:active, :archived, :active] + +# good +enum :status, [:active, :archived] + # bad enum status: { active: 0, archived: 0 } @@ -4031,18 +4092,27 @@ Identifies places where `pluck` is used in `where` query methods and can be replaced with `select`. Since `pluck` is an eager method and hits the database immediately, -using `select` helps to avoid additional database queries. +using `select` helps to avoid additional database queries by running as +a subquery. -This cop has two different enforcement modes. When the `EnforcedStyle` -is `conservative` (the default) then only calls to `pluck` on a constant -(i.e. a model class) in the `where` is used as offenses. +This cop has two modes of enforcement. When the `EnforcedStyle` is set +to `conservative` (the default), only calls to `pluck` on a constant +(e.g. a model class) within `where` are considered offenses. === Safety -When the `EnforcedStyle` is `aggressive` then all calls to `pluck` in the -`where` is used as offenses. This may lead to false positives -as the cop cannot replace to `select` between calls to `pluck` on an -`ActiveRecord::Relation` instance vs a call to `pluck` on an `Array` instance. +When `EnforcedStyle` is set to `aggressive`, all calls to `pluck` +within `where` are considered offenses. This might lead to false +positives because the check cannot distinguish between calls to +`pluck` on an `ActiveRecord::Relation` instance and calls to `pluck` +on an `Array` instance. + +Additionally, when using a subquery with the SQL `IN` operator, +databases like PostgreSQL and MySQL can't optimize complex queries as +well. They need to scan all records of the outer table against the +subquery result sequentially, rather than using an index. This can +cause significant performance issues compared to writing the query +differently or using `pluck`. === Examples @@ -4107,10 +4177,14 @@ core extensions to the numeric classes. # bad 3.day.ago 1.months.ago +5.megabyte +1.gigabyte # good 3.days.ago 1.month.ago +5.megabytes +1.gigabyte ---- == Rails/Presence @@ -6794,15 +6868,16 @@ validates :foo, uniqueness: true | Yes | Always (Unsafe) | 2.9 -| 2.10 +| 2.26 |=== Identifies places where manually constructed SQL -in `where` can be replaced with `where(attribute: value)`. +in `where` and `where.not` can be replaced with +`where(attribute: value)` and `where.not(attribute: value)`. === Safety -This cop's autocorrection is unsafe because it may change SQL. +This cop's autocorrection is unsafe because is may change SQL. See: https://github.com/rubocop/rubocop-rails/issues/403 === Examples @@ -6811,6 +6886,7 @@ See: https://github.com/rubocop/rubocop-rails/issues/403 ---- # bad User.where('name = ?', 'Gabe') +User.where.not('name = ?', 'Gabe') User.where('name = :name', name: 'Gabe') User.where('name IS NULL') User.where('name IN (?)', ['john', 'jane']) @@ -6819,6 +6895,7 @@ User.where('users.name = :name', name: 'Gabe') # good User.where(name: 'Gabe') +User.where.not(name: 'Gabe') User.where(name: nil) User.where(name: ['john', 'jane']) User.where(users: { name: 'Gabe' }) diff --git a/lib/rubocop/rails/version.rb b/lib/rubocop/rails/version.rb index 29db46e6d2..438e0a2245 100644 --- a/lib/rubocop/rails/version.rb +++ b/lib/rubocop/rails/version.rb @@ -4,7 +4,7 @@ module RuboCop module Rails # This module holds the RuboCop Rails version information. module Version - STRING = '2.25.1' + STRING = '2.26.0' def self.document_version STRING.match('\d+\.\d+').to_s diff --git a/relnotes/v2.26.0.md b/relnotes/v2.26.0.md new file mode 100644 index 0000000000..312b84f82a --- /dev/null +++ b/relnotes/v2.26.0.md @@ -0,0 +1,33 @@ +### New features + +* [#1238](https://github.com/rubocop/rubocop-rails/issues/1238): Add new `Rails/EnumSyntax` cop. ([@maxprokopiev][], [@koic][]) +* [#1309](https://github.com/rubocop/rubocop-rails/pull/1309): Support Rails 7 syntax for `Rails/EnumHash` cop. ([@ytjmt][]) +* [#1298](https://github.com/rubocop/rubocop-rails/pull/1298): Support Rails 7 syntax for `Rails/EnumUniqueness` cop. ([@ytjmt][]) + +### Bug fixes + +* [#1335](https://github.com/rubocop/rubocop-rails/pull/1335): Fix an error for `Rails/BulkChangeTable` when the block for `change_table` is empty. ([@earlopain][]) +* [#1325](https://github.com/rubocop/rubocop-rails/pull/1325): Fix an error for `Rails/RenderPlainText` when the content type is passed as a constant. ([@earlopain][]) +* [#1337](https://github.com/rubocop/rubocop-rails/pull/1337): Fix an error for `Rails/Validation` when passing no arguments. ([@earlopain][]) +* [#1330](https://github.com/rubocop/rubocop-rails/pull/1330): Fix an error for `Rails/WhereNot` when using placeholder without second argument. ([@earlopain][]) +* [#1311](https://github.com/rubocop/rubocop-rails/pull/1311): Fix false negatives for `Rails/ActionControllerFlashBeforeRender` when using implicit render or rescue blocks. ([@tldn0718][]) +* [#1313](https://github.com/rubocop/rubocop-rails/pull/1313): Fix false positives for `Rails/CompactBlank` when using `collection.reject!`. ([@koic][]) +* [#1319](https://github.com/rubocop/rubocop-rails/issues/1319): Fix a false positive for `Rails/RedundantPresenceValidationOnBelongsTo` when removing `presence` would leave other non-validation options like `allow_blank` without validations. ([@earlopain][]) +* [#1306](https://github.com/rubocop/rubocop-rails/pull/1306): Make `Rails/PluralizationGrammar` aware of byte methods. ([@earlopain][]) +* [#1302](https://github.com/rubocop/rubocop-rails/pull/1302): Allow `params` receiver by default for `Style/CollectionMethods`. ([@koic][]) +* [#1321](https://github.com/rubocop/rubocop-rails/pull/1321): Fix an error for `Rails/WhereEquals` when the second argument is not yet typed (`where("foo = ?", )`). ([@earlopain][]) + +### Changes + +* [#1308](https://github.com/rubocop/rubocop-rails/issues/1308): Change `Rails/CompactBlank` to handle `select(&:present?)`. ([@fatkodima][]) +* [#1303](https://github.com/rubocop/rubocop-rails/pull/1303): Change `Rails/IgnoredSkipActionFilterOption` to handle multiple callbacks. ([@fatkodima][]) +* [#1199](https://github.com/rubocop/rubocop-rails/issues/1199): Make `Rails/WhereEquals` aware of `where.not(...)`. ([@earlopain][]) +* [#1003](https://github.com/rubocop/rubocop-rails/pull/1003): Change `Rails/RootPathnameMethods` to detect offenses on `Dir.[]`. ([@r7kamura][]) + +[@maxprokopiev]: https://github.com/maxprokopiev +[@koic]: https://github.com/koic +[@ytjmt]: https://github.com/ytjmt +[@earlopain]: https://github.com/earlopain +[@tldn0718]: https://github.com/tldn0718 +[@fatkodima]: https://github.com/fatkodima +[@r7kamura]: https://github.com/r7kamura From 8fa685685cc4983dd7a94332608cd79b54272f07 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 24 Aug 2024 17:18:40 +0900 Subject: [PATCH 15/52] Switch back docs version to master --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index 0e3477f379..9e0ff48acb 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-rails title: RuboCop Rails # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: '2.26' +version: ~ nav: - modules/ROOT/nav.adoc From 0909f0ebe5df723b26f057243ade4e046957a512 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Sat, 24 Aug 2024 12:06:10 +0200 Subject: [PATCH 16/52] Remove RuboCop < 1.52 compatibility code The minimum required version right now is >= 1.52 --- lib/rubocop/cop/rails/action_order.rb | 6 +--- .../rails/active_record_callbacks_order.rb | 6 +--- .../redundant_active_record_all_method.rb | 29 ------------------- 3 files changed, 2 insertions(+), 39 deletions(-) diff --git a/lib/rubocop/cop/rails/action_order.rb b/lib/rubocop/cop/rails/action_order.rb index a2bcd3b462..954c1ae2fd 100644 --- a/lib/rubocop/cop/rails/action_order.rb +++ b/lib/rubocop/cop/rails/action_order.rb @@ -92,11 +92,7 @@ def add_range(range1, range2) end def range_with_comments(node) - # rubocop:todo InternalAffairs/LocationExpression - # Using `RuboCop::Ext::Comment#source_range` requires RuboCop > 1.46, - # which introduces https://github.com/rubocop/rubocop/pull/11630. - ranges = [node, *processed_source.ast_with_comments[node]].map { |comment| comment.loc.expression } - # rubocop:enable InternalAffairs/LocationExpression + ranges = [node, *processed_source.ast_with_comments[node]].map(&:source_range) ranges.reduce do |result, range| add_range(result, range) end diff --git a/lib/rubocop/cop/rails/active_record_callbacks_order.rb b/lib/rubocop/cop/rails/active_record_callbacks_order.rb index 8742e76338..cb544234f6 100644 --- a/lib/rubocop/cop/rails/active_record_callbacks_order.rb +++ b/lib/rubocop/cop/rails/active_record_callbacks_order.rb @@ -123,11 +123,7 @@ def begin_pos_with_comment(node) end def inline_comment?(comment) - # rubocop:todo InternalAffairs/LocationExpression - # Using `RuboCop::Ext::Comment#source_range` requires RuboCop > 1.46, - # which introduces https://github.com/rubocop/rubocop/pull/11630. - !comment_line?(comment.loc.expression.source_line) - # rubocop:enable InternalAffairs/LocationExpression + !comment_line?(comment.source_range.source_line) end def start_line_position(node) diff --git a/lib/rubocop/cop/rails/redundant_active_record_all_method.rb b/lib/rubocop/cop/rails/redundant_active_record_all_method.rb index ee5fa6afd6..252e890875 100644 --- a/lib/rubocop/cop/rails/redundant_active_record_all_method.rb +++ b/lib/rubocop/cop/rails/redundant_active_record_all_method.rb @@ -3,35 +3,6 @@ module RuboCop module Cop module Rails - # TODO: In the future, please support only RuboCop 1.52+ and use `RuboCop::Cop::AllowedReceivers`: - # https://github.com/rubocop/rubocop/blob/v1.52.0/lib/rubocop/cop/mixin/allowed_receivers.rb - # At that time, this duplicated module implementation can be removed. - module AllowedReceivers - def allowed_receiver?(receiver) - receiver_name = receiver_name(receiver) - - allowed_receivers.include?(receiver_name) - end - - def receiver_name(receiver) - return receiver_name(receiver.receiver) if receiver.receiver && !receiver.receiver.const_type? - - if receiver.send_type? - if receiver.receiver - "#{receiver_name(receiver.receiver)}.#{receiver.method_name}" - else - receiver.method_name.to_s - end - else - receiver.source - end - end - - def allowed_receivers - cop_config.fetch('AllowedReceivers', []) - end - end - # Detect redundant `all` used as a receiver for Active Record query methods. # # For the methods `delete_all` and `destroy_all`, this cop will only check cases where the receiver is a model. From d83f48a061972977fd277066f188a5d2f58953e8 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Mon, 26 Aug 2024 10:50:22 +0200 Subject: [PATCH 17/52] Enable `InternalAffairs/UndefinedConfig` This works fine right now. I did a bit of spelunking for `NilOrEmpty` in `Rails/Present` and I believe it is a copy-paste error. Added together with `Rails/Blank` in https://github.com/rubocop/rubocop/pull/4133/ which does contain this config value. There are no tests or docs for this config value. --- .rubocop.yml | 4 ---- lib/rubocop/cop/rails/present.rb | 2 -- lib/rubocop/cop/rails/skips_model_validations.rb | 6 ++++-- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 43ee5e077b..dc83f549fc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -19,10 +19,6 @@ AllCops: InternalAffairs/NodeMatcherDirective: Enabled: false -# FIXME: Workaround for a false positive caused by this cop when using `bundle exec rake`. -InternalAffairs/UndefinedConfig: - Enabled: false - Naming/InclusiveLanguage: Enabled: true CheckStrings: true diff --git a/lib/rubocop/cop/rails/present.rb b/lib/rubocop/cop/rails/present.rb index 1d789cf7bd..3d77f33d6f 100644 --- a/lib/rubocop/cop/rails/present.rb +++ b/lib/rubocop/cop/rails/present.rb @@ -98,8 +98,6 @@ def on_and(node) end def on_or(node) - return unless cop_config['NilOrEmpty'] - exists_and_not_empty?(node) do |var1, var2| return unless var1 == var2 diff --git a/lib/rubocop/cop/rails/skips_model_validations.rb b/lib/rubocop/cop/rails/skips_model_validations.rb index 5a78926c92..58a6fe519d 100644 --- a/lib/rubocop/cop/rails/skips_model_validations.rb +++ b/lib/rubocop/cop/rails/skips_model_validations.rb @@ -100,7 +100,8 @@ def allowed_method?(node) end def forbidden_methods - obsolete_result = cop_config['Blacklist'] + # TODO: Remove when RuboCop Rails 3 releases. + obsolete_result = cop_config['Blacklist'] # rubocop:disable InternalAffairs/UndefinedConfig if obsolete_result warn '`Blacklist` has been renamed to `ForbiddenMethods`.' unless @displayed_forbidden_warning @displayed_forbidden_warning = true @@ -111,7 +112,8 @@ def forbidden_methods end def allowed_methods - obsolete_result = cop_config['Whitelist'] + # TODO: Remove when RuboCop Rails 3 releases. + obsolete_result = cop_config['Whitelist'] # rubocop:disable InternalAffairs/UndefinedConfig if obsolete_result warn '`Whitelist` has been renamed to `AllowedMethods`.' unless @displayed_allowed_warning @displayed_allowed_warning = true From 5c975e5f7480ef5134410b2364aca290f4870a74 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Mon, 26 Aug 2024 13:45:43 +0200 Subject: [PATCH 18/52] [Fix #1340] Fix a false positive for `Rails/WhereEquals` when qualifying the database name And `Rails/WhereNot`/``Rails/WhereRange` as well. I'd like to extract some of this logic to a module sometime since it is looking rather similar. The original issue mentions Redshift, and I know that MSSQL allows cross-database queries as well --- changelog/fix_false_positive_database_qualified.md | 1 + lib/rubocop/cop/rails/where_equals.rb | 7 ++++++- lib/rubocop/cop/rails/where_not.rb | 7 ++++++- lib/rubocop/cop/rails/where_range.rb | 7 ++++++- spec/rubocop/cop/rails/where_equals_spec.rb | 6 ++++++ spec/rubocop/cop/rails/where_not_spec.rb | 6 ++++++ spec/rubocop/cop/rails/where_range_spec.rb | 6 ++++++ 7 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 changelog/fix_false_positive_database_qualified.md diff --git a/changelog/fix_false_positive_database_qualified.md b/changelog/fix_false_positive_database_qualified.md new file mode 100644 index 0000000000..50e815b818 --- /dev/null +++ b/changelog/fix_false_positive_database_qualified.md @@ -0,0 +1 @@ +* [#1340](https://github.com/rubocop/rubocop-rails/issues/1340): Fix a false positive for `Rails/WhereEquals`, `Rails/WhereNot`, and `Rails/WhereRange` when qualifying the database name. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/where_equals.rb b/lib/rubocop/cop/rails/where_equals.rb index b1d56b7c24..b538bedd8d 100644 --- a/lib/rubocop/cop/rails/where_equals.rb +++ b/lib/rubocop/cop/rails/where_equals.rb @@ -74,6 +74,7 @@ def offense_range(node) range_between(node.loc.selector.begin_pos, node.source_range.end_pos) end + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength def extract_column_and_value(template_node, value_node) value = case template_node.value @@ -90,8 +91,12 @@ def extract_column_and_value(template_node, value_node) return end - [Regexp.last_match(1), value] + column_qualifier = Regexp.last_match(1) + return if column_qualifier.count('.') > 1 + + [column_qualifier, value] end + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength def build_good_method(method_name, column, value) if column.include?('.') diff --git a/lib/rubocop/cop/rails/where_not.rb b/lib/rubocop/cop/rails/where_not.rb index 96762f5e47..2b6300165e 100644 --- a/lib/rubocop/cop/rails/where_not.rb +++ b/lib/rubocop/cop/rails/where_not.rb @@ -68,6 +68,7 @@ def offense_range(node) range_between(node.loc.selector.begin_pos, node.source_range.end_pos) end + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength def extract_column_and_value(template_node, value_node) value = case template_node.value @@ -84,8 +85,12 @@ def extract_column_and_value(template_node, value_node) return end - [Regexp.last_match(1), value] + column_qualifier = Regexp.last_match(1) + return if column_qualifier.count('.') > 1 + + [column_qualifier, value] end + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength def build_good_method(dot, column, value) dot ||= '.' diff --git a/lib/rubocop/cop/rails/where_range.rb b/lib/rubocop/cop/rails/where_range.rb index 4797a50e81..1c8fd4a0fb 100644 --- a/lib/rubocop/cop/rails/where_range.rb +++ b/lib/rubocop/cop/rails/where_range.rb @@ -140,6 +140,8 @@ def extract_column_and_value(template_node, values_node) rhs = pair2.value end end + else + return end if lhs @@ -150,7 +152,10 @@ def extract_column_and_value(template_node, values_node) rhs_source = parentheses_needed?(rhs) ? "(#{rhs.source})" : rhs.source end - [Regexp.last_match(1), "#{lhs_source}#{operator}#{rhs_source}"] if operator + column_qualifier = Regexp.last_match(1) + return if column_qualifier.count('.') > 1 + + [column_qualifier, "#{lhs_source}#{operator}#{rhs_source}"] if operator end # rubocop:enable Metrics diff --git a/spec/rubocop/cop/rails/where_equals_spec.rb b/spec/rubocop/cop/rails/where_equals_spec.rb index 1af170ebff..5c564a72e7 100644 --- a/spec/rubocop/cop/rails/where_equals_spec.rb +++ b/spec/rubocop/cop/rails/where_equals_spec.rb @@ -217,4 +217,10 @@ users.not('name = ?', 'Gabe') RUBY end + + it 'does not register an offense when qualifying the database' do + expect_no_offenses(<<~RUBY) + User.where('database.users.name = ?', 'Gabe') + RUBY + end end diff --git a/spec/rubocop/cop/rails/where_not_spec.rb b/spec/rubocop/cop/rails/where_not_spec.rb index 84d8aeded0..36e1ecca54 100644 --- a/spec/rubocop/cop/rails/where_not_spec.rb +++ b/spec/rubocop/cop/rails/where_not_spec.rb @@ -275,4 +275,10 @@ User.where('name <> ? AND age <> ?', 'john', 19) RUBY end + + it 'does not register an offense when qualifying the database' do + expect_no_offenses(<<~RUBY) + User.where('database.users.name != ?', 'Gabe') + RUBY + end end diff --git a/spec/rubocop/cop/rails/where_range_spec.rb b/spec/rubocop/cop/rails/where_range_spec.rb index 6a5a7b3353..4102fee308 100644 --- a/spec/rubocop/cop/rails/where_range_spec.rb +++ b/spec/rubocop/cop/rails/where_range_spec.rb @@ -221,6 +221,12 @@ Model.where(column: ...value) RUBY end + + it 'does not register an offense when qualifying the database' do + expect_no_offenses(<<~RUBY) + Model.where('database.table.column >= ?', value) + RUBY + end end end end From 0f36342a119659e3afc7385f4bc1e5791bb920ee Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Sun, 1 Sep 2024 10:49:59 +0200 Subject: [PATCH 19/52] [Fix #1345] Improve offense message for `Rails/RootPathnameMethods` The current message is confusing/nonsensical for `Dir[]`. Let's display the correct code instead to show what needs to be done --- .../cop/rails/root_pathname_methods.rb | 18 ++++++++----- .../cop/rails/root_pathname_methods_spec.rb | 26 +++++++++---------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/lib/rubocop/cop/rails/root_pathname_methods.rb b/lib/rubocop/cop/rails/root_pathname_methods.rb index 233b1744d0..5898d0b421 100644 --- a/lib/rubocop/cop/rails/root_pathname_methods.rb +++ b/lib/rubocop/cop/rails/root_pathname_methods.rb @@ -23,6 +23,8 @@ module Rails # File.binread(Rails.root.join('db', 'schema.rb')) # File.write(Rails.root.join('db', 'schema.rb'), content) # File.binwrite(Rails.root.join('db', 'schema.rb'), content) + # Dir.glob(Rails.root.join('db', 'schema.rb')) + # Dir[Rails.root.join('db', 'schema.rb')] # # # good # Rails.root.join('db', 'schema.rb').open @@ -31,12 +33,13 @@ module Rails # Rails.root.join('db', 'schema.rb').binread # Rails.root.join('db', 'schema.rb').write(content) # Rails.root.join('db', 'schema.rb').binwrite(content) + # Rails.root.glob("db/schema.rb") # class RootPathnameMethods < Base # rubocop:disable Metrics/ClassLength extend AutoCorrector include RangeHelp - MSG = '`%s` is a `Pathname` so you can just append `#%s`.' + MSG = '`%s` is a `Pathname`, so you can use `%s`.' DIR_GLOB_METHODS = %i[[] glob].to_set.freeze @@ -188,13 +191,14 @@ class RootPathnameMethods < Base # rubocop:disable Metrics/ClassLength def on_send(node) evidence(node) do |method, path, args, rails_root| - add_offense(node, message: format(MSG, method: method, rails_root: rails_root.source)) do |corrector| - replacement = if dir_glob?(node) - build_path_glob_replacement(path) - else - build_path_replacement(path, method, args) - end + replacement = if dir_glob?(node) + build_path_glob_replacement(path) + else + build_path_replacement(path, method, args) + end + message = format(MSG, rails_root: rails_root.source, replacement: replacement) + add_offense(node, message: message) do |corrector| corrector.replace(node, replacement) end end diff --git a/spec/rubocop/cop/rails/root_pathname_methods_spec.rb b/spec/rubocop/cop/rails/root_pathname_methods_spec.rb index 04b9508073..82f00ea5da 100644 --- a/spec/rubocop/cop/rails/root_pathname_methods_spec.rb +++ b/spec/rubocop/cop/rails/root_pathname_methods_spec.rb @@ -12,7 +12,7 @@ it "registers an offense when using `#{receiver}.#{method}(Rails.public_path)` (if arity exists)" do expect_offense(<<~RUBY, receiver: receiver, method: method) %{receiver}.%{method}(Rails.public_path) - ^{receiver}^^{method}^^^^^^^^^^^^^^^^^^^ `Rails.public_path` is a `Pathname` so you can just append `#%{method}`. + ^{receiver}^^{method}^^^^^^^^^^^^^^^^^^^ `Rails.public_path` is a `Pathname`, so you can use `Rails.public_path.%{method}`. RUBY expect_correction(<<~RUBY) @@ -23,7 +23,7 @@ it "registers an offense when using `::#{receiver}.#{method}(::Rails.root.join(...))` (if arity exists)" do expect_offense(<<~RUBY, receiver: receiver, method: method) ::%{receiver}.%{method}(::Rails.root.join('db', 'schema.rb')) - ^^^{receiver}^^{method}^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `::Rails.root` is a `Pathname` so you can just append `#%{method}`. + ^^^{receiver}^^{method}^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `::Rails.root` is a `Pathname`, so you can use `::Rails.root.join('db', 'schema.rb').%{method}`. RUBY expect_correction(<<~RUBY) @@ -34,7 +34,7 @@ it "registers an offense when using `::#{receiver}.#{method}(::Rails.root.join(...), ...)` (if arity exists)" do expect_offense(<<~RUBY, receiver: receiver, method: method) ::%{receiver}.%{method}(::Rails.root.join('db', 'schema.rb'), 20, 5) - ^^^{receiver}^^{method}^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `::Rails.root` is a `Pathname` so you can just append `#%{method}`. + ^^^{receiver}^^{method}^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `::Rails.root` is a `Pathname`, so you can use `::Rails.root.join('db', 'schema.rb').%{method}(20, 5)`. RUBY expect_correction(<<~RUBY) @@ -56,7 +56,7 @@ it "registers an offense when using `Dir.glob(Rails.root.join('**/*.rb'))`" do expect_offense(<<~RUBY) Dir.glob(Rails.root.join('**/*.rb')) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#glob`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.glob('**/*.rb')`. RUBY expect_correction(<<~RUBY) @@ -67,7 +67,7 @@ it "registers an offense when using `::Dir.glob(Rails.root.join('**/*.rb'))`" do expect_offense(<<~RUBY) ::Dir.glob(Rails.root.join('**/*.rb')) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#glob`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.glob('**/*.rb')`. RUBY expect_correction(<<~RUBY) @@ -78,7 +78,7 @@ it "registers an offense when using `Dir.glob(Rails.root.join('**/\#{path}/*.rb'))`" do expect_offense(<<~'RUBY') Dir.glob(Rails.root.join("**/#{path}/*.rb")) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#glob`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.glob("**/#{path}/*.rb")`. RUBY expect_correction(<<~'RUBY') @@ -89,7 +89,7 @@ it "registers an offense when using `Dir.glob(Rails.root.join('**', '*.rb'))`" do expect_offense(<<~RUBY) Dir.glob(Rails.root.join('**', '*.rb')) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#glob`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.glob('**/*.rb')`. RUBY expect_correction(<<~RUBY) @@ -105,7 +105,7 @@ it "registers an offense when using `Dir.glob(Rails.root.join('**', '*.rb'))`" do expect_offense(<<~RUBY) Dir.glob(Rails.root.join('**', '*.rb')) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#glob`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.glob("**/*.rb")`. RUBY expect_correction(<<~RUBY) @@ -117,7 +117,7 @@ it "registers an offense when using `Dir.glob(Rails.root.join('**', \"\#{path}\", '*.rb'))`" do expect_offense(<<~'RUBY') Dir.glob(Rails.root.join('**', "#{path}", '*.rb')) - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#glob`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.glob("**/#{path}/*.rb")`. RUBY expect_correction(<<~'RUBY') @@ -128,7 +128,7 @@ it 'registers an offense when using `Rails.env` argument within `Dir.glob`' do expect_offense(<<~RUBY) Dir.glob(Rails.root.join("db", "seeds", Rails.env, "*.rb")).sort.each do |file| - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#glob`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.glob("db/seeds/\#{Rails.env}/*.rb")`. load file end RUBY @@ -145,7 +145,7 @@ it 'registers offense when using `Dir[Rails.root.join(...)]`' do expect_offense(<<~RUBY) Dir[Rails.root.join('spec/support/**/*.rb')] - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#[]`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.glob('spec/support/**/*.rb')`. RUBY expect_correction(<<~RUBY) @@ -192,7 +192,7 @@ it 'registers an offense when using `File.open(Rails.root.join(...), ...)` inside an iterator' do expect_offense(<<~RUBY) files.map { |file| File.open(Rails.root.join('db', file), 'wb') } - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#open`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.join('db', file).open('wb')`. RUBY expect_correction(<<~RUBY) @@ -203,7 +203,7 @@ it 'registers an offense when using `File.open Rails.root.join ...` without parens' do expect_offense(<<~RUBY) file = File.open Rails.root.join 'docs', 'invoice.pdf' - ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname` so you can just append `#open`. + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rails.root` is a `Pathname`, so you can use `Rails.root.join('docs', 'invoice.pdf').open`. RUBY expect_correction(<<~RUBY) From 4c97338d95a6fe5ee454098cd4bd3bc174606e32 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:25:58 +0200 Subject: [PATCH 20/52] [Issue #1269] Revert #1344, add `Rails/ActionControllerFlashBeforeRender` tests from issue #1269 This reverts commit 0f703db581ffbf49830d0c1705c57129b6a7d4aa, reversing changes made to 0f63f00ecee27313e92eedad74a33b7c5ef21be1. This cop would need to do control flow analysis which it just doesn't do. RuboCop also has no mechanism for that. So just reverting this for now to fix the newly introduces false positives --- changelog/fix_revert_flash_before_render.md | 1 + .../action_controller_flash_before_render.rb | 10 +- ...ion_controller_flash_before_render_spec.rb | 246 +++++------------- 3 files changed, 74 insertions(+), 183 deletions(-) create mode 100644 changelog/fix_revert_flash_before_render.md diff --git a/changelog/fix_revert_flash_before_render.md b/changelog/fix_revert_flash_before_render.md new file mode 100644 index 0000000000..4a7cab0316 --- /dev/null +++ b/changelog/fix_revert_flash_before_render.md @@ -0,0 +1 @@ +* [#1269](https://github.com/rubocop/rubocop-rails/issues/1269): Fix false positives for `Rails/ActionControllerFlashBeforeRender` in combination with implicit returns. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/action_controller_flash_before_render.rb b/lib/rubocop/cop/rails/action_controller_flash_before_render.rb index bf4602cdab..806e92e455 100644 --- a/lib/rubocop/cop/rails/action_controller_flash_before_render.rb +++ b/lib/rubocop/cop/rails/action_controller_flash_before_render.rb @@ -72,13 +72,13 @@ def followed_by_render?(flash_node) if (node = context.each_ancestor(:if, :rescue).first) return false if use_redirect_to?(context) - context = node.rescue_type? ? node.parent : node + context = node + elsif context.right_siblings.empty? + return true end + context = context.right_siblings - siblings = context.right_siblings - return true if siblings.empty? - - siblings.compact.any? do |render_candidate| + context.compact.any? do |render_candidate| render?(render_candidate) end end diff --git a/spec/rubocop/cop/rails/action_controller_flash_before_render_spec.rb b/spec/rubocop/cop/rails/action_controller_flash_before_render_spec.rb index 0c8f682e16..6ca55d122b 100644 --- a/spec/rubocop/cop/rails/action_controller_flash_before_render_spec.rb +++ b/spec/rubocop/cop/rails/action_controller_flash_before_render_spec.rb @@ -128,36 +128,9 @@ def create end end RUBY - - expect_offense(<<~RUBY) - class HomeController < #{parent_class} - def create - flash[:alert] = "msg" if condition - ^^^^^ Use `flash.now` before `render`. - end - end - RUBY - - expect_correction(<<~RUBY) - class HomeController < #{parent_class} - def create - flash.now[:alert] = "msg" if condition - end - end - RUBY end it 'does not register an offense when using `flash` before `redirect_to`' do - expect_no_offenses(<<~RUBY) - class HomeController < #{parent_class} - def create - flash[:alert] = "msg" if condition - - redirect_to :index - end - end - RUBY - expect_no_offenses(<<~RUBY) class HomeController < #{parent_class} def create @@ -172,16 +145,6 @@ def create end it 'does not register an offense when using `flash` before `redirect_back`' do - expect_no_offenses(<<~RUBY) - class HomeController < #{parent_class} - def create - flash[:alert] = "msg" if condition - - redirect_back fallback_location: root_path - end - end - RUBY - expect_no_offenses(<<~RUBY) class HomeController < #{parent_class} def create @@ -195,7 +158,7 @@ def create RUBY end - it 'registers an offense when using `flash` in multiline `if` branch before `render`' do + it 'registers an offense when using `flash` in multiline `if` branch before `render_to`' do expect_offense(<<~RUBY) class HomeController < #{parent_class} def create @@ -222,29 +185,6 @@ def create end end RUBY - - expect_offense(<<~RUBY) - class HomeController < #{parent_class} - def create - if condition - do_something - flash[:alert] = "msg" - ^^^^^ Use `flash.now` before `render`. - end - end - end - RUBY - - expect_correction(<<~RUBY) - class HomeController < #{parent_class} - def create - if condition - do_something - flash.now[:alert] = "msg" - end - end - end - RUBY end it 'does not register an offense when using `flash` in multiline `if` branch before `redirect_to`' do @@ -277,81 +217,6 @@ def create end end RUBY - - expect_no_offenses(<<~RUBY) - class HomeController < #{parent_class} - def create - if condition - flash[:alert] = "msg" - redirect_to :index - - return - end - end - end - RUBY - end - - it 'registers an offense when using `flash` in multiline `rescue` branch before `render`' do - expect_offense(<<~RUBY) - class HomeController < #{parent_class} - def create - begin - do_something - flash[:alert] = "msg in begin" - ^^^^^ Use `flash.now` before `render`. - rescue - flash[:alert] = "msg in rescue" - ^^^^^ Use `flash.now` before `render`. - end - - render :index - end - end - RUBY - - expect_correction(<<~RUBY) - class HomeController < #{parent_class} - def create - begin - do_something - flash.now[:alert] = "msg in begin" - rescue - flash.now[:alert] = "msg in rescue" - end - - render :index - end - end - RUBY - - expect_offense(<<~RUBY) - class HomeController < #{parent_class} - def create - begin - do_something - flash[:alert] = "msg in begin" - ^^^^^ Use `flash.now` before `render`. - rescue - flash[:alert] = "msg in rescue" - ^^^^^ Use `flash.now` before `render`. - end - end - end - RUBY - - expect_correction(<<~RUBY) - class HomeController < #{parent_class} - def create - begin - do_something - flash.now[:alert] = "msg in begin" - rescue - flash.now[:alert] = "msg in rescue" - end - end - end - RUBY end it 'does not register an offense when using `flash` in multiline `rescue` branch before `redirect_to`' do @@ -370,48 +235,6 @@ def create end RUBY end - - it 'does not register an offense when using `flash` before `redirect_to` in `rescue` branch' do - expect_no_offenses(<<~RUBY) - class HomeController < #{parent_class} - def create - begin - do_something - flash[:alert] = "msg in begin" - redirect_to :index - - return - rescue - flash[:alert] = "msg in rescue" - redirect_to :index - - return - end - - render :index - end - end - RUBY - - expect_no_offenses(<<~RUBY) - class HomeController < #{parent_class} - def create - begin - do_something - flash[:alert] = "msg in begin" - redirect_to :index - - return - rescue - flash[:alert] = "msg in rescue" - redirect_to :index - - return - end - end - end - RUBY - end end end @@ -505,4 +328,71 @@ def create RUBY end end + + context 'when using `flash` after `render` and `redirect_to` is used in implicit return branch ' \ + 'and render is is used in the other branch' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + class HomeController < ApplicationController + def create + if foo.update(params) + flash[:success] = 'msg' + + if redirect_to_index? + redirect_to index + else + redirect_to path(foo) + end + else + flash.now[:alert] = 'msg' + render :edit, status: :unprocessable_entity + end + end + end + RUBY + end + end + + context 'when using `flash` after `render` and `render` is part of a different preceding branch' \ + 'that implicitly returns' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + class HomeController < ApplicationController + def create + if remote_request? || sandbox? + if current_user.nil? + render :index + else + head :forbidden + end + elsif current_user.nil? + redirect_to sign_in_path + else + flash[:alert] = 'msg' + if request.referer.present? + redirect_to(request.referer) + else + redirect_to(root_path) + end + end + end + end + RUBY + end + end + + context 'when using `flash` in `rescue` and `redirect_to` in `ensure`' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + class HomeController < ApplicationController + def create + rescue + flash[:alert] = 'msg' + ensure + redirect_to :index + end + end + RUBY + end + end end From dbdee93776ae3df24d35ce5440c803b1efb52bda Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Tue, 3 Sep 2024 12:30:50 +0200 Subject: [PATCH 21/52] [Fix #1343] False negatives for `Rails/EnumSyntax` I don't believe there is any issue with just looking at all value types. It just translates `foo: bar` into `:foo, bar`. Additionally, add `instance_methods` as a rails option. Not doing this would result autocorrect treating it as a enum column --- changelog/fix_false_negatives_enum_syntax.md | 1 + lib/rubocop/cop/rails/enum_syntax.rb | 26 +++++++---------- spec/rubocop/cop/rails/enum_syntax_spec.rb | 30 ++++++++++++++++++-- 3 files changed, 40 insertions(+), 17 deletions(-) create mode 100644 changelog/fix_false_negatives_enum_syntax.md diff --git a/changelog/fix_false_negatives_enum_syntax.md b/changelog/fix_false_negatives_enum_syntax.md new file mode 100644 index 0000000000..b1d030fdf2 --- /dev/null +++ b/changelog/fix_false_negatives_enum_syntax.md @@ -0,0 +1 @@ +* [#1343](https://github.com/rubocop/rubocop-rails/issues/1343): Fix false negatives for `Rails/EnumSyntax` for non-literal mappings. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/enum_syntax.rb b/lib/rubocop/cop/rails/enum_syntax.rb index 39501c4331..9a36dadfef 100644 --- a/lib/rubocop/cop/rails/enum_syntax.rb +++ b/lib/rubocop/cop/rails/enum_syntax.rb @@ -24,7 +24,10 @@ class EnumSyntax < Base MSG = 'Enum defined with keyword arguments in `%s` enum declaration. Use positional arguments instead.' MSG_OPTIONS = 'Enum defined with deprecated options in `%s` enum declaration. Remove the `_` prefix.' RESTRICT_ON_SEND = %i[enum].freeze - OPTION_NAMES = %w[prefix suffix scopes default].freeze + + # From https://github.com/rails/rails/blob/v7.2.1/activerecord/lib/active_record/enum.rb#L231 + OPTION_NAMES = %w[prefix suffix scopes default instance_methods].freeze + UNDERSCORED_OPTION_NAMES = OPTION_NAMES.map { |option| "_#{option}" }.freeze def_node_matcher :enum?, <<~PATTERN (send nil? :enum (hash $...)) @@ -34,14 +37,6 @@ class EnumSyntax < Base (send nil? :enum $_ ${array hash} $_) PATTERN - def_node_matcher :enum_values, <<~PATTERN - (pair $_ ${array hash}) - PATTERN - - def_node_matcher :enum_options, <<~PATTERN - (pair $_ $_) - PATTERN - def on_send(node) check_and_correct_keyword_args(node) check_enum_options(node) @@ -52,10 +47,9 @@ def on_send(node) def check_and_correct_keyword_args(node) enum?(node) do |pairs| pairs.each do |pair| - key, values = enum_values(pair) - next unless key + next if option_key?(pair) - correct_keyword_args(node, key, values, pairs[1..]) + correct_keyword_args(node, pair.key, pair.value, pairs[1..]) end end end @@ -63,9 +57,7 @@ def check_and_correct_keyword_args(node) def check_enum_options(node) enum_with_options?(node) do |key, _, options| options.children.each do |option| - name, = enum_options(option) - - add_offense(name, message: format(MSG_OPTIONS, enum: enum_name_value(key))) if name.source[0] == '_' + add_offense(option.key, message: format(MSG_OPTIONS, enum: enum_name_value(key))) if option_key?(option) end end end @@ -107,6 +99,10 @@ def enum_name(elem) end end + def option_key?(pair) + UNDERSCORED_OPTION_NAMES.include?(pair.key.source) + end + def correct_options(options) corrected_options = options.map do |pair| name = if pair.key.source[0] == '_' diff --git a/spec/rubocop/cop/rails/enum_syntax_spec.rb b/spec/rubocop/cop/rails/enum_syntax_spec.rb index 2abf4e47fa..80c698cc05 100644 --- a/spec/rubocop/cop/rails/enum_syntax_spec.rb +++ b/spec/rubocop/cop/rails/enum_syntax_spec.rb @@ -82,6 +82,32 @@ end end + context 'when the enum name is underscored' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum :_key => { active: 0, archived: 1 }, _prefix: true + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `_key` enum declaration. Use positional arguments instead. + RUBY + + expect_correction(<<~RUBY) + enum :_key, { active: 0, archived: 1 }, prefix: true + RUBY + end + end + + context 'when the enum value is not a literal' do + it 'registers an offense' do + expect_offense(<<~RUBY) + enum key: %i[foo bar].map.with_index { |v, i| [v, i] }.to_h + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `key` enum declaration. Use positional arguments instead. + RUBY + + expect_correction(<<~RUBY) + enum :key, %i[foo bar].map.with_index { |v, i| [v, i] }.to_h + RUBY + end + end + it 'autocorrects' do expect_offense(<<~RUBY) enum status: { active: 0, archived: 1 } @@ -95,12 +121,12 @@ it 'autocorrects options too' do expect_offense(<<~RUBY) - enum status: { active: 0, archived: 1 }, _prefix: true, _suffix: true, _default: :active, _scopes: true + enum status: { active: 0, archived: 1 }, _prefix: true, _suffix: true, _default: :active, _scopes: true, _instance_methods: true ^^^^^^^^^^^^^^^^^^^^^^^^^^ Enum defined with keyword arguments in `status` enum declaration. Use positional arguments instead. RUBY expect_correction(<<~RUBY) - enum :status, { active: 0, archived: 1 }, prefix: true, suffix: true, default: :active, scopes: true + enum :status, { active: 0, archived: 1 }, prefix: true, suffix: true, default: :active, scopes: true, instance_methods: true RUBY end end From 0a80131242a53569e6a96a996c86e65da2068320 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Tue, 3 Sep 2024 19:24:27 +0300 Subject: [PATCH 22/52] Change `Rails/EnumSyntax` to autocorrect underscored options --- ...change_enum_syntax_to_autoccorect_underscored_options.md | 1 + lib/rubocop/cop/rails/enum_syntax.rb | 6 +++++- spec/rubocop/cop/rails/enum_syntax_spec.rb | 6 +++++- 3 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 changelog/change_enum_syntax_to_autoccorect_underscored_options.md diff --git a/changelog/change_enum_syntax_to_autoccorect_underscored_options.md b/changelog/change_enum_syntax_to_autoccorect_underscored_options.md new file mode 100644 index 0000000000..f497ea13de --- /dev/null +++ b/changelog/change_enum_syntax_to_autoccorect_underscored_options.md @@ -0,0 +1 @@ +* [#1350](https://github.com/rubocop/rubocop-rails/pull/1350): Change `Rails/EnumSyntax` to autocorrect underscored options. ([@fatkodima][]) diff --git a/lib/rubocop/cop/rails/enum_syntax.rb b/lib/rubocop/cop/rails/enum_syntax.rb index 9a36dadfef..a3d650440a 100644 --- a/lib/rubocop/cop/rails/enum_syntax.rb +++ b/lib/rubocop/cop/rails/enum_syntax.rb @@ -57,7 +57,11 @@ def check_and_correct_keyword_args(node) def check_enum_options(node) enum_with_options?(node) do |key, _, options| options.children.each do |option| - add_offense(option.key, message: format(MSG_OPTIONS, enum: enum_name_value(key))) if option_key?(option) + next unless option_key?(option) + + add_offense(option.key, message: format(MSG_OPTIONS, enum: enum_name_value(key))) do |corrector| + corrector.replace(option.key, option.key.source.delete_prefix('_')) + end end end end diff --git a/spec/rubocop/cop/rails/enum_syntax_spec.rb b/spec/rubocop/cop/rails/enum_syntax_spec.rb index 80c698cc05..9799fe66d1 100644 --- a/spec/rubocop/cop/rails/enum_syntax_spec.rb +++ b/spec/rubocop/cop/rails/enum_syntax_spec.rb @@ -47,12 +47,16 @@ end context 'with options prefixed with `_`' do - it 'registers an offense' do + it 'registers an offense and corrects' do expect_offense(<<~RUBY) enum :status, { active: 0, archived: 1 }, _prefix: true, _suffix: true ^^^^^^^ Enum defined with deprecated options in `status` enum declaration. Remove the `_` prefix. ^^^^^^^ Enum defined with deprecated options in `status` enum declaration. Remove the `_` prefix. RUBY + + expect_correction(<<~RUBY) + enum :status, { active: 0, archived: 1 }, prefix: true, suffix: true + RUBY end end From ff0759314dcb41009b96919d45ed12217a8d63ca Mon Sep 17 00:00:00 2001 From: fatkodima Date: Tue, 3 Sep 2024 19:05:58 +0300 Subject: [PATCH 23/52] Change `Rails/ApplicationRecord` to ignore migrations --- changelog/change_application_record_to_ignore_migrations.md | 1 + config/default.yml | 4 +++- lib/rubocop/cop/rails/application_record.rb | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelog/change_application_record_to_ignore_migrations.md diff --git a/changelog/change_application_record_to_ignore_migrations.md b/changelog/change_application_record_to_ignore_migrations.md new file mode 100644 index 0000000000..59f8e2259d --- /dev/null +++ b/changelog/change_application_record_to_ignore_migrations.md @@ -0,0 +1 @@ +* [#1342](https://github.com/rubocop/rubocop-rails/issues/1342): Change `Rails/ApplicationRecord` to ignore migrations. ([@fatkodima][]) diff --git a/config/default.yml b/config/default.yml index 97b01498b0..74a0251182 100644 --- a/config/default.yml +++ b/config/default.yml @@ -212,7 +212,9 @@ Rails/ApplicationRecord: Enabled: true SafeAutoCorrect: false VersionAdded: '0.49' - VersionChanged: '2.5' + VersionChanged: '<>' + Exclude: + - db/**/*.rb Rails/ArelStar: Description: 'Enforces `Arel.star` instead of `"*"` for expanded columns.' diff --git a/lib/rubocop/cop/rails/application_record.rb b/lib/rubocop/cop/rails/application_record.rb index 91ee5e2aaf..f5f40bcdc2 100644 --- a/lib/rubocop/cop/rails/application_record.rb +++ b/lib/rubocop/cop/rails/application_record.rb @@ -5,6 +5,10 @@ module Cop module Rails # Checks that models subclass `ApplicationRecord` with Rails 5.0. # + # It is a common practice to define models inside migrations in order to retain forward + # compatibility by avoiding loading any application code. And so migration files are excluded + # by default for this cop. + # # @safety # This cop's autocorrection is unsafe because it may let the logic from `ApplicationRecord` # sneak into an Active Record model that is not purposed to inherit logic common among other From 5a0a69a5f0f81a59a514530424b032fde0f7bc97 Mon Sep 17 00:00:00 2001 From: masato-bkn <37011138+masato-bkn@users.noreply.github.com> Date: Wed, 4 Sep 2024 23:29:53 +0900 Subject: [PATCH 24/52] Fix example in `Rails/PluralizationGrammar` --- lib/rubocop/cop/rails/pluralization_grammar.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rubocop/cop/rails/pluralization_grammar.rb b/lib/rubocop/cop/rails/pluralization_grammar.rb index beaaa8d736..4ee227b486 100644 --- a/lib/rubocop/cop/rails/pluralization_grammar.rb +++ b/lib/rubocop/cop/rails/pluralization_grammar.rb @@ -11,7 +11,7 @@ module Rails # 3.day.ago # 1.months.ago # 5.megabyte - # 1.gigabyte + # 1.gigabytes # # # good # 3.days.ago From 027db53f1778a11c57d2a4b8fd1c7833ddfc793a Mon Sep 17 00:00:00 2001 From: masato-bkn <37011138+masato-bkn@users.noreply.github.com> Date: Sat, 7 Sep 2024 12:15:20 +0900 Subject: [PATCH 25/52] Add missing tests for `Rails/CompactBlank` when receiver is a hash --- spec/rubocop/cop/rails/compact_blank_spec.rb | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/spec/rubocop/cop/rails/compact_blank_spec.rb b/spec/rubocop/cop/rails/compact_blank_spec.rb index 93d1ca2bd7..3b3cd9d77b 100644 --- a/spec/rubocop/cop/rails/compact_blank_spec.rb +++ b/spec/rubocop/cop/rails/compact_blank_spec.rb @@ -24,6 +24,17 @@ RUBY end + it 'registers and corrects an offense when using `reject { |k, v| v.blank? }`' do + expect_offense(<<~RUBY) + collection.reject { |k, v| v.blank? } + ^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact_blank` instead. + RUBY + + expect_correction(<<~RUBY) + collection.compact_blank + RUBY + end + it 'registers and corrects an offense when using `delete_if { |e| e.blank? }`' do expect_offense(<<~RUBY) collection.delete_if { |e| e.blank? } @@ -46,6 +57,17 @@ RUBY end + it 'registers and corrects an offense when using `delete_if { |k, v| v.blank? }`' do + expect_offense(<<~RUBY) + collection.delete_if { |k, v| v.blank? } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact_blank!` instead. + RUBY + + expect_correction(<<~RUBY) + collection.compact_blank! + RUBY + end + it 'does not registers an offense when using `reject! { |e| e.blank? }`' do expect_no_offenses(<<~RUBY) collection.reject! { |e| e.blank? } @@ -91,6 +113,17 @@ RUBY end + it 'registers and corrects an offense when using `select { |k, v| v.present? }`' do + expect_offense(<<~RUBY) + collection.select { |k, v| v.present? } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact_blank` instead. + RUBY + + expect_correction(<<~RUBY) + collection.compact_blank + RUBY + end + it 'registers and corrects an offense when using `keep_if { |e| e.present? }`' do expect_offense(<<~RUBY) collection.keep_if { |e| e.present? } @@ -113,6 +146,17 @@ RUBY end + it 'registers and corrects an offense when using `keep_if { |k, v| v.present? }`' do + expect_offense(<<~RUBY) + collection.keep_if { |k, v| v.present? } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact_blank!` instead. + RUBY + + expect_correction(<<~RUBY) + collection.compact_blank! + RUBY + end + it 'does not register an offense when using `select! { |e| e.present? }`' do expect_no_offenses(<<~RUBY) collection.select! { |e| e.present? } From 22bc59e3a0c6991dfc771ebe9b4c2c4e868e3d20 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 7 Sep 2024 17:06:43 +0900 Subject: [PATCH 26/52] Update Changelog --- CHANGELOG.md | 10 ++++++++++ .../change_application_record_to_ignore_migrations.md | 1 - ...e_enum_syntax_to_autoccorect_underscored_options.md | 1 - changelog/fix_false_negatives_enum_syntax.md | 1 - changelog/fix_false_positive_database_qualified.md | 1 - 5 files changed, 10 insertions(+), 4 deletions(-) delete mode 100644 changelog/change_application_record_to_ignore_migrations.md delete mode 100644 changelog/change_enum_syntax_to_autoccorect_underscored_options.md delete mode 100644 changelog/fix_false_negatives_enum_syntax.md delete mode 100644 changelog/fix_false_positive_database_qualified.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 8671e1bf72..f4ef61d35a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ ## master (unreleased) +### Bug fixes + +* [#1343](https://github.com/rubocop/rubocop-rails/issues/1343): Fix false negatives for `Rails/EnumSyntax` for non-literal mappings. ([@earlopain][]) +* [#1340](https://github.com/rubocop/rubocop-rails/issues/1340): Fix a false positive for `Rails/WhereEquals`, `Rails/WhereNot`, and `Rails/WhereRange` when qualifying the database name. ([@earlopain][]) + +### Changes + +* [#1342](https://github.com/rubocop/rubocop-rails/issues/1342): Change `Rails/ApplicationRecord` to ignore migrations. ([@fatkodima][]) +* [#1350](https://github.com/rubocop/rubocop-rails/pull/1350): Change `Rails/EnumSyntax` to autocorrect underscored options. ([@fatkodima][]) + ## 2.26.0 (2024-08-24) ### New features diff --git a/changelog/change_application_record_to_ignore_migrations.md b/changelog/change_application_record_to_ignore_migrations.md deleted file mode 100644 index 59f8e2259d..0000000000 --- a/changelog/change_application_record_to_ignore_migrations.md +++ /dev/null @@ -1 +0,0 @@ -* [#1342](https://github.com/rubocop/rubocop-rails/issues/1342): Change `Rails/ApplicationRecord` to ignore migrations. ([@fatkodima][]) diff --git a/changelog/change_enum_syntax_to_autoccorect_underscored_options.md b/changelog/change_enum_syntax_to_autoccorect_underscored_options.md deleted file mode 100644 index f497ea13de..0000000000 --- a/changelog/change_enum_syntax_to_autoccorect_underscored_options.md +++ /dev/null @@ -1 +0,0 @@ -* [#1350](https://github.com/rubocop/rubocop-rails/pull/1350): Change `Rails/EnumSyntax` to autocorrect underscored options. ([@fatkodima][]) diff --git a/changelog/fix_false_negatives_enum_syntax.md b/changelog/fix_false_negatives_enum_syntax.md deleted file mode 100644 index b1d030fdf2..0000000000 --- a/changelog/fix_false_negatives_enum_syntax.md +++ /dev/null @@ -1 +0,0 @@ -* [#1343](https://github.com/rubocop/rubocop-rails/issues/1343): Fix false negatives for `Rails/EnumSyntax` for non-literal mappings. ([@earlopain][]) diff --git a/changelog/fix_false_positive_database_qualified.md b/changelog/fix_false_positive_database_qualified.md deleted file mode 100644 index 50e815b818..0000000000 --- a/changelog/fix_false_positive_database_qualified.md +++ /dev/null @@ -1 +0,0 @@ -* [#1340](https://github.com/rubocop/rubocop-rails/issues/1340): Fix a false positive for `Rails/WhereEquals`, `Rails/WhereNot`, and `Rails/WhereRange` when qualifying the database name. ([@earlopain][]) From 6d6fca2e6fc6e4c4d0785c09538b59f8f55a5f6c Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 7 Sep 2024 17:07:14 +0900 Subject: [PATCH 27/52] Cut 2.26.1 --- CHANGELOG.md | 2 ++ config/default.yml | 2 +- docs/antora.yml | 2 +- docs/modules/ROOT/pages/cops_rails.adoc | 21 +++++++++++++++++++-- lib/rubocop/rails/version.rb | 2 +- relnotes/v2.26.1.md | 12 ++++++++++++ 6 files changed, 36 insertions(+), 5 deletions(-) create mode 100644 relnotes/v2.26.1.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f4ef61d35a..ae1c5d800e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ## master (unreleased) +## 2.26.1 (2024-09-07) + ### Bug fixes * [#1343](https://github.com/rubocop/rubocop-rails/issues/1343): Fix false negatives for `Rails/EnumSyntax` for non-literal mappings. ([@earlopain][]) diff --git a/config/default.yml b/config/default.yml index 74a0251182..b59db897c5 100644 --- a/config/default.yml +++ b/config/default.yml @@ -212,7 +212,7 @@ Rails/ApplicationRecord: Enabled: true SafeAutoCorrect: false VersionAdded: '0.49' - VersionChanged: '<>' + VersionChanged: '2.26' Exclude: - db/**/*.rb diff --git a/docs/antora.yml b/docs/antora.yml index 9e0ff48acb..0e3477f379 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-rails title: RuboCop Rails # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: ~ +version: '2.26' nav: - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/pages/cops_rails.adoc b/docs/modules/ROOT/pages/cops_rails.adoc index b946879608..ad89ca7c52 100644 --- a/docs/modules/ROOT/pages/cops_rails.adoc +++ b/docs/modules/ROOT/pages/cops_rails.adoc @@ -612,11 +612,15 @@ end | Yes | Always (Unsafe) | 0.49 -| 2.5 +| 2.26 |=== Checks that models subclass `ApplicationRecord` with Rails 5.0. +It is a common practice to define models inside migrations in order to retain forward +compatibility by avoiding loading any application code. And so migration files are excluded +by default for this cop. + === Safety This cop's autocorrection is unsafe because it may let the logic from `ApplicationRecord` @@ -638,6 +642,16 @@ class Rails4Model < ActiveRecord::Base end ---- +=== Configurable attributes + +|=== +| Name | Default value | Configurable values + +| Exclude +| `+db/**/*.rb+` +| Array +|=== + == Rails/ArelStar |=== @@ -4178,7 +4192,7 @@ core extensions to the numeric classes. 3.day.ago 1.months.ago 5.megabyte -1.gigabyte +1.gigabytes # good 3.days.ago @@ -5458,6 +5472,8 @@ File.read(Rails.root.join('db', 'schema.rb')) File.binread(Rails.root.join('db', 'schema.rb')) File.write(Rails.root.join('db', 'schema.rb'), content) File.binwrite(Rails.root.join('db', 'schema.rb'), content) +Dir.glob(Rails.root.join('db', 'schema.rb')) +Dir[Rails.root.join('db', 'schema.rb')] # good Rails.root.join('db', 'schema.rb').open @@ -5466,6 +5482,7 @@ Rails.root.join('db', 'schema.rb').read Rails.root.join('db', 'schema.rb').binread Rails.root.join('db', 'schema.rb').write(content) Rails.root.join('db', 'schema.rb').binwrite(content) +Rails.root.glob("db/schema.rb") ---- == Rails/RootPublicPath diff --git a/lib/rubocop/rails/version.rb b/lib/rubocop/rails/version.rb index 438e0a2245..c77f1c36d1 100644 --- a/lib/rubocop/rails/version.rb +++ b/lib/rubocop/rails/version.rb @@ -4,7 +4,7 @@ module RuboCop module Rails # This module holds the RuboCop Rails version information. module Version - STRING = '2.26.0' + STRING = '2.26.1' def self.document_version STRING.match('\d+\.\d+').to_s diff --git a/relnotes/v2.26.1.md b/relnotes/v2.26.1.md new file mode 100644 index 0000000000..4a0505bc57 --- /dev/null +++ b/relnotes/v2.26.1.md @@ -0,0 +1,12 @@ +### Bug fixes + +* [#1343](https://github.com/rubocop/rubocop-rails/issues/1343): Fix false negatives for `Rails/EnumSyntax` for non-literal mappings. ([@earlopain][]) +* [#1340](https://github.com/rubocop/rubocop-rails/issues/1340): Fix a false positive for `Rails/WhereEquals`, `Rails/WhereNot`, and `Rails/WhereRange` when qualifying the database name. ([@earlopain][]) + +### Changes + +* [#1342](https://github.com/rubocop/rubocop-rails/issues/1342): Change `Rails/ApplicationRecord` to ignore migrations. ([@fatkodima][]) +* [#1350](https://github.com/rubocop/rubocop-rails/pull/1350): Change `Rails/EnumSyntax` to autocorrect underscored options. ([@fatkodima][]) + +[@earlopain]: https://github.com/earlopain +[@fatkodima]: https://github.com/fatkodima From ebf1762cf09d7033c385cdc99f1cf4f9ccc3273b Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 7 Sep 2024 17:15:32 +0900 Subject: [PATCH 28/52] Switch back docs version to master --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index 0e3477f379..9e0ff48acb 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-rails title: RuboCop Rails # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: '2.26' +version: ~ nav: - modules/ROOT/nav.adoc From cbb7257a4fdcd1378c5fe02149b48982bc9f41dc Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Mon, 9 Sep 2024 13:17:08 +0900 Subject: [PATCH 29/52] [Doc] Update the "Rails configuration tip" section Follow up https://github.com/rails/rails/pull/50506. --- README.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index adbf9a5464..b8d01488ca 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ end ## Rails configuration tip -If you are using Rails 6.1 or newer, add the following `config.generators.after_generate` setting to +In Rails 6.1+, add the following `config.generators.after_generate` setting to your `config/environments/development.rb` to apply RuboCop autocorrection to code generated by `bin/rails g`. ```ruby @@ -84,6 +84,20 @@ It uses `rubocop -A` to apply `Style/FrozenStringLiteralComment` and other unsaf `rubocop -A` is unsafe autocorrection, but code generated by default is simple and less likely to be incompatible with `rubocop -A`. If you have problems you can replace it with `rubocop -a` instead. +In Rails 7.2+, it is recommended to use `config.generators.apply_rubocop_autocorrect_after_generate!` instead of the above setting: + +```diff + # config/environments/development.rb + Rails.application.configure do + (snip) + # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. +- # config.generators.apply_rubocop_autocorrect_after_generate! ++ config.generators.apply_rubocop_autocorrect_after_generate! + end +``` + +You only need to uncomment. + ## The Cops All cops are located under From 9980211e21c78ec6c6a529e9bd1ec691732840bd Mon Sep 17 00:00:00 2001 From: masato-bkn <37011138+masato-bkn@users.noreply.github.com> Date: Sun, 8 Sep 2024 15:39:13 +0900 Subject: [PATCH 30/52] Support `filter` in `Rails/CompactBlank` --- ...e_support_filter_in_rails_compact_blank.md | 1 + lib/rubocop/cop/rails/compact_blank.rb | 11 ++-- spec/rubocop/cop/rails/compact_blank_spec.rb | 57 +++++++++++++++++++ 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 changelog/change_support_filter_in_rails_compact_blank.md diff --git a/changelog/change_support_filter_in_rails_compact_blank.md b/changelog/change_support_filter_in_rails_compact_blank.md new file mode 100644 index 0000000000..a439c69a02 --- /dev/null +++ b/changelog/change_support_filter_in_rails_compact_blank.md @@ -0,0 +1 @@ +* [#1359](https://github.com/rubocop/rubocop-rails/pull/1359): Support `filter` in `Rails/CompactBlank`. ([@masato-bkn][]) diff --git a/lib/rubocop/cop/rails/compact_blank.rb b/lib/rubocop/cop/rails/compact_blank.rb index a6f0f0860a..5b3535cf76 100644 --- a/lib/rubocop/cop/rails/compact_blank.rb +++ b/lib/rubocop/cop/rails/compact_blank.rb @@ -25,6 +25,8 @@ module Rails # collection.reject { |_k, v| v.blank? } # collection.select(&:present?) # collection.select { |_k, v| v.present? } + # collection.filter(&:present?) + # collection.filter { |_k, v| v.present? } # # # good # collection.compact_blank @@ -44,7 +46,8 @@ class CompactBlank < Base extend TargetRailsVersion MSG = 'Use `%s` instead.' - RESTRICT_ON_SEND = %i[reject delete_if select keep_if].freeze + RESTRICT_ON_SEND = %i[reject delete_if select filter keep_if].freeze + DESTRUCTIVE_METHODS = %i[delete_if keep_if].freeze minimum_target_rails_version 6.1 @@ -64,14 +67,14 @@ class CompactBlank < Base def_node_matcher :select_with_block?, <<~PATTERN (block - (send _ {:select :keep_if}) + (send _ {:select :filter :keep_if}) $(args ...) (send $(lvar _) :present?)) PATTERN def_node_matcher :select_with_block_pass?, <<~PATTERN - (send _ {:select :keep_if} + (send _ {:select :filter :keep_if} (block-pass (sym :present?))) PATTERN @@ -120,7 +123,7 @@ def offense_range(node) end def preferred_method(node) - node.method?(:reject) || node.method?(:select) ? 'compact_blank' : 'compact_blank!' + DESTRUCTIVE_METHODS.include?(node.method_name) ? 'compact_blank!' : 'compact_blank' end end end diff --git a/spec/rubocop/cop/rails/compact_blank_spec.rb b/spec/rubocop/cop/rails/compact_blank_spec.rb index 3b3cd9d77b..e89d7f3eca 100644 --- a/spec/rubocop/cop/rails/compact_blank_spec.rb +++ b/spec/rubocop/cop/rails/compact_blank_spec.rb @@ -124,6 +124,39 @@ RUBY end + it 'registers and corrects an offense when using `filter { |e| e.present? }`' do + expect_offense(<<~RUBY) + collection.filter { |e| e.present? } + ^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact_blank` instead. + RUBY + + expect_correction(<<~RUBY) + collection.compact_blank + RUBY + end + + it 'registers and corrects an offense when using `filter(&:present?)`' do + expect_offense(<<~RUBY) + collection.filter(&:present?) + ^^^^^^^^^^^^^^^^^^ Use `compact_blank` instead. + RUBY + + expect_correction(<<~RUBY) + collection.compact_blank + RUBY + end + + it 'registers and corrects an offense when using `filter { |k, v| v.present? }`' do + expect_offense(<<~RUBY) + collection.filter { |k, v| v.present? } + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact_blank` instead. + RUBY + + expect_correction(<<~RUBY) + collection.compact_blank + RUBY + end + it 'registers and corrects an offense when using `keep_if { |e| e.present? }`' do expect_offense(<<~RUBY) collection.keep_if { |e| e.present? } @@ -169,6 +202,18 @@ RUBY end + it 'does not register an offense when using `filter! { |e| e.present? }`' do + expect_no_offenses(<<~RUBY) + collection.filter! { |e| e.present? } + RUBY + end + + it 'does not register an offense when using `filter!(&:present?)`' do + expect_no_offenses(<<~RUBY) + collection.filter!(&:present?) + RUBY + end + it 'does not register an offense when using `compact_blank`' do expect_no_offenses(<<~RUBY) collection.compact_blank @@ -206,6 +251,12 @@ def foo(arg) collection.select { |e| e.blank? } RUBY end + + it 'does not register an offense when using `filter { |e| e.blank? }`' do + expect_no_offenses(<<~RUBY) + collection.filter { |e| e.blank? } + RUBY + end end context 'Rails <= 6.0', :rails60 do @@ -226,5 +277,11 @@ def foo(arg) collection.select { |e| e.present? } RUBY end + + it 'does not register an offense when using `filter { |e| e.present? }`' do + expect_no_offenses(<<~RUBY) + collection.filter { |e| e.present? } + RUBY + end end end From f4f3bf13a3433a1223e675d1954ac8ad74d96eca Mon Sep 17 00:00:00 2001 From: masato-bkn <37011138+masato-bkn@users.noreply.github.com> Date: Wed, 11 Sep 2024 22:02:52 +0900 Subject: [PATCH 31/52] Fix `Rails/CompactBlank` to avoid reporting offense for `filter` in Ruby versions below 2.6 --- lib/rubocop/cop/rails/compact_blank.rb | 1 + spec/rubocop/cop/rails/compact_blank_spec.rb | 21 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/rubocop/cop/rails/compact_blank.rb b/lib/rubocop/cop/rails/compact_blank.rb index 5b3535cf76..636faf5084 100644 --- a/lib/rubocop/cop/rails/compact_blank.rb +++ b/lib/rubocop/cop/rails/compact_blank.rb @@ -80,6 +80,7 @@ class CompactBlank < Base PATTERN def on_send(node) + return if target_ruby_version < 2.6 && node.method?(:filter) return unless bad_method?(node) range = offense_range(node) diff --git a/spec/rubocop/cop/rails/compact_blank_spec.rb b/spec/rubocop/cop/rails/compact_blank_spec.rb index e89d7f3eca..75937de4ee 100644 --- a/spec/rubocop/cop/rails/compact_blank_spec.rb +++ b/spec/rubocop/cop/rails/compact_blank_spec.rb @@ -257,6 +257,27 @@ def foo(arg) collection.filter { |e| e.blank? } RUBY end + + context 'target_ruby_version >= 2.6', :ruby26 do + it 'registers and corrects an offense when using `filter { |e| e.present? }`' do + expect_offense(<<~RUBY) + collection.filter { |e| e.present? } + ^^^^^^^^^^^^^^^^^^^^^^^^^ Use `compact_blank` instead. + RUBY + + expect_correction(<<~RUBY) + collection.compact_blank + RUBY + end + end + + context 'target_ruby_version < 2.6', :ruby25, unsupported_on: :prism do + it 'does not register an offense when using `filter { |e| e.present? }`' do + expect_no_offenses(<<~RUBY) + collection.filter { |e| e.present? } + RUBY + end + end end context 'Rails <= 6.0', :rails60 do From 50fe9a72fd1fa2012b05c1c2909427bf762760a0 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Thu, 12 Sep 2024 12:30:58 +0900 Subject: [PATCH 32/52] [Fix #1362] Fix false positives for `Rails/EnumSyntax` Fixes #1362. This PR fixes false positives for `Rails/EnumSyntax` when using Ruby 2.7. The warning shown in https://github.com/rubocop/rubocop-rails/issues/1238 appears starting from Rails 7.2 (Requires Ruby 3.1+). On the other hand, if users use Ruby 2.7, the warning reported in https://github.com/rubocop/rubocop-rails/issues/1362 will be displayed. Therefore, it would be appropriate to enable this cop only when analyzing Ruby 3.0+. Nothing will happen when using Ruby 2.7 with Rails 7.0 or Rails 7.1, but the warning in https://github.com/rubocop/rubocop-rails/issues/1238 will not be displayed either. Meanwhile, in Rails 7.2, which requires Ruby 3.1+, Ruby 2.7 cannot be used, so there is no issue. --- .../fix_false_positives_for_rails_enum_syntax.md | 1 + lib/rubocop/cop/rails/enum_syntax.rb | 2 ++ spec/rubocop/cop/rails/enum_syntax_spec.rb | 14 +++++++++++++- 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 changelog/fix_false_positives_for_rails_enum_syntax.md diff --git a/changelog/fix_false_positives_for_rails_enum_syntax.md b/changelog/fix_false_positives_for_rails_enum_syntax.md new file mode 100644 index 0000000000..914d96ff49 --- /dev/null +++ b/changelog/fix_false_positives_for_rails_enum_syntax.md @@ -0,0 +1 @@ +* [#1362](https://github.com/rubocop/rubocop-rails/issues/1362): Fix false positives for `Rails/EnumSyntax` when using Ruby 2.7. ([@koic][]) diff --git a/lib/rubocop/cop/rails/enum_syntax.rb b/lib/rubocop/cop/rails/enum_syntax.rb index a3d650440a..5b3d683916 100644 --- a/lib/rubocop/cop/rails/enum_syntax.rb +++ b/lib/rubocop/cop/rails/enum_syntax.rb @@ -17,8 +17,10 @@ module Rails # class EnumSyntax < Base extend AutoCorrector + extend TargetRubyVersion extend TargetRailsVersion + minimum_target_ruby_version 3.0 minimum_target_rails_version 7.0 MSG = 'Enum defined with keyword arguments in `%s` enum declaration. Use positional arguments instead.' diff --git a/spec/rubocop/cop/rails/enum_syntax_spec.rb b/spec/rubocop/cop/rails/enum_syntax_spec.rb index 9799fe66d1..b5f20a2436 100644 --- a/spec/rubocop/cop/rails/enum_syntax_spec.rb +++ b/spec/rubocop/cop/rails/enum_syntax_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true RSpec.describe RuboCop::Cop::Rails::EnumSyntax, :config do - context 'Rails >= 7.0', :rails70 do + context 'Rails >= 7.0 and Ruby >= 3.0', :rails70, :ruby30 do context 'when keyword arguments are used' do context 'with %i[] syntax' do it 'registers an offense' do @@ -148,6 +148,18 @@ end end + context 'Rails >= 7.0 and Ruby <= 2.7', :rails70, :ruby27, unsupported_on: :prism do + context 'when keyword arguments are used' do + context 'with %i[] syntax' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + enum status: %i[active archived], _prefix: true + RUBY + end + end + end + end + context 'Rails <= 6.1', :rails61 do context 'when keyword arguments are used' do context 'with %i[] syntax' do From 38cec18985618f9879d7308b37af0f8100c35f1a Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 14 Sep 2024 05:09:07 +0900 Subject: [PATCH 33/52] [Doc] Sync the Rails configuration tip with the README --- docs/modules/ROOT/pages/usage.adoc | 32 +++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index 1b68c110d4..97cfe75cec 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -33,18 +33,17 @@ end == Rails configuration tip -If you are using Rails 6.1 or newer, add the following `config.generators.after_generate` setting to -your config/application.rb to apply RuboCop autocorrection to code generated by `bin/rails g`. +In Rails 6.1+, add the following `config.generators.after_generate` setting to +your `config/environments/development.rb` to apply RuboCop autocorrection to code generated by `bin/rails g`. [source,ruby] ---- -module YourCoolApp - class Application < Rails::Application - config.generators.after_generate do |files| - parsable_files = files.filter { |file| File.exist?(file) && file.end_with?('.rb') } - unless parsable_files.empty? - system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true) - end +# config/environments/development.rb +Rails.application.configure do + config.generators.after_generate do |files| + parsable_files = files.filter { |file| file.end_with?('.rb') } + unless parsable_files.empty? + system("bundle exec rubocop -A --fail-level=E #{parsable_files.shelljoin}", exception: true) end end end @@ -53,3 +52,18 @@ end It uses `rubocop -A` to apply `Style/FrozenStringLiteralComment` and other unsafe autocorrection cops. `rubocop -A` is unsafe autocorrection, but code generated by default is simple and less likely to be incompatible with `rubocop -A`. If you have problems you can replace it with `rubocop -a` instead. + +In Rails 7.2+, it is recommended to use `config.generators.apply_rubocop_autocorrect_after_generate!` instead of the above setting: + +[source,diff] +---- + # config/environments/development.rb + Rails.application.configure do + (snip) + # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. +- # config.generators.apply_rubocop_autocorrect_after_generate! ++ config.generators.apply_rubocop_autocorrect_after_generate! + end +---- + +You only need to uncomment. From f935a0b8a1ddbc8e651e689293609dce39ada5d3 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Wed, 18 Sep 2024 01:10:42 +0900 Subject: [PATCH 34/52] Suppress new RuboCop offenses Follow up https://github.com/rubocop/rubocop/pull/13242 This commit removes the following redundant `source_range` to suppress new RuboCop offenses: ```console $ bundle exec rake (snip) Offenses: lib/rubocop/cop/rails/redundant_foreign_key.rb:43:44: C: [Corrected] InternalAffairs/RedundantSourceRange: Remove the redundant source_range. add_offense(foreign_key_pair.source_range) do |corrector| ^^^^^^^^^^^^ lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb:81:34: C: [Corrected] InternalAffairs/RedundantSourceRange: Remove the redundant source_range. add_offense(receiver.source_range) do |corrector| ^^^^^^^^^^^^ lib/rubocop/cop/rails/reflection_class_name.rb:46:47: C: [Corrected] InternalAffairs/RedundantSourceRange: Remove the redundant source_range. add_offense(reflection_class_name.source_range) do |corrector| ^^^^^^^^^^^^ lib/rubocop/cop/rails/request_referer.rb:37:30: C: [Corrected] InternalAffairs/RedundantSourceRange: Remove the redundant source_range. add_offense(node.source_range) do |corrector| ^^^^^^^^^^^^ 296 files inspected, 4 offenses detected, 4 offenses corrected ``` --- lib/rubocop/cop/rails/redundant_foreign_key.rb | 2 +- lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb | 2 +- lib/rubocop/cop/rails/reflection_class_name.rb | 2 +- lib/rubocop/cop/rails/request_referer.rb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/rubocop/cop/rails/redundant_foreign_key.rb b/lib/rubocop/cop/rails/redundant_foreign_key.rb index 3026fca294..f1f1e336fb 100644 --- a/lib/rubocop/cop/rails/redundant_foreign_key.rb +++ b/lib/rubocop/cop/rails/redundant_foreign_key.rb @@ -40,7 +40,7 @@ class RedundantForeignKey < Base def on_send(node) association_with_foreign_key(node) do |type, name, options, foreign_key_pair, foreign_key| if redundant?(node, type, name, options, foreign_key) - add_offense(foreign_key_pair.source_range) do |corrector| + add_offense(foreign_key_pair) do |corrector| range = range_with_surrounding_space(foreign_key_pair.source_range, side: :left) range = range_with_surrounding_comma(range, :left) diff --git a/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb b/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb index 62d52786cf..05df3c8675 100644 --- a/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb +++ b/lib/rubocop/cop/rails/redundant_receiver_in_with_options.rb @@ -78,7 +78,7 @@ def on_block(node) send_nodes.each do |send_node| receiver = send_node.receiver - add_offense(receiver.source_range) do |corrector| + add_offense(receiver) do |corrector| autocorrect(corrector, send_node, node) end end diff --git a/lib/rubocop/cop/rails/reflection_class_name.rb b/lib/rubocop/cop/rails/reflection_class_name.rb index d0afa1acb6..8393956b83 100644 --- a/lib/rubocop/cop/rails/reflection_class_name.rb +++ b/lib/rubocop/cop/rails/reflection_class_name.rb @@ -43,7 +43,7 @@ def on_send(node) return if reflection_class_name.value.send_type? && reflection_class_name.value.receiver.nil? return if reflection_class_name.value.lvar_type? && str_assigned?(reflection_class_name) - add_offense(reflection_class_name.source_range) do |corrector| + add_offense(reflection_class_name) do |corrector| autocorrect(corrector, reflection_class_name) end end diff --git a/lib/rubocop/cop/rails/request_referer.rb b/lib/rubocop/cop/rails/request_referer.rb index 38a68d8099..980064b884 100644 --- a/lib/rubocop/cop/rails/request_referer.rb +++ b/lib/rubocop/cop/rails/request_referer.rb @@ -34,7 +34,7 @@ def on_send(node) referer?(node) do return unless node.method?(wrong_method_name) - add_offense(node.source_range) do |corrector| + add_offense(node) do |corrector| corrector.replace(node, "request.#{style}") end end From a17163895bc137e8625bc3056e3d9925e349ba5e Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 19 Sep 2024 09:58:31 +0200 Subject: [PATCH 35/52] [Fix #727] Disable `Rails/TransactionExitStatement` on Rails >= 7.2 On Rails 7.2, the behavior is exactly like it was in earlier Rails. On Rails 7.1, it is controlled by `active_record.commit_transaction_on_non_local_return`. https://github.com/rails/rails/commit/eccc6061f4f3abdfdeb9a363987a898418d9498f https://github.com/rails/rails/pull/48600 --- changelog/change_disable_transaction_exit_rails_7.2.md | 1 + lib/rubocop/cop/rails/transaction_exit_statement.rb | 5 +++++ .../cop/rails/transaction_exit_statement_spec.rb | 10 ++++++++++ spec/support/shared_contexts.rb | 4 ++++ 4 files changed, 20 insertions(+) create mode 100644 changelog/change_disable_transaction_exit_rails_7.2.md diff --git a/changelog/change_disable_transaction_exit_rails_7.2.md b/changelog/change_disable_transaction_exit_rails_7.2.md new file mode 100644 index 0000000000..c199c04e3f --- /dev/null +++ b/changelog/change_disable_transaction_exit_rails_7.2.md @@ -0,0 +1 @@ +* [#727](https://github.com/rubocop/rubocop-rails/issues/727): Disable `Rails/TransactionExitStatement` on Rails >= 7.2. ([@earlopain][]) diff --git a/lib/rubocop/cop/rails/transaction_exit_statement.rb b/lib/rubocop/cop/rails/transaction_exit_statement.rb index dc22555cfb..508e06697e 100644 --- a/lib/rubocop/cop/rails/transaction_exit_statement.rb +++ b/lib/rubocop/cop/rails/transaction_exit_statement.rb @@ -15,6 +15,10 @@ module Rails # # If you are defining custom transaction methods, you can configure it with `TransactionMethods`. # + # NOTE: This cop is disabled on Rails >= 7.2 because transactions were restored + # to their historical behavior. In Rails 7.1, the behavior is controlled with + # the config `active_record.commit_transaction_on_non_local_return`. + # # @example # # bad # ApplicationRecord.transaction do @@ -76,6 +80,7 @@ class TransactionExitStatement < Base PATTERN def on_send(node) + return if target_rails_version >= 7.2 return unless in_transaction_block?(node) exit_statements(node.parent.body).each do |statement_node| diff --git a/spec/rubocop/cop/rails/transaction_exit_statement_spec.rb b/spec/rubocop/cop/rails/transaction_exit_statement_spec.rb index 2db1d3ea8a..8cf2b76317 100644 --- a/spec/rubocop/cop/rails/transaction_exit_statement_spec.rb +++ b/spec/rubocop/cop/rails/transaction_exit_statement_spec.rb @@ -114,4 +114,14 @@ it_behaves_like 'flags transaction exit statements', :writable_transaction end + + context 'Rails >= 7.2', :rails72 do + it 'registers no offense' do + expect_no_offenses(<<~RUBY) + ApplicationRecord.transaction do + return if user.active? + end + RUBY + end + end end diff --git a/spec/support/shared_contexts.rb b/spec/support/shared_contexts.rb index bd659b6a0b..c9df13973b 100644 --- a/spec/support/shared_contexts.rb +++ b/spec/support/shared_contexts.rb @@ -31,3 +31,7 @@ RSpec.shared_context 'with Rails 7.1', :rails71 do let(:rails_version) { 7.1 } end + +RSpec.shared_context 'with Rails 7.2', :rails72 do + let(:rails_version) { 7.2 } +end From 34ca70318c122ecf169fb74d8d8f805f637f4af7 Mon Sep 17 00:00:00 2001 From: Earlopain <14981592+Earlopain@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:15:13 +0200 Subject: [PATCH 36/52] [Fix #1203] Insert the target rails version into docs --- lib/rubocop/cop/mixin/target_rails_version.rb | 8 +++----- tasks/cops_documentation.rake | 9 ++++++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/rubocop/cop/mixin/target_rails_version.rb b/lib/rubocop/cop/mixin/target_rails_version.rb index 4dca5074ae..a6eb55052c 100644 --- a/lib/rubocop/cop/mixin/target_rails_version.rb +++ b/lib/rubocop/cop/mixin/target_rails_version.rb @@ -7,6 +7,9 @@ module TargetRailsVersion # Informs the base RuboCop gem that it the Rails version is checked via `requires_gem` API, # without needing to call this `#support_target_rails_version` method. USES_REQUIRES_GEM_API = true + # Look for `railties` instead of `rails`, to support apps that only use a subset of `rails` + # See https://github.com/rubocop/rubocop/pull/11289 + TARGET_GEM_NAME = 'railties' # :nodoc: def minimum_target_rails_version(version) if respond_to?(:requires_gem) @@ -33,11 +36,6 @@ def support_target_rails_version?(version) @minimum_target_rails_version <= version end end - - # Look for `railties` instead of `rails`, to support apps that only use a subset of `rails` - # See https://github.com/rubocop/rubocop/pull/11289 - TARGET_GEM_NAME = 'railties' - private_constant :TARGET_GEM_NAME end end end diff --git a/tasks/cops_documentation.rake b/tasks/cops_documentation.rake index 7d9275354e..3804b175ee 100644 --- a/tasks/cops_documentation.rake +++ b/tasks/cops_documentation.rake @@ -12,12 +12,19 @@ end task update_cops_documentation: :yard_for_generate_documentation do deps = ['Rails'] + # NOTE: Insert minimum_target_rails_version after ruby version + required_rails_version = lambda do |data| + return '' unless (version = data.cop.gem_requirements[RuboCop::Cop::TargetRailsVersion::TARGET_GEM_NAME]) + + "NOTE: Required Rails version: #{version.requirements[0][1]}\n\n" + end + extra_info = { required_ruby_version: required_rails_version } # NOTE: Update `<>` version for docs/modules/ROOT/pages/cops_rails.adoc # when running release tasks. RuboCop::Rails::Inject.defaults! - CopsDocumentationGenerator.new(departments: deps).call + CopsDocumentationGenerator.new(departments: deps, extra_info: extra_info).call end desc 'Syntax check for the documentation comments' From a451135c12b118ae88bfe6b56adef14714190d41 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 21 Sep 2024 12:48:36 +0900 Subject: [PATCH 37/52] Update Changelog --- CHANGELOG.md | 10 ++++++++++ .../change_support_filter_in_rails_compact_blank.md | 1 - changelog/fix_false_positives_for_rails_enum_syntax.md | 1 - changelog/fix_revert_flash_before_render.md | 1 - changelog/fix_wrong_autocorrect_for_rails_file_path.md | 1 - 5 files changed, 10 insertions(+), 4 deletions(-) delete mode 100644 changelog/change_support_filter_in_rails_compact_blank.md delete mode 100644 changelog/fix_false_positives_for_rails_enum_syntax.md delete mode 100644 changelog/fix_revert_flash_before_render.md delete mode 100644 changelog/fix_wrong_autocorrect_for_rails_file_path.md diff --git a/CHANGELOG.md b/CHANGELOG.md index ae1c5d800e..f995c19ac6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,16 @@ ## master (unreleased) +### Bug fixes + +* [#1362](https://github.com/rubocop/rubocop-rails/issues/1362): Fix false positives for `Rails/EnumSyntax` when using Ruby 2.7. ([@koic][]) +* [#1269](https://github.com/rubocop/rubocop-rails/issues/1269): Fix false positives for `Rails/ActionControllerFlashBeforeRender` in combination with implicit returns. ([@earlopain][]) +* [#1326](https://github.com/rubocop/rubocop-rails/pull/1326): Fix wrong autocorrect for `Rails/FilePath` when passing an array to `File.join`. ([@earlopain][]) + +### Changes + +* [#1359](https://github.com/rubocop/rubocop-rails/pull/1359): Support `filter` in `Rails/CompactBlank`. ([@masato-bkn][]) + ## 2.26.1 (2024-09-07) ### Bug fixes diff --git a/changelog/change_support_filter_in_rails_compact_blank.md b/changelog/change_support_filter_in_rails_compact_blank.md deleted file mode 100644 index a439c69a02..0000000000 --- a/changelog/change_support_filter_in_rails_compact_blank.md +++ /dev/null @@ -1 +0,0 @@ -* [#1359](https://github.com/rubocop/rubocop-rails/pull/1359): Support `filter` in `Rails/CompactBlank`. ([@masato-bkn][]) diff --git a/changelog/fix_false_positives_for_rails_enum_syntax.md b/changelog/fix_false_positives_for_rails_enum_syntax.md deleted file mode 100644 index 914d96ff49..0000000000 --- a/changelog/fix_false_positives_for_rails_enum_syntax.md +++ /dev/null @@ -1 +0,0 @@ -* [#1362](https://github.com/rubocop/rubocop-rails/issues/1362): Fix false positives for `Rails/EnumSyntax` when using Ruby 2.7. ([@koic][]) diff --git a/changelog/fix_revert_flash_before_render.md b/changelog/fix_revert_flash_before_render.md deleted file mode 100644 index 4a7cab0316..0000000000 --- a/changelog/fix_revert_flash_before_render.md +++ /dev/null @@ -1 +0,0 @@ -* [#1269](https://github.com/rubocop/rubocop-rails/issues/1269): Fix false positives for `Rails/ActionControllerFlashBeforeRender` in combination with implicit returns. ([@earlopain][]) diff --git a/changelog/fix_wrong_autocorrect_for_rails_file_path.md b/changelog/fix_wrong_autocorrect_for_rails_file_path.md deleted file mode 100644 index 10b2da3ae5..0000000000 --- a/changelog/fix_wrong_autocorrect_for_rails_file_path.md +++ /dev/null @@ -1 +0,0 @@ -* [#1326](https://github.com/rubocop/rubocop-rails/pull/1326): Fix wrong autocorrect for `Rails/FilePath` when passing an array to `File.join`. ([@earlopain][]) From f646d6e10aa5b6997b410bd59d1e1168646c3dce Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 21 Sep 2024 12:48:50 +0900 Subject: [PATCH 38/52] Cut 2.26.2 --- CHANGELOG.md | 2 ++ docs/antora.yml | 2 +- docs/modules/ROOT/pages/cops_rails.adoc | 4 ++++ lib/rubocop/rails/version.rb | 2 +- relnotes/v2.26.2.md | 13 +++++++++++++ 5 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 relnotes/v2.26.2.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f995c19ac6..13df636ab8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ## master (unreleased) +## 2.26.2 (2024-09-21) + ### Bug fixes * [#1362](https://github.com/rubocop/rubocop-rails/issues/1362): Fix false positives for `Rails/EnumSyntax` when using Ruby 2.7. ([@koic][]) diff --git a/docs/antora.yml b/docs/antora.yml index 9e0ff48acb..0e3477f379 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-rails title: RuboCop Rails # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: ~ +version: '2.26' nav: - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/pages/cops_rails.adoc b/docs/modules/ROOT/pages/cops_rails.adoc index ad89ca7c52..b9892b58eb 100644 --- a/docs/modules/ROOT/pages/cops_rails.adoc +++ b/docs/modules/ROOT/pages/cops_rails.adoc @@ -1109,6 +1109,8 @@ collection.reject(&:blank?) collection.reject { |_k, v| v.blank? } collection.select(&:present?) collection.select { |_k, v| v.present? } +collection.filter(&:present?) +collection.filter { |_k, v| v.present? } # good collection.compact_blank @@ -1925,6 +1927,8 @@ enum status: { active: 0, archived: 1 } == Rails/EnumSyntax +NOTE: Required Ruby version: 3.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed diff --git a/lib/rubocop/rails/version.rb b/lib/rubocop/rails/version.rb index c77f1c36d1..15095dece0 100644 --- a/lib/rubocop/rails/version.rb +++ b/lib/rubocop/rails/version.rb @@ -4,7 +4,7 @@ module RuboCop module Rails # This module holds the RuboCop Rails version information. module Version - STRING = '2.26.1' + STRING = '2.26.2' def self.document_version STRING.match('\d+\.\d+').to_s diff --git a/relnotes/v2.26.2.md b/relnotes/v2.26.2.md new file mode 100644 index 0000000000..93e5c7a53b --- /dev/null +++ b/relnotes/v2.26.2.md @@ -0,0 +1,13 @@ +### Bug fixes + +* [#1362](https://github.com/rubocop/rubocop-rails/issues/1362): Fix false positives for `Rails/EnumSyntax` when using Ruby 2.7. ([@koic][]) +* [#1269](https://github.com/rubocop/rubocop-rails/issues/1269): Fix false positives for `Rails/ActionControllerFlashBeforeRender` in combination with implicit returns. ([@earlopain][]) +* [#1326](https://github.com/rubocop/rubocop-rails/pull/1326): Fix wrong autocorrect for `Rails/FilePath` when passing an array to `File.join`. ([@earlopain][]) + +### Changes + +* [#1359](https://github.com/rubocop/rubocop-rails/pull/1359): Support `filter` in `Rails/CompactBlank`. ([@masato-bkn][]) + +[@koic]: https://github.com/koic +[@earlopain]: https://github.com/earlopain +[@masato-bkn]: https://github.com/masato-bkn From 122cde03a128710fafaec5ffe4ac763106f656e0 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 21 Sep 2024 12:51:27 +0900 Subject: [PATCH 39/52] Switch back docs version to master --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index 0e3477f379..9e0ff48acb 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-rails title: RuboCop Rails # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: '2.26' +version: ~ nav: - modules/ROOT/nav.adoc From 1a2c974f60c089948480e62ec93fdda662714800 Mon Sep 17 00:00:00 2001 From: masato-bkn <37011138+masato-bkn@users.noreply.github.com> Date: Sun, 22 Sep 2024 17:05:53 +0900 Subject: [PATCH 40/52] Fix test cases for `*` and `**` arguments in `Rails/SaveBang` --- spec/rubocop/cop/rails/save_bang_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/rubocop/cop/rails/save_bang_spec.rb b/spec/rubocop/cop/rails/save_bang_spec.rb index c036b194a6..383ba34570 100644 --- a/spec/rubocop/cop/rails/save_bang_spec.rb +++ b/spec/rubocop/cop/rails/save_bang_spec.rb @@ -47,12 +47,12 @@ RUBY else expect_offense(<<~RUBY, method: method) - object.#{method}(variable) + object.#{method}(*variable) ^{method} Use `#{method}!` instead of `#{method}` if the return value is not checked. RUBY expect_correction(<<~RUBY) - object.#{method}!(variable) + object.#{method}!(*variable) RUBY end end @@ -64,12 +64,12 @@ RUBY else expect_offense(<<~RUBY, method: method) - object.#{method}(variable) + object.#{method}(**variable) ^{method} Use `#{method}!` instead of `#{method}` if the return value is not checked. RUBY expect_correction(<<~RUBY) - object.#{method}!(variable) + object.#{method}!(**variable) RUBY end end From 84d4b258848f469d3c640b35e7abebb8bc57a0e7 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Sun, 22 Sep 2024 15:01:24 +0300 Subject: [PATCH 41/52] Change `Rails/SelectMap` to handle safe navigation operators --- ...lect_map_safe_navigation_handle_safe_navigation.md | 1 + lib/rubocop/cop/rails/select_map.rb | 3 ++- spec/rubocop/cop/rails/select_map_spec.rb | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 changelog/change_select_map_safe_navigation_handle_safe_navigation.md diff --git a/changelog/change_select_map_safe_navigation_handle_safe_navigation.md b/changelog/change_select_map_safe_navigation_handle_safe_navigation.md new file mode 100644 index 0000000000..e6a8cf2090 --- /dev/null +++ b/changelog/change_select_map_safe_navigation_handle_safe_navigation.md @@ -0,0 +1 @@ +* [#1195](https://github.com/rubocop/rubocop-rails/issues/1195): Change `Rails/SelectMap` to handle safe navigation operators. ([@fatkodima][]) diff --git a/lib/rubocop/cop/rails/select_map.rb b/lib/rubocop/cop/rails/select_map.rb index ede846d915..c988096df1 100644 --- a/lib/rubocop/cop/rails/select_map.rb +++ b/lib/rubocop/cop/rails/select_map.rb @@ -40,12 +40,13 @@ def on_send(node) autocorrect(corrector, select_node, node, preferred_method) end end + alias on_csend on_send private def find_select_node(node, column_name) node.descendants.detect do |select_candidate| - next if !select_candidate.send_type? || !select_candidate.method?(:select) + next if !select_candidate.call_type? || !select_candidate.method?(:select) match_column_name?(select_candidate, column_name) end diff --git a/spec/rubocop/cop/rails/select_map_spec.rb b/spec/rubocop/cop/rails/select_map_spec.rb index 767516e4d6..de609cb06c 100644 --- a/spec/rubocop/cop/rails/select_map_spec.rb +++ b/spec/rubocop/cop/rails/select_map_spec.rb @@ -56,6 +56,17 @@ RUBY end + it 'handles safe navigation chain' do + expect_offense(<<~RUBY) + relation&.select(:column_name)&.map(&:column_name) + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `pluck(:column_name)` instead of `select` with `map`. + RUBY + + expect_correction(<<~RUBY) + relation&.pluck(:column_name) + RUBY + end + it 'does not register an offense when using `select(:mismatch_column_name).map(&:column_name)`' do expect_no_offenses(<<~RUBY) Model.select(:mismatch_column_name).map(&:column_name) From f9272b31dfa076f8b930503ef7e7b34eb539e46f Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sun, 29 Sep 2024 01:12:50 +0900 Subject: [PATCH 42/52] Add `shared_context` for Rails 8.0 Rails 8.0.0.beta1 has been released: https://github.com/rails/rails/releases/tag/v8.0.0.beta1 --- spec/support/shared_contexts.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/support/shared_contexts.rb b/spec/support/shared_contexts.rb index c9df13973b..147f2f3a8a 100644 --- a/spec/support/shared_contexts.rb +++ b/spec/support/shared_contexts.rb @@ -35,3 +35,7 @@ RSpec.shared_context 'with Rails 7.2', :rails72 do let(:rails_version) { 7.2 } end + +RSpec.shared_context 'with Rails 8.0', :rails80 do + let(:rails_version) { 8.0 } +end From 986484ca2a5ba808648773615b9337cfd09dc0c6 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 5 Oct 2024 17:54:56 +0900 Subject: [PATCH 43/52] Use RuboCop RSpec 3.1 --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 6c697258a6..592d44402f 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,7 @@ gem 'rake' gem 'rspec' gem 'rubocop', github: 'rubocop/rubocop' gem 'rubocop-performance', '~> 1.21.0' -gem 'rubocop-rspec', '~> 3.0.0' +gem 'rubocop-rspec', '~> 3.1.0' gem 'simplecov' gem 'test-queue' gem 'yard', '~> 0.9' From 855e0b0fda313f4305e4927c542d6be4622fa6c8 Mon Sep 17 00:00:00 2001 From: fatkodima Date: Sun, 6 Oct 2024 00:00:43 +0300 Subject: [PATCH 44/52] Change `Rails/EnvLocal` to handle negated conditions --- ..._env_local_to_handle_negated_conditions.md | 1 + lib/rubocop/cop/rails/env_local.rb | 29 +++++++++++++++++-- spec/rubocop/cop/rails/env_local_spec.rb | 29 +++++++++++++++++++ 3 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 changelog/change_env_local_to_handle_negated_conditions.md diff --git a/changelog/change_env_local_to_handle_negated_conditions.md b/changelog/change_env_local_to_handle_negated_conditions.md new file mode 100644 index 0000000000..3d0482b15d --- /dev/null +++ b/changelog/change_env_local_to_handle_negated_conditions.md @@ -0,0 +1 @@ +* [#1374](https://github.com/rubocop/rubocop-rails/pull/1374): Change `Rails/EnvLocal` to handle negated conditions. ([@fatkodima][]) diff --git a/lib/rubocop/cop/rails/env_local.rb b/lib/rubocop/cop/rails/env_local.rb index b76a354647..8aea161c71 100644 --- a/lib/rubocop/cop/rails/env_local.rb +++ b/lib/rubocop/cop/rails/env_local.rb @@ -19,20 +19,33 @@ class EnvLocal < Base extend TargetRailsVersion MSG = 'Use `Rails.env.local?` instead.' + MSG_NEGATED = 'Use `!Rails.env.local?` instead.' LOCAL_ENVIRONMENTS = %i[development? test?].to_set.freeze minimum_target_rails_version 7.1 - # @!method rails_env_local_candidate?(node) - def_node_matcher :rails_env_local_candidate?, <<~PATTERN + # @!method rails_env_local_or?(node) + def_node_matcher :rails_env_local_or?, <<~PATTERN (or (send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS) (send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS) ) PATTERN + # @!method rails_env_local_and?(node) + def_node_matcher :rails_env_local_and?, <<~PATTERN + (and + (send + (send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS) + :!) + (send + (send (send (const {cbase nil? } :Rails) :env) $%LOCAL_ENVIRONMENTS) + :!) + ) + PATTERN + def on_or(node) - rails_env_local_candidate?(node) do |*environments| + rails_env_local_or?(node) do |*environments| next unless environments.to_set == LOCAL_ENVIRONMENTS add_offense(node) do |corrector| @@ -40,6 +53,16 @@ def on_or(node) end end end + + def on_and(node) + rails_env_local_and?(node) do |*environments| + next unless environments.to_set == LOCAL_ENVIRONMENTS + + add_offense(node, message: MSG_NEGATED) do |corrector| + corrector.replace(node, '!Rails.env.local?') + end + end + end end end end diff --git a/spec/rubocop/cop/rails/env_local_spec.rb b/spec/rubocop/cop/rails/env_local_spec.rb index 62cef8b1f3..aba7485130 100644 --- a/spec/rubocop/cop/rails/env_local_spec.rb +++ b/spec/rubocop/cop/rails/env_local_spec.rb @@ -10,6 +10,14 @@ RUBY end + it 'registers no offenses for non-local `!Rails.env._? && !Rails.env._?`' do + expect_no_offenses(<<~RUBY) + !Rails.env.development? && Rails.env.production? + !Rails.env.test? && Rails.env.production? + !Rails.env.production? && Rails.env.other? + RUBY + end + it 'registers no offenses for single `Rails.env._?`' do expect_no_offenses(<<~RUBY) Rails.env.development? @@ -35,6 +43,20 @@ RUBY end + it 'registers an offense for `!Rails.env.development? && !Rails.env.test?`' do + expect_offense(<<~RUBY) + !Rails.env.development? && !Rails.env.test? + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `!Rails.env.local?` instead. + !Rails.env.test? && !Rails.env.development? + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Use `!Rails.env.local?` instead. + RUBY + + expect_correction(<<~RUBY) + !Rails.env.local? + !Rails.env.local? + RUBY + end + it 'registers no offenses for `Rails.env.local?`' do expect_no_offenses(<<~RUBY) Rails.env.local? @@ -52,6 +74,13 @@ RUBY end + it 'registers no offenses for `!Rails.env.development? && !Rails.env.test?`' do + expect_no_offenses(<<~RUBY) + !Rails.env.development? && !Rails.env.test? + !Rails.env.test? && !Rails.env.development? + RUBY + end + it 'registers no offenses for `Rails.env.local?`' do expect_no_offenses(<<~RUBY) Rails.env.local? From 2e619f3783213ace534b3d1f1a95a16d7c3ad954 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Wed, 9 Oct 2024 01:41:38 +0900 Subject: [PATCH 45/52] [Docs] Add `TargetRailsVersion` to config documentation --- README.md | 20 ++++++++++++++++++++ config/default.yml | 10 +++++----- docs/modules/ROOT/pages/usage.adoc | 21 +++++++++++++++++++++ 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b8d01488ca..72a264c7b3 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,26 @@ RuboCop::RakeTask.new do |task| end ``` +## RuboCop Rails configuration + +The following settings specific to RuboCop Rails can be configured in `.rubocop.yml`. + +### `AllCops: TargetRailsVersion` + +What version of Rails is the inspected code using? If a value is specified +for `TargetRailsVersion` then it is used. Acceptable values are specified +as a float (e.g., 7.2); the patch version of Rails should not be included. + +```yaml +AllCops: + TargetRailsVersion: 7.2 +``` + +If `TargetRailsVersion` is not set, RuboCop will parse the Gemfile.lock or +gems.locked file to find the version of Rails that has been bound to the +application. If neither of those files exist, RuboCop will use Rails 5.0 +as the default. + ## Rails configuration tip In Rails 6.1+, add the following `config.generators.after_generate` setting to diff --git a/config/default.yml b/config/default.yml index b59db897c5..0e7d183460 100644 --- a/config/default.yml +++ b/config/default.yml @@ -17,12 +17,12 @@ AllCops: # Enable checking Active Support extensions. # See: https://docs.rubocop.org/rubocop/configuration.html#enable-checking-active-support-extensions ActiveSupportExtensionsEnabled: true - # What version of Rails is the inspected code using? If a value is specified - # for TargetRailsVersion then it is used. Acceptable values are specified - # as a float (i.e. 5.1); the patch version of Rails should not be included. - # If TargetRailsVersion is not set, RuboCop will parse the Gemfile.lock or + # What version of Rails is the inspected code using? If a value is specified + # for `TargetRailsVersion` then it is used. Acceptable values are specified + # as a float (e.g., 7.2); the patch version of Rails should not be included. + # If `TargetRailsVersion` is not set, RuboCop will parse the Gemfile.lock or # gems.locked file to find the version of Rails that has been bound to the - # application. If neither of those files exist, RuboCop will use Rails 5.0 + # application. If neither of those files exist, RuboCop will use Rails 5.0 # as the default. TargetRailsVersion: ~ diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc index 97cfe75cec..c4aa17b024 100644 --- a/docs/modules/ROOT/pages/usage.adoc +++ b/docs/modules/ROOT/pages/usage.adoc @@ -31,6 +31,27 @@ RuboCop::RakeTask.new do |task| end ---- +== RuboCop Rails configuration + +The following settings specific to RuboCop Rails can be configured in `.rubocop.yml`. + +=== `AllCops: TargetRailsVersion` + +What version of Rails is the inspected code using? If a value is specified +for `TargetRailsVersion` then it is used. Acceptable values are specified +as a float (e.g., 7.2); the patch version of Rails should not be included. + +[source,yaml] +---- +AllCops: + TargetRailsVersion: 7.2 +---- + +If `TargetRailsVersion` is not set, RuboCop will parse the Gemfile.lock or +gems.locked file to find the version of Rails that has been bound to the +application. If neither of those files exist, RuboCop will use Rails 5.0 +as the default. + == Rails configuration tip In Rails 6.1+, add the following `config.generators.after_generate` setting to From 209cc093632309b6075ab946dd443ef97730004a Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sun, 13 Oct 2024 18:37:17 +0900 Subject: [PATCH 46/52] Use RuboCop Performance 1.22 --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 592d44402f..923057b6d4 100644 --- a/Gemfile +++ b/Gemfile @@ -11,7 +11,7 @@ gem 'prism' gem 'rake' gem 'rspec' gem 'rubocop', github: 'rubocop/rubocop' -gem 'rubocop-performance', '~> 1.21.0' +gem 'rubocop-performance', '~> 1.22.0' gem 'rubocop-rspec', '~> 3.1.0' gem 'simplecov' gem 'test-queue' From 5bc926f1a04548cc27ac56b2ec070f53f2b86652 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Armand=20M=C3=A9grot?= Date: Thu, 19 Sep 2024 10:07:34 +0200 Subject: [PATCH 47/52] Fix `Rails/TimeZone` should not report offense on `String#to_time` with timezone specifier As `Time.parse("2012-03-02T16:05:37Z")` is allowed, `"2012-03-02T16:05:37Z".to_time` should also be allowed. --- .../fix_rails_time_zone_string_to_time_with_specifier.md | 1 + lib/rubocop/cop/rails/time_zone.rb | 3 +++ spec/rubocop/cop/rails/time_zone_spec.rb | 6 ++++++ 3 files changed, 10 insertions(+) create mode 100644 changelog/fix_rails_time_zone_string_to_time_with_specifier.md diff --git a/changelog/fix_rails_time_zone_string_to_time_with_specifier.md b/changelog/fix_rails_time_zone_string_to_time_with_specifier.md new file mode 100644 index 0000000000..05d07e76fb --- /dev/null +++ b/changelog/fix_rails_time_zone_string_to_time_with_specifier.md @@ -0,0 +1 @@ +* [#1367](https://github.com/rubocop/rubocop-rails/pull/1367): Fix `Rails/TimeZone` should not report offense on `String#to_time` with timezone specifier. ([@armandmgt][]) diff --git a/lib/rubocop/cop/rails/time_zone.rb b/lib/rubocop/cop/rails/time_zone.rb index f8249609f3..a9471de299 100644 --- a/lib/rubocop/cop/rails/time_zone.rb +++ b/lib/rubocop/cop/rails/time_zone.rb @@ -28,6 +28,8 @@ module Rails # Time.zone.now # Time.zone.parse('2015-03-02T19:05:37') # Time.zone.parse('2015-03-02T19:05:37Z') # Respect ISO 8601 format with timezone specifier. + # Time.parse('2015-03-02T19:05:37Z') # Also respects ISO 8601 + # '2015-03-02T19:05:37Z'.to_time # Also respects ISO 8601 # # @example EnforcedStyle: flexible (default) # # `flexible` allows usage of `in_time_zone` instead of `zone`. @@ -67,6 +69,7 @@ def on_const(node) def on_send(node) return if !node.receiver&.str_type? || !node.method?(:to_time) + return if attach_timezone_specifier?(node.receiver) add_offense(node.loc.selector, message: MSG_STRING_TO_TIME) do |corrector| corrector.replace(node, "Time.zone.parse(#{node.receiver.source})") unless node.csend_type? diff --git a/spec/rubocop/cop/rails/time_zone_spec.rb b/spec/rubocop/cop/rails/time_zone_spec.rb index 4d8fce6250..4aacc1462d 100644 --- a/spec/rubocop/cop/rails/time_zone_spec.rb +++ b/spec/rubocop/cop/rails/time_zone_spec.rb @@ -144,6 +144,12 @@ expect_no_corrections end + it 'does not register an offense for `to_time` when attaching timezone specifier `Z`' do + expect_no_offenses(<<~RUBY) + "2012-03-02T16:05:37Z".to_time + RUBY + end + it 'does not register an offense for `to_time` without receiver' do expect_no_offenses(<<~RUBY) to_time From a413fe6fd1e4f0f2b053f4549a152615004974c2 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Mon, 14 Oct 2024 17:06:02 +0900 Subject: [PATCH 48/52] Suppress new RuboCop offenses This commit suppresses the following new RuboCop offenses: ```console Offenses: lib/rubocop/cop/rails/squished_sql_heredocs.rb:71:49: W: [Correctable] Lint/SafeNavigationConsistency: Use . instead of unnecessary &.. node.parent&.send_type? && node.parent&.method?(:squish) ^^ lib/rubocop/cop/rails/where_range.rb:92:43: W: [Correctable] Lint/SafeNavigationConsistency: Use . instead of unnecessary &.. receiver&.send_type? && receiver&.method?(:where) ^^ 296 files inspected, 2 offenses detected, 2 offenses autocorrectable ``` --- lib/rubocop/cop/rails/squished_sql_heredocs.rb | 2 +- lib/rubocop/cop/rails/where_range.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rubocop/cop/rails/squished_sql_heredocs.rb b/lib/rubocop/cop/rails/squished_sql_heredocs.rb index 887cb0492d..24fe9cab43 100644 --- a/lib/rubocop/cop/rails/squished_sql_heredocs.rb +++ b/lib/rubocop/cop/rails/squished_sql_heredocs.rb @@ -68,7 +68,7 @@ def sql_heredoc?(node) end def using_squish?(node) - node.parent&.send_type? && node.parent&.method?(:squish) + node.parent&.send_type? && node.parent.method?(:squish) end def singleline_comments_present?(node) diff --git a/lib/rubocop/cop/rails/where_range.rb b/lib/rubocop/cop/rails/where_range.rb index 1c8fd4a0fb..a42a2302a6 100644 --- a/lib/rubocop/cop/rails/where_range.rb +++ b/lib/rubocop/cop/rails/where_range.rb @@ -89,7 +89,7 @@ def on_send(node) def where_not?(node) receiver = node.receiver - receiver&.send_type? && receiver&.method?(:where) + receiver&.send_type? && receiver.method?(:where) end # rubocop:disable Metrics From 94a8370ff480c712214f396ac5eb988d31d0e072 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Fri, 18 Oct 2024 12:07:11 +0900 Subject: [PATCH 49/52] [Fix #1377] Fix an error for `Rails/EnumSyntax` Fixes #1377 This PR fixes an error for `Rails/EnumSyntax` when positional arguments are used and options are not passed as keyword arguments. --- changelog/fix_an_error_for_rails_enum_syntax.md | 1 + lib/rubocop/cop/rails/enum_syntax.rb | 2 ++ spec/rubocop/cop/rails/enum_syntax_spec.rb | 8 ++++++++ 3 files changed, 11 insertions(+) create mode 100644 changelog/fix_an_error_for_rails_enum_syntax.md diff --git a/changelog/fix_an_error_for_rails_enum_syntax.md b/changelog/fix_an_error_for_rails_enum_syntax.md new file mode 100644 index 0000000000..0ad353b258 --- /dev/null +++ b/changelog/fix_an_error_for_rails_enum_syntax.md @@ -0,0 +1 @@ +* [#1377](https://github.com/rubocop/rubocop-rails/issues/1377): Fix an error for `Rails/EnumSyntax` when positional arguments are used and options are not passed as keyword arguments. ([@koic][]) diff --git a/lib/rubocop/cop/rails/enum_syntax.rb b/lib/rubocop/cop/rails/enum_syntax.rb index 5b3d683916..6f603a3056 100644 --- a/lib/rubocop/cop/rails/enum_syntax.rb +++ b/lib/rubocop/cop/rails/enum_syntax.rb @@ -106,6 +106,8 @@ def enum_name(elem) end def option_key?(pair) + return false unless pair.respond_to?(:key) + UNDERSCORED_OPTION_NAMES.include?(pair.key.source) end diff --git a/spec/rubocop/cop/rails/enum_syntax_spec.rb b/spec/rubocop/cop/rails/enum_syntax_spec.rb index b5f20a2436..c51bd496f2 100644 --- a/spec/rubocop/cop/rails/enum_syntax_spec.rb +++ b/spec/rubocop/cop/rails/enum_syntax_spec.rb @@ -146,6 +146,14 @@ expect_no_offenses('enum') end end + + context 'when positional arguments are used and options are not passed as keyword arguments' do + it 'does not register an offense' do + expect_no_offenses(<<~RUBY) + enum :status, { active: 0, archived: 1 }, prefix + RUBY + end + end end context 'Rails >= 7.0 and Ruby <= 2.7', :rails70, :ruby27, unsupported_on: :prism do From f052a898a509f5dc5b85d957ae02a6aebc87624c Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 26 Oct 2024 17:12:24 +0900 Subject: [PATCH 50/52] Update Changelog --- CHANGELOG.md | 12 ++++++++++++ .../change_disable_transaction_exit_rails_7.2.md | 1 - .../change_env_local_to_handle_negated_conditions.md | 1 - ...ect_map_safe_navigation_handle_safe_navigation.md | 1 - changelog/fix_an_error_for_rails_enum_syntax.md | 1 - ..._rails_time_zone_string_to_time_with_specifier.md | 1 - 6 files changed, 12 insertions(+), 5 deletions(-) delete mode 100644 changelog/change_disable_transaction_exit_rails_7.2.md delete mode 100644 changelog/change_env_local_to_handle_negated_conditions.md delete mode 100644 changelog/change_select_map_safe_navigation_handle_safe_navigation.md delete mode 100644 changelog/fix_an_error_for_rails_enum_syntax.md delete mode 100644 changelog/fix_rails_time_zone_string_to_time_with_specifier.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 13df636ab8..176f115ddf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,17 @@ ## master (unreleased) +### Bug fixes + +* [#1377](https://github.com/rubocop/rubocop-rails/issues/1377): Fix an error for `Rails/EnumSyntax` when positional arguments are used and options are not passed as keyword arguments. ([@koic][]) +* [#1367](https://github.com/rubocop/rubocop-rails/pull/1367): Fix `Rails/TimeZone` should not report offense on `String#to_time` with timezone specifier. ([@armandmgt][]) + +### Changes + +* [#727](https://github.com/rubocop/rubocop-rails/issues/727): Disable `Rails/TransactionExitStatement` on Rails >= 7.2. ([@earlopain][]) +* [#1374](https://github.com/rubocop/rubocop-rails/pull/1374): Change `Rails/EnvLocal` to handle negated conditions. ([@fatkodima][]) +* [#1195](https://github.com/rubocop/rubocop-rails/issues/1195): Change `Rails/SelectMap` to handle safe navigation operators. ([@fatkodima][]) + ## 2.26.2 (2024-09-21) ### Bug fixes @@ -1152,3 +1163,4 @@ [@fwolfst]: https://github.com/fwolfst [@maxprokopiev]: https://github.com/maxprokopiev [@ytjmt]: https://github.com/ytjmt +[@armandmgt]: https://github.com/armandmgt diff --git a/changelog/change_disable_transaction_exit_rails_7.2.md b/changelog/change_disable_transaction_exit_rails_7.2.md deleted file mode 100644 index c199c04e3f..0000000000 --- a/changelog/change_disable_transaction_exit_rails_7.2.md +++ /dev/null @@ -1 +0,0 @@ -* [#727](https://github.com/rubocop/rubocop-rails/issues/727): Disable `Rails/TransactionExitStatement` on Rails >= 7.2. ([@earlopain][]) diff --git a/changelog/change_env_local_to_handle_negated_conditions.md b/changelog/change_env_local_to_handle_negated_conditions.md deleted file mode 100644 index 3d0482b15d..0000000000 --- a/changelog/change_env_local_to_handle_negated_conditions.md +++ /dev/null @@ -1 +0,0 @@ -* [#1374](https://github.com/rubocop/rubocop-rails/pull/1374): Change `Rails/EnvLocal` to handle negated conditions. ([@fatkodima][]) diff --git a/changelog/change_select_map_safe_navigation_handle_safe_navigation.md b/changelog/change_select_map_safe_navigation_handle_safe_navigation.md deleted file mode 100644 index e6a8cf2090..0000000000 --- a/changelog/change_select_map_safe_navigation_handle_safe_navigation.md +++ /dev/null @@ -1 +0,0 @@ -* [#1195](https://github.com/rubocop/rubocop-rails/issues/1195): Change `Rails/SelectMap` to handle safe navigation operators. ([@fatkodima][]) diff --git a/changelog/fix_an_error_for_rails_enum_syntax.md b/changelog/fix_an_error_for_rails_enum_syntax.md deleted file mode 100644 index 0ad353b258..0000000000 --- a/changelog/fix_an_error_for_rails_enum_syntax.md +++ /dev/null @@ -1 +0,0 @@ -* [#1377](https://github.com/rubocop/rubocop-rails/issues/1377): Fix an error for `Rails/EnumSyntax` when positional arguments are used and options are not passed as keyword arguments. ([@koic][]) diff --git a/changelog/fix_rails_time_zone_string_to_time_with_specifier.md b/changelog/fix_rails_time_zone_string_to_time_with_specifier.md deleted file mode 100644 index 05d07e76fb..0000000000 --- a/changelog/fix_rails_time_zone_string_to_time_with_specifier.md +++ /dev/null @@ -1 +0,0 @@ -* [#1367](https://github.com/rubocop/rubocop-rails/pull/1367): Fix `Rails/TimeZone` should not report offense on `String#to_time` with timezone specifier. ([@armandmgt][]) From 9165c107995bd519fd67276a164e239d65912c2c Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 26 Oct 2024 17:12:46 +0900 Subject: [PATCH 51/52] Cut 2.27.0 --- CHANGELOG.md | 2 + docs/antora.yml | 2 +- docs/modules/ROOT/pages/cops_rails.adoc | 548 ++++++++++++++++++++++++ lib/rubocop/rails/version.rb | 2 +- relnotes/v2.27.0.md | 15 + 5 files changed, 567 insertions(+), 2 deletions(-) create mode 100644 relnotes/v2.27.0.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 176f115ddf..fb96f43400 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,8 @@ ## master (unreleased) +## 2.27.0 (2024-10-26) + ### Bug fixes * [#1377](https://github.com/rubocop/rubocop-rails/issues/1377): Fix an error for `Rails/EnumSyntax` when positional arguments are used and options are not passed as keyword arguments. ([@koic][]) diff --git a/docs/antora.yml b/docs/antora.yml index 9e0ff48acb..f011548566 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-rails title: RuboCop Rails # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: ~ +version: '2.27' nav: - modules/ROOT/nav.adoc diff --git a/docs/modules/ROOT/pages/cops_rails.adoc b/docs/modules/ROOT/pages/cops_rails.adoc index b9892b58eb..af8158a478 100644 --- a/docs/modules/ROOT/pages/cops_rails.adoc +++ b/docs/modules/ROOT/pages/cops_rails.adoc @@ -6,6 +6,7 @@ = Rails +[#railsactioncontrollerflashbeforerender] == Rails/ActionControllerFlashBeforeRender |=== @@ -21,11 +22,13 @@ Using `flash` assignment before `render` in Rails controllers will persist the message for too long. Check https://guides.rubyonrails.org/action_controller_overview.html#flash-now +[#safety-railsactioncontrollerflashbeforerender] === Safety This cop's autocorrection is unsafe because it replaces `flash` by `flash.now`. Even though it is usually a mistake, it might be used intentionally. +[#examples-railsactioncontrollerflashbeforerender] === Examples [source,ruby] @@ -47,8 +50,11 @@ class HomeController < ApplicationController end ---- +[#railsactioncontrollertestcase] == Rails/ActionControllerTestCase +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -63,11 +69,13 @@ Using `ActionController::TestCase` is discouraged and should be replaced by `ActionDispatch::IntegrationTest`. Controller tests are too close to the internals of a controller whereas integration tests mimic the browser/user. +[#safety-railsactioncontrollertestcase] === Safety This cop's autocorrection is unsafe because the API of each test case class is different. Make sure to update each test of your controller test cases after changing the superclass. +[#examples-railsactioncontrollertestcase] === Examples [source,ruby] @@ -81,6 +89,7 @@ class MyControllerTest < ActionDispatch::IntegrationTest end ---- +[#configurable-attributes-railsactioncontrollertestcase] === Configurable attributes |=== @@ -91,11 +100,13 @@ end | Array |=== +[#references-railsactioncontrollertestcase] === References * https://rails.rubystyle.guide/#integration-testing * https://api.rubyonrails.org/classes/ActionController/TestCase.html +[#railsactionfilter] == Rails/ActionFilter |=== @@ -116,8 +127,10 @@ something_filter methods or the newer something_action methods. IMPORTANT: This cop is deprecated. Because the `*_filter` methods were removed in Rails 4.2, and that Rails version is no longer supported by RuboCop Rails. This cop will be removed in RuboCop Rails 3.0. +[#examples-railsactionfilter] === Examples +[#enforcedstyle_-action-_default_-railsactionfilter] ==== EnforcedStyle: action (default) [source,ruby] @@ -133,6 +146,7 @@ append_around_action :do_stuff skip_after_action :do_stuff ---- +[#enforcedstyle_-filter-railsactionfilter] ==== EnforcedStyle: filter [source,ruby] @@ -148,6 +162,7 @@ append_around_filter :do_stuff skip_after_filter :do_stuff ---- +[#configurable-attributes-railsactionfilter] === Configurable attributes |=== @@ -162,6 +177,7 @@ skip_after_filter :do_stuff | Array |=== +[#railsactionorder] == Rails/ActionOrder |=== @@ -193,6 +209,7 @@ defined before actions not specified. - destroy ---- +[#examples-railsactionorder] === Examples [source,ruby] @@ -208,6 +225,7 @@ def show; end def destroy; end ---- +[#configurable-attributes-railsactionorder] === Configurable attributes |=== @@ -222,6 +240,7 @@ def destroy; end | Array |=== +[#railsactiverecordaliases] == Rails/ActiveRecordAliases |=== @@ -237,11 +256,13 @@ def destroy; end Checks that ActiveRecord aliases are not used. The direct method names are more clear and easier to read. +[#safety-railsactiverecordaliases] === Safety This cop is unsafe because custom `update_attributes` method call was changed to `update` but the method name remained same in the method definition. +[#examples-railsactiverecordaliases] === Examples [source,ruby] @@ -253,6 +274,7 @@ book.update_attributes!(author: 'Alice') book.update!(author: 'Alice') ---- +[#railsactiverecordcallbacksorder] == Rails/ActiveRecordCallbacksOrder |=== @@ -268,6 +290,7 @@ book.update!(author: 'Alice') Checks that Active Record callbacks are declared in the order in which they will be executed. +[#examples-railsactiverecordcallbacksorder] === Examples [source,ruby] @@ -285,6 +308,7 @@ class Person < ApplicationRecord end ---- +[#configurable-attributes-railsactiverecordcallbacksorder] === Configurable attributes |=== @@ -295,10 +319,12 @@ end | Array |=== +[#references-railsactiverecordcallbacksorder] === References * https://rails.rubystyle.guide/#callbacks-order +[#railsactiverecordoverride] == Rails/ActiveRecordOverride |=== @@ -314,6 +340,7 @@ end Checks for overriding built-in Active Record methods instead of using callbacks. +[#examples-railsactiverecordoverride] === Examples [source,ruby] @@ -336,6 +363,7 @@ class Book < ApplicationRecord end ---- +[#configurable-attributes-railsactiverecordoverride] === Configurable attributes |=== @@ -350,6 +378,7 @@ end | Array |=== +[#railsactivesupportaliases] == Rails/ActiveSupportAliases |=== @@ -365,6 +394,7 @@ end Checks that ActiveSupport aliases to core ruby methods are not used. +[#examples-railsactivesupportaliases] === Examples [source,ruby] @@ -382,6 +412,7 @@ are not used. [1, 2, 'a'].prepend('b') ---- +[#railsactivesupportonload] == Rails/ActiveSupportOnLoad |=== @@ -397,11 +428,13 @@ are not used. Checks for Rails framework classes that are patched directly instead of using Active Support load hooks. Direct patching forcibly loads the framework referenced, using hooks defers loading until it's actually needed. +[#safety-railsactivesupportonload] === Safety While using lazy load hooks is recommended, it changes the order in which is code is loaded and may reveal load order dependency bugs. +[#examples-railsactivesupportonload] === Examples [source,ruby] @@ -413,11 +446,13 @@ ActiveRecord::Base.include(MyClass) ActiveSupport.on_load(:active_record) { include MyClass } ---- +[#references-railsactivesupportonload] === References * https://api.rubyonrails.org/classes/ActiveSupport/LazyLoadHooks.html * https://guides.rubyonrails.org/engines.html#available-load-hooks +[#railsaddcolumnindex] == Rails/AddColumnIndex |=== @@ -435,6 +470,7 @@ key. `add_column` does not accept `index`, but also does not raise an error for extra keys, so it is possible to mistakenly add the key without realizing it will not actually add an index. +[#examples-railsaddcolumnindex] === Examples [source,ruby] @@ -447,6 +483,7 @@ add_column :table, :column, :integer add_index :table, :column ---- +[#configurable-attributes-railsaddcolumnindex] === Configurable attributes |=== @@ -457,6 +494,7 @@ add_index :table, :column | Array |=== +[#railsaftercommitoverride] == Rails/AfterCommitOverride |=== @@ -473,6 +511,7 @@ Enforces that there is only one call to `after_commit` (and its aliases - `after_create_commit`, `after_update_commit`, and `after_destroy_commit`) with the same callback name per model. +[#examples-railsaftercommitoverride] === Examples [source,ruby] @@ -501,6 +540,7 @@ after_create_commit :log_create_action after_update_commit :log_update_action ---- +[#railsapplicationcontroller] == Rails/ApplicationController |=== @@ -515,11 +555,13 @@ after_update_commit :log_update_action Checks that controllers subclass `ApplicationController`. +[#safety-railsapplicationcontroller] === Safety This cop's autocorrection is unsafe because it may let the logic from `ApplicationController` sneak into a controller that is not purposed to inherit logic common among other controllers. +[#examples-railsapplicationcontroller] === Examples [source,ruby] @@ -535,8 +577,11 @@ class MyController < ActionController::Base end ---- +[#railsapplicationjob] == Rails/ApplicationJob +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -549,11 +594,13 @@ end Checks that jobs subclass `ApplicationJob` with Rails 5.0. +[#safety-railsapplicationjob] === Safety This cop's autocorrection is unsafe because it may let the logic from `ApplicationJob` sneak into a job that is not purposed to inherit logic common among other jobs. +[#examples-railsapplicationjob] === Examples [source,ruby] @@ -569,8 +616,11 @@ class Rails4Job < ActiveJob::Base end ---- +[#railsapplicationmailer] == Rails/ApplicationMailer +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -583,11 +633,13 @@ end Checks that mailers subclass `ApplicationMailer` with Rails 5.0. +[#safety-railsapplicationmailer] === Safety This cop's autocorrection is unsafe because it may let the logic from `ApplicationMailer` sneak into a mailer that is not purposed to inherit logic common among other mailers. +[#examples-railsapplicationmailer] === Examples [source,ruby] @@ -603,8 +655,11 @@ class MyMailer < ActionMailer::Base end ---- +[#railsapplicationrecord] == Rails/ApplicationRecord +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -621,12 +676,14 @@ It is a common practice to define models inside migrations in order to retain fo compatibility by avoiding loading any application code. And so migration files are excluded by default for this cop. +[#safety-railsapplicationrecord] === Safety This cop's autocorrection is unsafe because it may let the logic from `ApplicationRecord` sneak into an Active Record model that is not purposed to inherit logic common among other Active Record models. +[#examples-railsapplicationrecord] === Examples [source,ruby] @@ -642,6 +699,7 @@ class Rails4Model < ActiveRecord::Base end ---- +[#configurable-attributes-railsapplicationrecord] === Configurable attributes |=== @@ -652,6 +710,7 @@ end | Array |=== +[#railsarelstar] == Rails/ArelStar |=== @@ -671,6 +730,7 @@ quoted asterisk (e.g. `my_model`.`*`). This causes the database to look for a column named `*` (or `"*"`) as opposed to expanding the column list as one would likely expect. +[#safety-railsarelstar] === Safety This cop's autocorrection is unsafe because it turns a quoted `*` into @@ -678,6 +738,7 @@ an SQL `*`, unquoted. `*` is a valid column name in certain databases supported by Rails, and even though it is usually a mistake, it might denote legitimate access to a column named `*`. +[#examples-railsarelstar] === Examples [source,ruby] @@ -689,6 +750,7 @@ MyTable.arel_table["*"] MyTable.arel_table[Arel.star] ---- +[#railsassertnot] == Rails/AssertNot |=== @@ -703,6 +765,7 @@ MyTable.arel_table[Arel.star] Use `assert_not` instead of `assert !`. +[#examples-railsassertnot] === Examples [source,ruby] @@ -714,6 +777,7 @@ assert !x assert_not x ---- +[#configurable-attributes-railsassertnot] === Configurable attributes |=== @@ -724,6 +788,7 @@ assert_not x | Array |=== +[#railsattributedefaultblockvalue] == Rails/AttributeDefaultBlockValue |=== @@ -741,6 +806,7 @@ which value is an array, string literal or method call without a block. It will accept all other values, such as string, symbol, integer and float literals as well as constants. +[#examples-railsattributedefaultblockvalue] === Examples [source,ruby] @@ -797,6 +863,7 @@ class User < ApplicationRecord end ---- +[#configurable-attributes-railsattributedefaultblockvalue] === Configurable attributes |=== @@ -807,8 +874,11 @@ end | Array |=== +[#railsbelongsto] == Rails/BelongsTo +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -843,6 +913,7 @@ superfluous `optional: false`). Therefore, in the cases we're using `required: true`, we'll simply invert it to `optional: false` and the user can remove depending on their defaults. +[#examples-railsbelongsto] === Examples [source,ruby] @@ -868,11 +939,13 @@ class Post < ApplicationRecord end ---- +[#references-railsbelongsto] === References * https://guides.rubyonrails.org/5_0_release_notes.html * https://github.com/rails/rails/pull/18937 +[#railsblank] == Rails/Blank |=== @@ -893,14 +966,17 @@ The configuration of `NotPresent` will not produce an offense in the context of `unless else` if `Style/UnlessElse` is enabled. This is to prevent interference between the autocorrection of the two cops. +[#safety-railsblank] === Safety This cop is unsafe autocorrection, because `' '.empty?` returns false, but `' '.blank?` returns true. Therefore, autocorrection is not compatible if the receiver is a non-empty blank string, tab, or newline meta characters. +[#examples-railsblank] === Examples +[#nilorempty_-true-_default_-railsblank] ==== NilOrEmpty: true (default) [source,ruby] @@ -915,6 +991,7 @@ foo == nil || foo.empty? foo.blank? ---- +[#notpresent_-true-_default_-railsblank] ==== NotPresent: true (default) [source,ruby] @@ -928,6 +1005,7 @@ foo.blank? foo.blank? ---- +[#unlesspresent_-true-_default_-railsblank] ==== UnlessPresent: true (default) [source,ruby] @@ -956,6 +1034,7 @@ def blank? end ---- +[#configurable-attributes-railsblank] === Configurable attributes |=== @@ -974,6 +1053,7 @@ end | Boolean |=== +[#railsbulkchangetable] == Rails/BulkChangeTable |=== @@ -1000,6 +1080,7 @@ when the `Database` option is not set. If the adapter is not `mysql2`, `trilogy`, `postgresql`, or `postgis`, this Cop ignores offenses. +[#examples-railsbulkchangetable] === Examples [source,ruby] @@ -1053,6 +1134,7 @@ def change end ---- +[#configurable-attributes-railsbulkchangetable] === Configurable attributes |=== @@ -1067,13 +1149,17 @@ end | Array |=== +[#references-railsbulkchangetable] === References * https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-change_table * https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html +[#railscompactblank] == Rails/CompactBlank +NOTE: Required Rails version: 6.1 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -1086,6 +1172,7 @@ end Checks if collection can be blank-compacted with `compact_blank`. +[#safety-railscompactblank] === Safety It is unsafe by default because false positives may occur in the @@ -1100,6 +1187,7 @@ And `compact_blank!` has different implementations for `Array`, `Hash`, and `Array#compact_blank!`, `Hash#compact_blank!` are equivalent to `delete_if(&:blank?)`. If the cop makes a mistake, autocorrected code may get unexpected behavior. +[#examples-railscompactblank] === Examples [source,ruby] @@ -1125,8 +1213,11 @@ collection.keep_if { |_k, v| v.present? } # Same behavior as `Array#compact_blan collection.compact_blank! ---- +[#railscontenttag] == Rails/ContentTag +NOTE: Required Rails version: 5.1 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -1143,6 +1234,7 @@ NOTE: Allow `tag` when the first argument is a variable because `tag(name)` is simpler rather than `tag.public_send(name)`. And this cop will be renamed to something like `LegacyTag` in the future. (e.g. RuboCop Rails 3.0) +[#examples-railscontenttag] === Examples [source,ruby] @@ -1157,6 +1249,7 @@ tag.br(class: 'classname') tag(name, class: 'classname') ---- +[#configurable-attributes-railscontenttag] === Configurable attributes |=== @@ -1167,12 +1260,14 @@ tag(name, class: 'classname') | Array |=== +[#references-railscontenttag] === References * https://github.com/rubocop/rubocop-rails/issues/260 * https://github.com/rails/rails/issues/25195 * https://api.rubyonrails.org/classes/ActionView/Helpers/TagHelper.html#method-i-content_tag +[#railscreatetablewithtimestamps] == Rails/CreateTableWithTimestamps |=== @@ -1191,6 +1286,7 @@ In many cases, timestamps are useful information and should be added. NOTE: Allow `timestamps` not written when `id: false` because this emphasizes respecting user's editing intentions. +[#examples-railscreatetablewithtimestamps] === Examples [source,ruby] @@ -1235,6 +1331,7 @@ create_table :users, articles, id: false do |t| end ---- +[#configurable-attributes-railscreatetablewithtimestamps] === Configurable attributes |=== @@ -1249,6 +1346,7 @@ end | Array |=== +[#railsdangerouscolumnnames] == Rails/DangerousColumnNames |=== @@ -1265,6 +1363,7 @@ Avoid dangerous column names. Some column names are considered dangerous because they would overwrite methods already defined. +[#examples-railsdangerouscolumnnames] === Examples [source,ruby] @@ -1276,6 +1375,7 @@ add_column :users, :save add_column :users, :saved ---- +[#configurable-attributes-railsdangerouscolumnnames] === Configurable attributes |=== @@ -1290,6 +1390,7 @@ add_column :users, :saved | Array |=== +[#railsdate] == Rails/Date |=== @@ -1321,12 +1422,15 @@ When `EnforcedStyle` is `flexible` then only `Date.today` is prohibited. And you can set a warning for `to_time` with `AllowToTime: false`. `AllowToTime` is `true` by default to prevent false positive on `DateTime` object. +[#safety-railsdate] === Safety This cop's autocorrection is unsafe because it may change handling time. +[#examples-railsdate] === Examples +[#enforcedstyle_-flexible-_default_-railsdate] ==== EnforcedStyle: flexible (default) [source,ruby] @@ -1342,6 +1446,7 @@ Date.yesterday date.in_time_zone ---- +[#enforcedstyle_-strict-railsdate] ==== EnforcedStyle: strict [source,ruby] @@ -1356,6 +1461,7 @@ Time.zone.today Time.zone.today - 1.day ---- +[#allowtotime_-true-_default_-railsdate] ==== AllowToTime: true (default) [source,ruby] @@ -1364,6 +1470,7 @@ Time.zone.today - 1.day date.to_time ---- +[#allowtotime_-false-railsdate] ==== AllowToTime: false [source,ruby] @@ -1372,6 +1479,7 @@ date.to_time date.to_time ---- +[#configurable-attributes-railsdate] === Configurable attributes |=== @@ -1386,6 +1494,7 @@ date.to_time | Boolean |=== +[#railsdefaultscope] == Rails/DefaultScope |=== @@ -1400,6 +1509,7 @@ date.to_time Looks for uses of `default_scope`. +[#examples-railsdefaultscope] === Examples [source,ruby] @@ -1421,6 +1531,7 @@ def self.published end ---- +[#railsdelegate] == Rails/Delegate |=== @@ -1445,6 +1556,7 @@ using the target object as a prefix of the method name without using the `delegate` method will be a violation. When set to `false`, this case is legal. +[#examples-railsdelegate] === Examples [source,ruby] @@ -1477,6 +1589,7 @@ def bar end ---- +[#enforceforprefixed_-true-_default_-railsdelegate] ==== EnforceForPrefixed: true (default) [source,ruby] @@ -1490,6 +1603,7 @@ end delegate :bar, to: :foo, prefix: true ---- +[#enforceforprefixed_-false-railsdelegate] ==== EnforceForPrefixed: false [source,ruby] @@ -1503,6 +1617,7 @@ end delegate :bar, to: :foo, prefix: true ---- +[#configurable-attributes-railsdelegate] === Configurable attributes |=== @@ -1513,6 +1628,7 @@ delegate :bar, to: :foo, prefix: true | Boolean |=== +[#railsdelegateallowblank] == Rails/DelegateAllowBlank |=== @@ -1529,6 +1645,7 @@ Looks for delegations that pass :allow_blank as an option instead of :allow_nil. :allow_blank is not a valid option to pass to ActiveSupport#delegate. +[#examples-railsdelegateallowblank] === Examples [source,ruby] @@ -1540,6 +1657,7 @@ delegate :foo, to: :bar, allow_blank: true delegate :foo, to: :bar, allow_nil: true ---- +[#railsdeprecatedactivemodelerrorsmethods] == Rails/DeprecatedActiveModelErrorsMethods |=== @@ -1555,12 +1673,14 @@ delegate :foo, to: :bar, allow_nil: true Checks direct manipulation of ActiveModel#errors as hash. These operations are deprecated in Rails 6.1 and will not work in Rails 7. +[#safety-railsdeprecatedactivemodelerrorsmethods] === Safety This cop is unsafe because it can report `errors` manipulation on non-ActiveModel, which is obviously valid. The cop has no way of knowing whether a variable is an ActiveModel or not. +[#examples-railsdeprecatedactivemodelerrorsmethods] === Examples [source,ruby] @@ -1586,6 +1706,7 @@ user.errors.keys.include?(:attr) user.errors.attribute_names.include?(:attr) ---- +[#configurable-attributes-railsdeprecatedactivemodelerrorsmethods] === Configurable attributes |=== @@ -1596,6 +1717,7 @@ user.errors.attribute_names.include?(:attr) | String |=== +[#railsdotseparatedkeys] == Rails/DotSeparatedKeys |=== @@ -1612,6 +1734,7 @@ Enforces the use of dot-separated locale keys instead of specifying the `:scope` with an array or a single symbol in `I18n` translation methods. Dot-separated notation is easier to read and trace the hierarchy. +[#examples-railsdotseparatedkeys] === Examples [source,ruby] @@ -1625,10 +1748,12 @@ I18n.t 'activerecord.errors.messages.record_invalid' I18n.t :record_invalid, scope: 'activerecord.errors.messages' ---- +[#references-railsdotseparatedkeys] === References * https://rails.rubystyle.guide/#dot-separated-keys +[#railsduplicateassociation] == Rails/DuplicateAssociation |=== @@ -1647,6 +1772,7 @@ When an association is defined multiple times on a model, Active Record override previously defined association with the new one. Because of this, this cop's autocorrection simply keeps the last of any duplicates and discards the rest. +[#examples-railsduplicateassociation] === Examples [source,ruby] @@ -1670,6 +1796,7 @@ has_many :bar, class_name: 'Foo' has_one :foo ---- +[#configurable-attributes-railsduplicateassociation] === Configurable attributes |=== @@ -1680,6 +1807,7 @@ has_one :foo | String |=== +[#railsduplicatescope] == Rails/DuplicateScope |=== @@ -1695,6 +1823,7 @@ has_one :foo Checks for multiple scopes in a model that have the same `where` clause. This often means you copy/pasted a scope, updated the name, and forgot to change the condition. +[#examples-railsduplicatescope] === Examples [source,ruby] @@ -1708,6 +1837,7 @@ scope :visible, -> { where(visible: true) } scope :hidden, -> { where(visible: false) } ---- +[#configurable-attributes-railsduplicatescope] === Configurable attributes |=== @@ -1718,6 +1848,7 @@ scope :hidden, -> { where(visible: false) } | String |=== +[#railsdurationarithmetic] == Rails/DurationArithmetic |=== @@ -1732,6 +1863,7 @@ scope :hidden, -> { where(visible: false) } Checks if a duration is added to or subtracted from `Time.current`. +[#examples-railsdurationarithmetic] === Examples [source,ruby] @@ -1750,10 +1882,12 @@ created_at - 1.minute 2.days.from_now ---- +[#references-railsdurationarithmetic] === References * https://rails.rubystyle.guide#duration-arithmetic +[#railsdynamicfindby] == Rails/DynamicFindBy |=== @@ -1770,11 +1904,13 @@ Checks dynamic `find_by_*` methods. Use `find_by` instead of dynamic method. See. https://rails.rubystyle.guide#find_by +[#safety-railsdynamicfindby] === Safety It is certainly unsafe when not configured properly, i.e. user-defined `find_by_xxx` method is not added to cop's `AllowedMethods`. +[#examples-railsdynamicfindby] === Examples [source,ruby] @@ -1790,6 +1926,7 @@ User.find_by(name: name, email: email) User.find_by!(email: email) ---- +[#allowedmethods_-__find_by_sql__-_find_by_token_for__-_default_-railsdynamicfindby] ==== AllowedMethods: ['find_by_sql', 'find_by_token_for'] (default) [source,ruby] @@ -1803,6 +1940,7 @@ User.find_by_sql(users_sql) User.find_by_token_for(:password_reset, token) ---- +[#allowedreceivers_-__gem__specification__-_page__-_default_-railsdynamicfindby] ==== AllowedReceivers: ['Gem::Specification', 'page'] (default) [source,ruby] @@ -1816,6 +1954,7 @@ Gem::Specification.find_by_name('backend').gem_dir page.find_by_id('a_dom_id').click ---- +[#configurable-attributes-railsdynamicfindby] === Configurable attributes |=== @@ -1834,10 +1973,12 @@ page.find_by_id('a_dom_id').click | Array |=== +[#references-railsdynamicfindby] === References * https://rails.rubystyle.guide#find_by +[#railseagerevaluationlogmessage] == Rails/EagerEvaluationLogMessage |=== @@ -1860,6 +2001,7 @@ arguments passed as method arguments. Passing a block to `Rails.logger.debug` prevents costly evaluation of interpolated strings when no output would be produced anyway. +[#examples-railseagerevaluationlogmessage] === Examples [source,ruby] @@ -1871,10 +2013,12 @@ Rails.logger.debug "The time is #{Time.zone.now}." Rails.logger.debug { "The time is #{Time.zone.now}." } ---- +[#references-railseagerevaluationlogmessage] === References * https://guides.rubyonrails.org/debugging_rails_applications.html#impact-of-logs-on-performance +[#railsenumhash] == Rails/EnumHash |=== @@ -1894,6 +2038,7 @@ position other than the last causes all previous definitions to shift. Explicitly specifying the value for each key prevents this from happening. +[#examples-railsenumhash] === Examples [source,ruby] @@ -1911,6 +2056,7 @@ enum status: [:active, :archived] enum status: { active: 0, archived: 1 } ---- +[#configurable-attributes-railsenumhash] === Configurable attributes |=== @@ -1921,14 +2067,18 @@ enum status: { active: 0, archived: 1 } | Array |=== +[#references-railsenumhash] === References * https://rails.rubystyle.guide#enums +[#railsenumsyntax] == Rails/EnumSyntax NOTE: Required Ruby version: 3.0 +NOTE: Required Rails version: 7.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -1944,6 +2094,7 @@ Looks for enums written with keyword arguments syntax. Defining enums with keyword arguments syntax is deprecated and will be removed in Rails 8.0. Positional arguments should be used instead: +[#examples-railsenumsyntax] === Examples [source,ruby] @@ -1955,6 +2106,7 @@ enum status: { active: 0, archived: 1 }, _prefix: true enum :status, { active: 0, archived: 1 }, prefix: true ---- +[#configurable-attributes-railsenumsyntax] === Configurable attributes |=== @@ -1969,6 +2121,7 @@ enum :status, { active: 0, archived: 1 }, prefix: true | Array |=== +[#railsenumuniqueness] == Rails/EnumUniqueness |=== @@ -1983,6 +2136,7 @@ enum :status, { active: 0, archived: 1 }, prefix: true Looks for duplicate values in enum declarations. +[#examples-railsenumuniqueness] === Examples [source,ruby] @@ -2012,6 +2166,7 @@ enum status: [:active, :archived, :active] enum status: [:active, :archived] ---- +[#configurable-attributes-railsenumuniqueness] === Configurable attributes |=== @@ -2022,8 +2177,11 @@ enum status: [:active, :archived] | Array |=== +[#railsenvlocal] == Rails/EnvLocal +NOTE: Required Rails version: 7.1 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -2037,6 +2195,7 @@ enum status: [:active, :archived] Checks for usage of `Rails.env.development? || Rails.env.test?` which can be replaced with `Rails.env.local?`, introduced in Rails 7.1. +[#examples-railsenvlocal] === Examples [source,ruby] @@ -2048,6 +2207,7 @@ Rails.env.development? || Rails.env.test? Rails.env.local? ---- +[#railsenvironmentcomparison] == Rails/EnvironmentComparison |=== @@ -2063,6 +2223,7 @@ Rails.env.local? Checks that Rails.env is compared using `.production?`-like methods instead of equality against a string or symbol. +[#examples-railsenvironmentcomparison] === Examples [source,ruby] @@ -2077,6 +2238,7 @@ Rails.env == :test Rails.env.production? ---- +[#railsenvironmentvariableaccess] == Rails/EnvironmentVariableAccess |=== @@ -2096,6 +2258,7 @@ time if the environment variables were loaded as part of initialization and copied into the application's configuration or secrets. The cop can be configured to allow either reads or writes if required. +[#examples-railsenvironmentvariableaccess] === Examples [source,ruby] @@ -2107,6 +2270,7 @@ Rails.application.secrets.foo Rails.application.config.foo = "bar" ---- +[#allowreads_-false-_default_-railsenvironmentvariableaccess] ==== AllowReads: false (default) [source,ruby] @@ -2116,6 +2280,7 @@ ENV["FOO"] ENV.fetch("FOO") ---- +[#allowreads_-true-railsenvironmentvariableaccess] ==== AllowReads: true [source,ruby] @@ -2125,6 +2290,7 @@ ENV["FOO"] ENV.fetch("FOO") ---- +[#allowwrites_-false-_default_-railsenvironmentvariableaccess] ==== AllowWrites: false (default) [source,ruby] @@ -2133,6 +2299,7 @@ ENV.fetch("FOO") ENV["FOO"] = "bar" ---- +[#allowwrites_-true-railsenvironmentvariableaccess] ==== AllowWrites: true [source,ruby] @@ -2141,6 +2308,7 @@ ENV["FOO"] = "bar" ENV["FOO"] = "bar" ---- +[#configurable-attributes-railsenvironmentvariableaccess] === Configurable attributes |=== @@ -2163,6 +2331,7 @@ ENV["FOO"] = "bar" | Boolean |=== +[#railsexit] == Rails/Exit |=== @@ -2189,6 +2358,7 @@ is used.) the program exiting, which could result in the code failing to run and do its job. +[#examples-railsexit] === Examples [source,ruby] @@ -2200,6 +2370,7 @@ exit(0) raise 'a bad error has happened' ---- +[#configurable-attributes-railsexit] === Configurable attributes |=== @@ -2214,8 +2385,11 @@ raise 'a bad error has happened' | Array |=== +[#railsexpandeddaterange] == Rails/ExpandedDateRange +NOTE: Required Rails version: 5.1 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -2229,6 +2403,7 @@ raise 'a bad error has happened' Checks for expanded date range. It only compatible `..` range is targeted. Incompatible `...` range is ignored. +[#examples-railsexpandeddaterange] === Examples [source,ruby] @@ -2248,10 +2423,12 @@ date.all_quarter date.all_year ---- +[#references-railsexpandeddaterange] === References * https://rails.rubystyle.guide/#date-time-range +[#railsfilepath] == Rails/FilePath |=== @@ -2267,8 +2444,10 @@ date.all_year Identifies usages of file path joining process to use `Rails.root.join` clause. It is used to add uniformity when joining paths. +[#examples-railsfilepath] === Examples +[#enforcedstyle_-slashes-_default_-railsfilepath] ==== EnforcedStyle: slashes (default) [source,ruby] @@ -2287,6 +2466,7 @@ File.join(Rails.root, 'app/models/goober') Rails.root.join('app/models/goober').to_s ---- +[#enforcedstyle_-arguments-railsfilepath] ==== EnforcedStyle: arguments [source,ruby] @@ -2305,6 +2485,7 @@ File.join(Rails.root, 'app/models/goober') Rails.root.join('app', 'models', 'goober').to_s ---- +[#configurable-attributes-railsfilepath] === Configurable attributes |=== @@ -2315,6 +2496,7 @@ Rails.root.join('app', 'models', 'goober').to_s | `slashes`, `arguments` |=== +[#railsfindby] == Rails/FindBy |=== @@ -2334,6 +2516,7 @@ And `where(...).first` can return different results from `find_by`. If you also want to detect `where.first`, you can set `IgnoreWhereFirst` to false. +[#examples-railsfindby] === Examples [source,ruby] @@ -2345,6 +2528,7 @@ User.where(name: 'Bruce').take User.find_by(name: 'Bruce') ---- +[#ignorewherefirst_-true-_default_-railsfindby] ==== IgnoreWhereFirst: true (default) [source,ruby] @@ -2353,6 +2537,7 @@ User.find_by(name: 'Bruce') User.where(name: 'Bruce').first ---- +[#ignorewherefirst_-false-railsfindby] ==== IgnoreWhereFirst: false [source,ruby] @@ -2361,6 +2546,7 @@ User.where(name: 'Bruce').first User.where(name: 'Bruce').first ---- +[#configurable-attributes-railsfindby] === Configurable attributes |=== @@ -2371,10 +2557,12 @@ User.where(name: 'Bruce').first | Boolean |=== +[#references-railsfindby] === References * https://rails.rubystyle.guide#find_by +[#railsfindbyid] == Rails/FindById |=== @@ -2391,6 +2579,7 @@ Enforces that `ActiveRecord#find` is used instead of `where.take!`, `find_by!`, and `find_by_id!` to retrieve a single record by primary key when you expect it to be found. +[#examples-railsfindbyid] === Examples [source,ruby] @@ -2404,10 +2593,12 @@ User.find_by!(id: id) User.find(id) ---- +[#references-railsfindbyid] === References * https://rails.rubystyle.guide/#find +[#railsfindeach] == Rails/FindEach |=== @@ -2422,12 +2613,14 @@ User.find(id) Identifies usages of `all.each` and change them to use `all.find_each` instead. +[#safety-railsfindeach] === Safety This cop is unsafe if the receiver object is not an Active Record object. Also, `all.each` returns an `Array` instance and `all.find_each` returns nil, so the return values are different. +[#examples-railsfindeach] === Examples [source,ruby] @@ -2439,6 +2632,7 @@ User.all.each User.all.find_each ---- +[#allowedmethods_-__order__-railsfindeach] ==== AllowedMethods: ['order'] [source,ruby] @@ -2447,6 +2641,7 @@ User.all.find_each User.order(:foo).each ---- +[#allowedpattern_-__order__-railsfindeach] ==== AllowedPattern: ['order'] [source,ruby] @@ -2455,6 +2650,7 @@ User.order(:foo).each User.order(:foo).each ---- +[#configurable-attributes-railsfindeach] === Configurable attributes |=== @@ -2469,12 +2665,16 @@ User.order(:foo).each | Array |=== +[#references-railsfindeach] === References * https://rails.rubystyle.guide#find-each +[#railsfreezetime] == Rails/FreezeTime +NOTE: Required Rails version: 5.2 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -2488,12 +2688,14 @@ User.order(:foo).each Identifies usages of `travel_to` with an argument of the current time and change them to use `freeze_time` instead. +[#safety-railsfreezetime] === Safety This cop’s autocorrection is unsafe because `freeze_time` just delegates to `travel_to` with a default `Time.now`, it is not strictly equivalent to `Time.now` if the argument of `travel_to` is the current time considering time zone. +[#examples-railsfreezetime] === Examples [source,ruby] @@ -2511,10 +2713,12 @@ travel_to(Time.current.to_time) freeze_time ---- +[#references-railsfreezetime] === References * https://rails.rubystyle.guide/#freeze-time +[#railshasandbelongstomany] == Rails/HasAndBelongsToMany |=== @@ -2529,6 +2733,7 @@ freeze_time Checks for the use of the has_and_belongs_to_many macro. +[#examples-railshasandbelongstomany] === Examples [source,ruby] @@ -2540,6 +2745,7 @@ Checks for the use of the has_and_belongs_to_many macro. # has_many :ingredients, through: :recipe_ingredients ---- +[#configurable-attributes-railshasandbelongstomany] === Configurable attributes |=== @@ -2550,10 +2756,12 @@ Checks for the use of the has_and_belongs_to_many macro. | Array |=== +[#references-railshasandbelongstomany] === References * https://rails.rubystyle.guide#has-many-through +[#railshasmanyorhasonedependent] == Rails/HasManyOrHasOneDependent |=== @@ -2572,6 +2780,7 @@ specify a `:dependent` option. It doesn't register an offense if `:through` or `dependent: nil` is specified, or if the model is read-only. +[#examples-railshasmanyorhasonedependent] === Examples [source,ruby] @@ -2600,6 +2809,7 @@ class User < ActiveRecord::Base end ---- +[#configurable-attributes-railshasmanyorhasonedependent] === Configurable attributes |=== @@ -2610,10 +2820,12 @@ end | Array |=== +[#references-railshasmanyorhasonedependent] === References * https://rails.rubystyle.guide#has_many-has_one-dependent-option +[#railshelperinstancevariable] == Rails/HelperInstanceVariable |=== @@ -2639,6 +2851,7 @@ example to a model, decorator or presenter. Provided that a class inherits `ActionView::Helpers::FormBuilder`, an offense will not be registered. +[#examples-railshelperinstancevariable] === Examples [source,ruby] @@ -2659,6 +2872,7 @@ class MyFormBuilder < ActionView::Helpers::FormBuilder end ---- +[#configurable-attributes-railshelperinstancevariable] === Configurable attributes |=== @@ -2669,8 +2883,11 @@ end | Array |=== +[#railshttppositionalarguments] == Rails/HttpPositionalArguments +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -2691,6 +2908,7 @@ Rails/HttpPositionalArguments cop or set your TargetRailsVersion in your NOTE: It does not detect any cases where `include Rack::Test::Methods` is used which makes the http methods incompatible behavior. +[#examples-railshttppositionalarguments] === Examples [source,ruby] @@ -2703,6 +2921,7 @@ get :new, params: { user_id: 1 } get :new, **options ---- +[#configurable-attributes-railshttppositionalarguments] === Configurable attributes |=== @@ -2713,6 +2932,7 @@ get :new, **options | Array |=== +[#railshttpstatus] == Rails/HttpStatus |=== @@ -2727,8 +2947,10 @@ get :new, **options Enforces use of symbolic or numeric value to define HTTP status. +[#examples-railshttpstatus] === Examples +[#enforcedstyle_-symbolic-_default_-railshttpstatus] ==== EnforcedStyle: symbolic (default) [source,ruby] @@ -2753,6 +2975,7 @@ assert_response :ok assert_redirected_to '/some/path', status: :moved_permanently ---- +[#enforcedstyle_-numeric-railshttpstatus] ==== EnforcedStyle: numeric [source,ruby] @@ -2776,6 +2999,7 @@ assert_response 200 assert_redirected_to '/some/path', status: 301 ---- +[#configurable-attributes-railshttpstatus] === Configurable attributes |=== @@ -2786,6 +3010,7 @@ assert_redirected_to '/some/path', status: 301 | `numeric`, `symbolic` |=== +[#railsi18nlazylookup] == Rails/I18nLazyLookup |=== @@ -2806,8 +3031,10 @@ is `lazy` (the default), explicit lookups are added as offenses. When the EnforcedStyle is `explicit` then lazy lookups are added as offenses. +[#examples-railsi18nlazylookup] === Examples +[#enforcedstyle_-lazy-_default_-railsi18nlazylookup] ==== EnforcedStyle: lazy (default) [source,ruby] @@ -2835,6 +3062,7 @@ class BooksController < ApplicationController end ---- +[#enforcedstyle_-explicit-railsi18nlazylookup] ==== EnforcedStyle: explicit [source,ruby] @@ -2856,6 +3084,7 @@ class BooksController < ApplicationController end ---- +[#configurable-attributes-railsi18nlazylookup] === Configurable attributes |=== @@ -2870,11 +3099,13 @@ end | Array |=== +[#references-railsi18nlazylookup] === References * https://rails.rubystyle.guide/#lazy-lookup * https://guides.rubyonrails.org/i18n.html#lazy-lookup +[#railsi18nlocaleassignment] == Rails/I18nLocaleAssignment |=== @@ -2894,6 +3125,7 @@ unexpected behavior at a later time. Using `I18n.with_locale` ensures the code passed in the block is the only place `I18n.locale` is affected. It eliminates the possibility of a `locale` sticking around longer than intended. +[#examples-railsi18nlocaleassignment] === Examples [source,ruby] @@ -2906,6 +3138,7 @@ I18n.with_locale(:fr) do end ---- +[#configurable-attributes-railsi18nlocaleassignment] === Configurable attributes |=== @@ -2916,6 +3149,7 @@ end | Array |=== +[#railsi18nlocaletexts] == Rails/I18nLocaleTexts |=== @@ -2930,6 +3164,7 @@ end Enforces use of I18n and locale files instead of locale specific strings. +[#examples-railsi18nlocaletexts] === Examples [source,ruby] @@ -2995,10 +3230,12 @@ class UserMailer < ApplicationMailer end ---- +[#references-railsi18nlocaletexts] === References * https://rails.rubystyle.guide/#locale-texts +[#railsignoredcolumnsassignment] == Rails/IgnoredColumnsAssignment |=== @@ -3018,6 +3255,7 @@ Overwriting previous assignments is usually a mistake, since it will un-ignore the first set of columns. Since duplicate column names is not a problem, it is better to simply append to the list. +[#examples-railsignoredcolumnsassignment] === Examples [source,ruby] @@ -3044,10 +3282,12 @@ class User < ActiveRecord::Base end ---- +[#references-railsignoredcolumnsassignment] === References * https://rails.rubystyle.guide/#append-ignored-columns +[#railsignoredskipactionfilteroption] == Rails/IgnoredSkipActionFilterOption |=== @@ -3067,6 +3307,7 @@ The `if` option will be ignored when `if` and `only` are used together. Similarly, the `except` option will be ignored when `if` and `except` are used together. +[#examples-railsignoredskipactionfilteroption] === Examples [source,ruby] @@ -3099,6 +3340,7 @@ class MyPageController < ApplicationController end ---- +[#configurable-attributes-railsignoredskipactionfilteroption] === Configurable attributes |=== @@ -3109,10 +3351,12 @@ end | Array |=== +[#references-railsignoredskipactionfilteroption] === References * https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html#method-i-_normalize_callback_options +[#railsindexby] == Rails/IndexBy |=== @@ -3130,6 +3374,7 @@ Looks for uses of `each_with_object({}) { ... }`, an enumerable into a hash where the values are the original elements. Rails provides the `index_by` method for this purpose. +[#examples-railsindexby] === Examples [source,ruby] @@ -3144,8 +3389,11 @@ Hash[[1, 2, 3].collect { |el| [foo(el), el] }] [1, 2, 3].index_by { |el| foo(el) } ---- +[#railsindexwith] == Rails/IndexWith +NOTE: Required Rails version: 6.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -3161,6 +3409,7 @@ Looks for uses of `each_with_object({}) { ... }`, an enumerable into a hash where the keys are the original elements. Rails provides the `index_with` method for this purpose. +[#examples-railsindexwith] === Examples [source,ruby] @@ -3175,6 +3424,7 @@ Hash[[1, 2, 3].collect { |el| [el, foo(el)] }] [1, 2, 3].index_with { |el| foo(el) } ---- +[#railsinquiry] == Rails/Inquiry |=== @@ -3189,6 +3439,7 @@ Hash[[1, 2, 3].collect { |el| [el, foo(el)] }] Checks that Active Support's `inquiry` method is not used. +[#examples-railsinquiry] === Examples [source,ruby] @@ -3210,10 +3461,12 @@ pets = %w(cat dog) pets.include? 'cat' ---- +[#references-railsinquiry] === References * https://rails.rubystyle.guide/#inquiry +[#railsinverseof] == Rails/InverseOf |=== @@ -3238,6 +3491,7 @@ associated object in memory, or set to `false` to opt-out. Note that setting `nil` does not stop Active Record from trying to determine the inverse automatically, and is not considered a valid value for this. +[#examples-railsinverseof] === Examples [source,ruby] @@ -3359,6 +3613,7 @@ class Patient < ApplicationRecord end ---- +[#ignorescopes_-false-_default_-railsinverseof] ==== IgnoreScopes: false (default) [source,ruby] @@ -3369,6 +3624,7 @@ class Blog < ApplicationRecord end ---- +[#ignorescopes_-true-railsinverseof] ==== IgnoreScopes: true [source,ruby] @@ -3379,6 +3635,7 @@ class Blog < ApplicationRecord end ---- +[#configurable-attributes-railsinverseof] === Configurable attributes |=== @@ -3393,11 +3650,13 @@ end | Array |=== +[#references-railsinverseof] === References * https://guides.rubyonrails.org/association_basics.html#bi-directional-associations * https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses +[#railslexicallyscopedactionfilter] == Rails/LexicallyScopedActionFilter |=== @@ -3413,6 +3672,7 @@ end Checks that methods specified in the filter's `only` or `except` options are defined within the same class or module. +[#safety-railslexicallyscopedactionfilter] === Safety You can technically specify methods of superclass or methods added by @@ -3423,6 +3683,7 @@ define the filter in that class or module. If you rely on behavior defined in the superclass actions, you must remember to invoke `super` in the subclass actions. +[#examples-railslexicallyscopedactionfilter] === Examples [source,ruby] @@ -3500,6 +3761,7 @@ class ArticlesController < ContentController end ---- +[#configurable-attributes-railslexicallyscopedactionfilter] === Configurable attributes |=== @@ -3510,10 +3772,12 @@ end | Array |=== +[#references-railslexicallyscopedactionfilter] === References * https://rails.rubystyle.guide#lexically-scoped-action-filter +[#railslinktoblank] == Rails/LinkToBlank |=== @@ -3534,6 +3798,7 @@ and could change its location for phishing purposes. The option `rel: 'noreferrer'` also blocks this behavior and removes the http-referrer header. +[#examples-railslinktoblank] === Examples [source,ruby] @@ -3548,12 +3813,14 @@ link_to 'Click here', url, target: '_blank', rel: 'noopener' link_to 'Click here', url, target: '_blank', rel: 'noreferrer' ---- +[#references-railslinktoblank] === References * https://mathiasbynens.github.io/rel-noopener/ * https://html.spec.whatwg.org/multipage/links.html#link-type-noopener * https://html.spec.whatwg.org/multipage/links.html#link-type-noreferrer +[#railsmailername] == Rails/MailerName |=== @@ -3571,11 +3838,13 @@ Enforces that mailer names end with `Mailer` suffix. Without the `Mailer` suffix it isn't immediately apparent what's a mailer and which views are related to the mailer. +[#safety-railsmailername] === Safety This cop's autocorrection is unsafe because renaming a constant is always an unsafe operation. +[#examples-railsmailername] === Examples [source,ruby] @@ -3595,6 +3864,7 @@ class UserMailer < ApplicationMailer end ---- +[#configurable-attributes-railsmailername] === Configurable attributes |=== @@ -3605,10 +3875,12 @@ end | Array |=== +[#references-railsmailername] === References * https://rails.rubystyle.guide/#mailer-name +[#railsmatchroute] == Rails/MatchRoute |=== @@ -3627,6 +3899,7 @@ can be replaced with a specific HTTP method. Don't use `match` to define any routes unless there is a need to map multiple request types among [:get, :post, :patch, :put, :delete] to a single action using the `:via` option. +[#examples-railsmatchroute] === Examples [source,ruby] @@ -3642,6 +3915,7 @@ match 'photos/:id', to: 'photos#show', via: [:get, :post] match 'photos/:id', to: 'photos#show', via: :all ---- +[#configurable-attributes-railsmatchroute] === Configurable attributes |=== @@ -3652,10 +3926,12 @@ match 'photos/:id', to: 'photos#show', via: :all | Array |=== +[#references-railsmatchroute] === References * https://rails.rubystyle.guide/#no-match-routes +[#railsmigrationclassname] == Rails/MigrationClassName |=== @@ -3672,6 +3948,7 @@ Makes sure that each migration file defines a migration class whose name matches the file name. (e.g. `20220224111111_create_users.rb` should define `CreateUsers` class.) +[#examples-railsmigrationclassname] === Examples [source,ruby] @@ -3687,6 +3964,7 @@ class CreateUsers < ActiveRecord::Migration[7.0] end ---- +[#configurable-attributes-railsmigrationclassname] === Configurable attributes |=== @@ -3697,6 +3975,7 @@ end | Array |=== +[#railsnegateinclude] == Rails/NegateInclude |=== @@ -3712,11 +3991,13 @@ end Enforces the use of `collection.exclude?(obj)` over `!collection.include?(obj)`. +[#safety-railsnegateinclude] === Safety This cop is unsafe because false positive will occur for receiver objects that do not have an `exclude?` method. (e.g. `IPAddr`) +[#examples-railsnegateinclude] === Examples [source,ruby] @@ -3730,10 +4011,12 @@ array.exclude?(2) hash.exclude?(:key) ---- +[#references-railsnegateinclude] === References * https://rails.rubystyle.guide#exclude +[#railsnotnullcolumn] == Rails/NotNullColumn |=== @@ -3766,6 +4049,7 @@ environment in `config/database.yml` or the environment variable `DATABASE_URL` when the `Database` option is not set. If the database is MySQL, this cop ignores offenses for `TEXT` columns. +[#examples-railsnotnullcolumn] === Examples [source,ruby] @@ -3787,6 +4071,7 @@ add_reference :products, :category change_column_null :products, :category_id, false ---- +[#configurable-attributes-railsnotnullcolumn] === Configurable attributes |=== @@ -3801,6 +4086,7 @@ change_column_null :products, :category_id, false | Array |=== +[#railsorderbyid] == Rails/OrderById |=== @@ -3822,6 +4108,7 @@ Use a timestamp column to order chronologically. As a bonus the intent is cleare NOTE: Make sure the changed order column does not introduce performance bottlenecks and appropriate database indexes are added. +[#examples-railsorderbyid] === Examples [source,ruby] @@ -3834,10 +4121,12 @@ scope :chronological, -> { order(primary_key => :asc) } scope :chronological, -> { order(created_at: :asc) } ---- +[#references-railsorderbyid] === References * https://rails.rubystyle.guide/#order-by-id +[#railsoutput] == Rails/Output |=== @@ -3852,11 +4141,13 @@ scope :chronological, -> { order(created_at: :asc) } Checks for the use of output calls like puts and print +[#safety-railsoutput] === Safety This cop's autocorrection is unsafe because depending on the Rails log level configuration, changing from `puts` to `Rails.logger.debug` could result in no output being shown. +[#examples-railsoutput] === Examples [source,ruby] @@ -3870,6 +4161,7 @@ print 'A debug message' Rails.logger.debug 'A debug message' ---- +[#configurable-attributes-railsoutput] === Configurable attributes |=== @@ -3880,6 +4172,7 @@ Rails.logger.debug 'A debug message' | Array |=== +[#railsoutputsafety] == Rails/OutputSafety |=== @@ -3898,6 +4191,7 @@ simply return a SafeBuffer containing the content as is. Instead, use `safe_join` to join content and escape it and concat to concatenate content and escape it, ensuring its safety. +[#examples-railsoutputsafety] === Examples [source,ruby] @@ -3956,8 +4250,11 @@ safe_join([user_content, " ", content_tag(:span, user_content)]) # "<b>hi</b> <b>hi</b>" ---- +[#railspick] == Rails/Pick +NOTE: Required Rails version: 6.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -3978,6 +4275,7 @@ Note that when `pick` is added to a relation with an existing limit, it causes a subquery to be added. In most cases this is undesirable, and care should be taken while resolving this violation. +[#safety-railspick] === Safety This cop is unsafe because `pluck` is defined on both `ActiveRecord::Relation` and `Enumerable`, @@ -3986,6 +4284,7 @@ in Rails 6.1 via rails/rails#38760, at which point the cop is safe. See: https://github.com/rubocop/rubocop-rails/pull/249 +[#examples-railspick] === Examples [source,ruby] @@ -3999,12 +4298,16 @@ Model.pick(:a) [{ a: :b, c: :d }].pick(:a, :b) ---- +[#references-railspick] === References * https://rails.rubystyle.guide#pick +[#railspluck] == Rails/Pluck +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -4021,6 +4324,7 @@ Enforces the use of `pluck` over `map`. element in an enumerable. When called on an Active Record relation, it results in a more efficient query that only selects the necessary key. +[#safety-railspluck] === Safety This cop is unsafe because model can use column aliases. @@ -4034,6 +4338,7 @@ User.select('name AS nickname').map { |user| user[:nickname] } # => array of nic User.select('name AS nickname').pluck(:nickname) # => raises ActiveRecord::StatementInvalid ---- +[#examples-railspluck] === Examples [source,ruby] @@ -4047,10 +4352,12 @@ Post.published.pluck(:title) [{ a: :b, c: :d }].pluck(:a) ---- +[#references-railspluck] === References * https://rails.rubystyle.guide#pluck +[#railspluckid] == Rails/PluckId |=== @@ -4065,10 +4372,12 @@ Post.published.pluck(:title) Enforces the use of `ids` over `pluck(:id)` and `pluck(primary_key)`. +[#safety-railspluckid] === Safety This cop is unsafe if the receiver object is not an Active Record object. +[#examples-railspluckid] === Examples [source,ruby] @@ -4090,10 +4399,12 @@ def self.user_ids end ---- +[#references-railspluckid] === References * https://rails.rubystyle.guide/#ids +[#railspluckinwhere] == Rails/PluckInWhere |=== @@ -4117,6 +4428,7 @@ This cop has two modes of enforcement. When the `EnforcedStyle` is set to `conservative` (the default), only calls to `pluck` on a constant (e.g. a model class) within `where` are considered offenses. +[#safety-railspluckinwhere] === Safety When `EnforcedStyle` is set to `aggressive`, all calls to `pluck` @@ -4132,6 +4444,7 @@ subquery result sequentially, rather than using an index. This can cause significant performance issues compared to writing the query differently or using `pluck`. +[#examples-railspluckinwhere] === Examples [source,ruby] @@ -4147,6 +4460,7 @@ Post.where(user_id: active_users.select(:id)) Post.where.not(user_id: active_users.select(:id)) ---- +[#enforcedstyle_-conservative-_default_-railspluckinwhere] ==== EnforcedStyle: conservative (default) [source,ruby] @@ -4155,6 +4469,7 @@ Post.where.not(user_id: active_users.select(:id)) Post.where(user_id: active_users.pluck(:id)) ---- +[#enforcedstyle_-aggressive-railspluckinwhere] ==== EnforcedStyle: aggressive [source,ruby] @@ -4163,6 +4478,7 @@ Post.where(user_id: active_users.pluck(:id)) Post.where(user_id: active_users.pluck(:id)) ---- +[#configurable-attributes-railspluckinwhere] === Configurable attributes |=== @@ -4173,6 +4489,7 @@ Post.where(user_id: active_users.pluck(:id)) | `conservative`, `aggressive` |=== +[#railspluralizationgrammar] == Rails/PluralizationGrammar |=== @@ -4188,6 +4505,7 @@ Post.where(user_id: active_users.pluck(:id)) Checks for correct grammar when using ActiveSupport's core extensions to the numeric classes. +[#examples-railspluralizationgrammar] === Examples [source,ruby] @@ -4205,6 +4523,7 @@ core extensions to the numeric classes. 1.gigabyte ---- +[#railspresence] == Rails/Presence |=== @@ -4220,6 +4539,7 @@ core extensions to the numeric classes. Checks code that can be written more easily using `Object#presence` defined by Active Support. +[#examples-railspresence] === Examples [source,ruby] @@ -4258,6 +4578,7 @@ a.blank? ? b : a a.presence || b ---- +[#railspresent] == Rails/Present |=== @@ -4278,8 +4599,10 @@ The configuration of `NotBlank` will not produce an offense in the context of `unless else` if `Style/UnlessElse` is enabled. This is to prevent interference between the autocorrection of the two cops. +[#examples-railspresent] === Examples +[#notnilandnotempty_-true-_default_-railspresent] ==== NotNilAndNotEmpty: true (default) [source,ruby] @@ -4296,6 +4619,7 @@ foo != nil && !foo.empty? foo.present? ---- +[#notblank_-true-_default_-railspresent] ==== NotBlank: true (default) [source,ruby] @@ -4312,6 +4636,7 @@ not foo.blank? foo.present? ---- +[#unlessblank_-true-_default_-railspresent] ==== UnlessBlank: true (default) [source,ruby] @@ -4325,6 +4650,7 @@ something unless foo.blank? something if foo.present? ---- +[#configurable-attributes-railspresent] === Configurable attributes |=== @@ -4343,6 +4669,7 @@ something if foo.present? | Boolean |=== +[#railsrakeenvironment] == Rails/RakeEnvironment |=== @@ -4366,12 +4693,14 @@ following conditions: * The task does not need application code. * The task invokes the `:environment` task. +[#safety-railsrakeenvironment] === Safety Probably not a problem in most cases, but it is possible that calling `:environment` task will break a behavior. It's also slower. E.g. some task that only needs one gem to be loaded to run will run significantly faster without loading the whole application. +[#examples-railsrakeenvironment] === Examples [source,ruby] @@ -4387,6 +4716,7 @@ task foo: :environment do end ---- +[#configurable-attributes-railsrakeenvironment] === Configurable attributes |=== @@ -4401,6 +4731,7 @@ end | Array |=== +[#railsreadwriteattribute] == Rails/ReadWriteAttribute |=== @@ -4428,6 +4759,7 @@ When called from within a method with the same name as the attribute, `read_attribute` and `write_attribute` must be used to prevent an infinite loop: +[#examples-railsreadwriteattribute] === Examples [source,ruby] @@ -4449,6 +4781,7 @@ def foo end ---- +[#configurable-attributes-railsreadwriteattribute] === Configurable attributes |=== @@ -4459,10 +4792,12 @@ end | Array |=== +[#references-railsreadwriteattribute] === References * https://rails.rubystyle.guide#read-attribute +[#railsredundantactiverecordallmethod] == Rails/RedundantActiveRecordAllMethod |=== @@ -4483,10 +4818,12 @@ This is because omitting `all` from an association changes the methods from `ActiveRecord::Relation` to `ActiveRecord::Associations::CollectionProxy`, which can affect their behavior. +[#safety-railsredundantactiverecordallmethod] === Safety This cop is unsafe for autocorrection if the receiver for `all` is not an Active Record object. +[#examples-railsredundantactiverecordallmethod] === Examples [source,ruby] @@ -4504,6 +4841,7 @@ users.where(id: ids) user.articles.order(:created_at) ---- +[#allowedreceivers_-__actionmailer__preview__-_activesupport__timezone__-_default_-railsredundantactiverecordallmethod] ==== AllowedReceivers: ['ActionMailer::Preview', 'ActiveSupport::TimeZone'] (default) [source,ruby] @@ -4513,6 +4851,7 @@ ActionMailer::Preview.all.first ActiveSupport::TimeZone.all.first ---- +[#configurable-attributes-railsredundantactiverecordallmethod] === Configurable attributes |=== @@ -4523,10 +4862,12 @@ ActiveSupport::TimeZone.all.first | Array |=== +[#references-railsredundantactiverecordallmethod] === References * https://rails.rubystyle.guide/#redundant-all +[#railsredundantallownil] == Rails/RedundantAllowNil |=== @@ -4542,6 +4883,7 @@ ActiveSupport::TimeZone.all.first Checks Rails model validations for a redundant `allow_nil` when `allow_blank` is present. +[#examples-railsredundantallownil] === Examples [source,ruby] @@ -4566,6 +4908,7 @@ validates :x, length: { is: 5 }, allow_blank: false validates :x, length: { is: 5 }, allow_nil: true, allow_blank: false ---- +[#configurable-attributes-railsredundantallownil] === Configurable attributes |=== @@ -4576,6 +4919,7 @@ validates :x, length: { is: 5 }, allow_nil: true, allow_blank: false | Array |=== +[#railsredundantforeignkey] == Rails/RedundantForeignKey |=== @@ -4591,6 +4935,7 @@ validates :x, length: { is: 5 }, allow_nil: true, allow_blank: false Detects cases where the `:foreign_key` option on associations is redundant. +[#examples-railsredundantforeignkey] === Examples [source,ruby] @@ -4614,8 +4959,11 @@ class Comment end ---- +[#railsredundantpresencevalidationonbelongsto] == Rails/RedundantPresenceValidationOnBelongsTo +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -4631,11 +4979,13 @@ unless `config.active_record.belongs_to_required_by_default` is explicitly set to `false`. The presence validator is added automatically, and explicit presence validation is redundant. +[#safety-railsredundantpresencevalidationonbelongsto] === Safety This cop's autocorrection is unsafe because it changes the default error message from "can't be blank" to "must exist". +[#examples-railsredundantpresencevalidationonbelongsto] === Examples [source,ruby] @@ -4659,6 +5009,7 @@ belongs_to :user belongs_to :author, foreign_key: :user_id ---- +[#railsredundantreceiverinwithoptions] == Rails/RedundantReceiverInWithOptions |=== @@ -4674,6 +5025,7 @@ belongs_to :author, foreign_key: :user_id Checks for redundant receiver in `with_options`. Receiver is implicit from Rails 4.2 or higher. +[#examples-railsredundantreceiverinwithoptions] === Examples [source,ruby] @@ -4729,8 +5081,11 @@ with_options options: false do |merger| end ---- +[#railsredundanttravelback] == Rails/RedundantTravelBack +NOTE: Required Rails version: 5.2 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -4744,6 +5099,7 @@ end Checks for redundant `travel_back` calls. Since Rails 5.2, `travel_back` is automatically called at the end of the test. +[#examples-railsredundanttravelback] === Examples [source,ruby] @@ -4771,6 +5127,7 @@ after do end ---- +[#configurable-attributes-railsredundanttravelback] === Configurable attributes |=== @@ -4781,6 +5138,7 @@ end | Array |=== +[#railsreflectionclassname] == Rails/ReflectionClassName |=== @@ -4796,11 +5154,13 @@ end Checks if the value of the option `class_name`, in the definition of a reflection is a string. +[#safety-railsreflectionclassname] === Safety This cop is unsafe because it cannot be determined whether constant or method return value specified to `class_name` is a string. +[#examples-railsreflectionclassname] === Examples [source,ruby] @@ -4813,6 +5173,7 @@ has_many :accounts, class_name: Account.name has_many :accounts, class_name: 'Account' ---- +[#railsrefutemethods] == Rails/RefuteMethods |=== @@ -4827,8 +5188,10 @@ has_many :accounts, class_name: 'Account' Use `assert_not` methods instead of `refute` methods. +[#examples-railsrefutemethods] === Examples +[#enforcedstyle_-assert_not-_default_-railsrefutemethods] ==== EnforcedStyle: assert_not (default) [source,ruby] @@ -4844,6 +5207,7 @@ assert_not_empty [1, 2, 3] assert_not_equal true, false ---- +[#enforcedstyle_-refute-railsrefutemethods] ==== EnforcedStyle: refute [source,ruby] @@ -4859,6 +5223,7 @@ refute_empty [1, 2, 3] refute_equal true, false ---- +[#configurable-attributes-railsrefutemethods] === Configurable attributes |=== @@ -4873,6 +5238,7 @@ refute_equal true, false | Array |=== +[#railsrelativedateconstant] == Rails/RelativeDateConstant |=== @@ -4888,10 +5254,12 @@ refute_equal true, false Checks whether constant value isn't relative date. Because the relative date will be evaluated only once. +[#safety-railsrelativedateconstant] === Safety This cop's autocorrection is unsafe because its dependence on the constant is not corrected. +[#examples-railsrelativedateconstant] === Examples [source,ruby] @@ -4918,6 +5286,7 @@ class SomeClass end ---- +[#railsrenderinline] == Rails/RenderInline |=== @@ -4932,6 +5301,7 @@ end Looks for inline rendering within controller actions. +[#examples-railsrenderinline] === Examples [source,ruby] @@ -4955,10 +5325,12 @@ class ProductsController < ApplicationController end ---- +[#references-railsrenderinline] === References * https://rails.rubystyle.guide/#inline-rendering +[#railsrenderplaintext] == Rails/RenderPlainText |=== @@ -4974,6 +5346,7 @@ end Identifies places where `render text:` can be replaced with `render plain:`. +[#examples-railsrenderplaintext] === Examples [source,ruby] @@ -4988,6 +5361,7 @@ render plain: 'Ruby!' render text: 'Ruby!', content_type: 'text/html' ---- +[#contenttypecompatibility_-true-_default_-railsrenderplaintext] ==== ContentTypeCompatibility: true (default) [source,ruby] @@ -4996,6 +5370,7 @@ render text: 'Ruby!', content_type: 'text/html' render text: 'Ruby!' ---- +[#contenttypecompatibility_-false-railsrenderplaintext] ==== ContentTypeCompatibility: false [source,ruby] @@ -5004,6 +5379,7 @@ render text: 'Ruby!' render text: 'Ruby!' ---- +[#configurable-attributes-railsrenderplaintext] === Configurable attributes |=== @@ -5014,10 +5390,12 @@ render text: 'Ruby!' | Boolean |=== +[#references-railsrenderplaintext] === References * https://rails.rubystyle.guide/#plain-text-rendering +[#railsrequestreferer] == Rails/RequestReferer |=== @@ -5033,8 +5411,10 @@ render text: 'Ruby!' Checks for consistent uses of `request.referer` or `request.referrer`, depending on the cop's configuration. +[#examples-railsrequestreferer] === Examples +[#enforcedstyle_-referer-_default_-railsrequestreferer] ==== EnforcedStyle: referer (default) [source,ruby] @@ -5046,6 +5426,7 @@ request.referrer request.referer ---- +[#enforcedstyle_-referrer-railsrequestreferer] ==== EnforcedStyle: referrer [source,ruby] @@ -5057,6 +5438,7 @@ request.referer request.referrer ---- +[#configurable-attributes-railsrequestreferer] === Configurable attributes |=== @@ -5067,8 +5449,11 @@ request.referrer | `referer`, `referrer` |=== +[#railsrequiredependency] == Rails/RequireDependency +NOTE: Required Rails version: 6.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -5090,6 +5475,7 @@ Applications running in Zeitwerk mode should not use `require_dependency`. NOTE: This cop is disabled by default. Please enable it if you are using Zeitwerk mode. +[#examples-railsrequiredependency] === Examples [source,ruby] @@ -5098,12 +5484,16 @@ NOTE: This cop is disabled by default. Please enable it if you are using Zeitwer require_dependency 'some_lib' ---- +[#references-railsrequiredependency] === References * https://guides.rubyonrails.org/autoloading_and_reloading_constants.html +[#railsresponseparsedbody] == Rails/ResponseParsedBody +NOTE: Required Rails version: 5.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -5116,6 +5506,7 @@ require_dependency 'some_lib' Prefer `response.parsed_body` to custom parsing logic for `response.body`. +[#safety-railsresponseparsedbody] === Safety This cop is unsafe because Content-Type may not be `application/json` or `text/html`. @@ -5123,6 +5514,7 @@ For example, the proprietary Content-Type provided by corporate entities such as `application/vnd.github+json` is not supported at `response.parsed_body` by default, so you still have to use `JSON.parse(response.body)` there. +[#examples-railsresponseparsedbody] === Examples [source,ruby] @@ -5140,6 +5532,7 @@ Nokogiri::HTML5.parse(response.body) response.parsed_body ---- +[#configurable-attributes-railsresponseparsedbody] === Configurable attributes |=== @@ -5150,6 +5543,7 @@ response.parsed_body | Array |=== +[#railsreversiblemigration] == Rails/ReversibleMigration |=== @@ -5165,6 +5559,7 @@ response.parsed_body Checks whether the change method of the migration file is reversible. +[#examples-railsreversiblemigration] === Examples [source,ruby] @@ -5328,6 +5723,7 @@ def change end ---- +[#configurable-attributes-railsreversiblemigration] === Configurable attributes |=== @@ -5338,11 +5734,13 @@ end | Array |=== +[#references-railsreversiblemigration] === References * https://rails.rubystyle.guide#reversible-migration * https://api.rubyonrails.org/classes/ActiveRecord/Migration/CommandRecorder.html +[#railsreversiblemigrationmethoddefinition] == Rails/ReversibleMigrationMethodDefinition |=== @@ -5359,6 +5757,7 @@ Checks whether the migration implements either a `change` method or both an `up` and a `down` method. +[#examples-railsreversiblemigrationmethoddefinition] === Examples [source,ruby] @@ -5399,6 +5798,7 @@ class SomeMigration < ActiveRecord::Migration[6.0] end ---- +[#configurable-attributes-railsreversiblemigrationmethoddefinition] === Configurable attributes |=== @@ -5409,6 +5809,7 @@ end | Array |=== +[#railsrootjoinchain] == Rails/RootJoinChain |=== @@ -5423,6 +5824,7 @@ end Use a single `#join` instead of chaining on `Rails.root` or `Rails.public_path`. +[#examples-railsrootjoinchain] === Examples [source,ruby] @@ -5440,6 +5842,7 @@ Rails.public_path.join('path', 'file.pdf') Rails.public_path.join('path', to, 'file.pdf') ---- +[#railsrootpathnamemethods] == Rails/RootPathnameMethods |=== @@ -5460,11 +5863,13 @@ so we can apply many IO methods directly. This cop works best when used together with `Style/FileRead`, `Style/FileWrite` and `Rails/RootJoinChain`. +[#safety-railsrootpathnamemethods] === Safety This cop is unsafe for autocorrection because ``Dir``'s `children`, `each_child`, `entries`, and `glob` methods return string element, but these methods of `Pathname` return `Pathname` element. +[#examples-railsrootpathnamemethods] === Examples [source,ruby] @@ -5489,6 +5894,7 @@ Rails.root.join('db', 'schema.rb').binwrite(content) Rails.root.glob("db/schema.rb") ---- +[#railsrootpublicpath] == Rails/RootPublicPath |=== @@ -5503,6 +5909,7 @@ Rails.root.glob("db/schema.rb") Favor `Rails.public_path` over `Rails.root` with `'public'` +[#examples-railsrootpublicpath] === Examples [source,ruby] @@ -5518,6 +5925,7 @@ Rails.public_path.join('file.pdf') Rails.public_path.join('file.pdf') ---- +[#railssafenavigation] == Rails/SafeNavigation NOTE: Required Ruby version: 2.3 @@ -5536,8 +5944,10 @@ Converts usages of `try!` to `&.`. It can also be configured to convert `try`. It will convert code to use safe navigation if the target Ruby version is set to 2.3+ +[#examples-railssafenavigation] === Examples +[#converttry_-false-_default_-railssafenavigation] ==== ConvertTry: false (default) [source,ruby] @@ -5559,6 +5969,7 @@ foo&.bar(baz) foo&.bar { |e| e.baz } ---- +[#converttry_-true-railssafenavigation] ==== ConvertTry: true [source,ruby] @@ -5577,6 +5988,7 @@ foo&.bar(baz) foo&.bar { |e| e.baz } ---- +[#configurable-attributes-railssafenavigation] === Configurable attributes |=== @@ -5587,6 +5999,7 @@ foo&.bar { |e| e.baz } | Boolean |=== +[#railssafenavigationwithblank] == Rails/SafeNavigationWithBlank |=== @@ -5602,6 +6015,7 @@ foo&.bar { |e| e.baz } Checks to make sure safe navigation isn't used with `blank?` in a conditional. +[#safety-railssafenavigationwithblank] === Safety While the safe navigation operator is generally a good idea, when @@ -5616,6 +6030,7 @@ foo&.blank? #=> nil foo.blank? #=> true ---- +[#examples-railssafenavigationwithblank] === Examples [source,ruby] @@ -5629,6 +6044,7 @@ do_something if foo.blank? do_something unless foo.blank? ---- +[#railssavebang] == Rails/SaveBang |=== @@ -5663,6 +6079,7 @@ that behavior can be turned off with `AllowImplicitReturn: false`. You can permit receivers that are giving false positives with `AllowedReceivers: []` +[#safety-railssavebang] === Safety This cop's autocorrection is unsafe because a custom `update` method call would be changed to `update!`, @@ -5683,6 +6100,7 @@ end update ---- +[#examples-railssavebang] === Examples [source,ruby] @@ -5712,6 +6130,7 @@ def save_user end ---- +[#allowimplicitreturn_-true-_default_-railssavebang] ==== AllowImplicitReturn: true (default) [source,ruby] @@ -5724,6 +6143,7 @@ def save_user end ---- +[#allowimplicitreturn_-false-railssavebang] ==== AllowImplicitReturn: false [source,ruby] @@ -5746,6 +6166,7 @@ def save_user end ---- +[#allowedreceivers_-__merchant_customers__-_service__mailer__-railssavebang] ==== AllowedReceivers: ['merchant.customers', 'Service::Mailer'] [source,ruby] @@ -5768,6 +6189,7 @@ Services::Service::Mailer.update(message: 'Message') Service::Mailer::update ---- +[#configurable-attributes-railssavebang] === Configurable attributes |=== @@ -5782,10 +6204,12 @@ Service::Mailer::update | Array |=== +[#references-railssavebang] === References * https://rails.rubystyle.guide#save-bang +[#railsschemacomment] == Rails/SchemaComment |=== @@ -5801,6 +6225,7 @@ Service::Mailer::update Enforces the use of the `comment` option when adding a new table or column to the database during a migration. +[#examples-railsschemacomment] === Examples [source,ruby] @@ -5820,6 +6245,7 @@ create_table :table, comment: 'Table of offenses data' do |t| end ---- +[#railsscopeargs] == Rails/ScopeArgs |=== @@ -5835,6 +6261,7 @@ end Checks for scope calls where it was passed a method (usually a scope) instead of a lambda/proc. +[#examples-railsscopeargs] === Examples [source,ruby] @@ -5846,6 +6273,7 @@ scope :something, where(something: true) scope :something, -> { where(something: true) } ---- +[#configurable-attributes-railsscopeargs] === Configurable attributes |=== @@ -5856,6 +6284,7 @@ scope :something, -> { where(something: true) } | Array |=== +[#railsselectmap] == Rails/SelectMap |=== @@ -5873,11 +6302,13 @@ These can be replaced with `pluck(:column_name)`. There also should be some performance improvement since it skips instantiating the model class for matches. +[#safety-railsselectmap] === Safety This cop is unsafe because the model might override the attribute getter. Additionally, the model's `after_initialize` hooks are skipped when using `pluck`. +[#examples-railsselectmap] === Examples [source,ruby] @@ -5889,6 +6320,7 @@ Model.select(:column_name).map(&:column_name) Model.pluck(:column_name) ---- +[#railsshorti18n] == Rails/ShortI18n |=== @@ -5911,6 +6343,7 @@ calls are added as offenses. When the EnforcedStyle is aggressive then all `translate` and `localize` calls without a receiver are added as offenses. +[#examples-railsshorti18n] === Examples [source,ruby] @@ -5924,6 +6357,7 @@ I18n.t :key I18n.l Time.now ---- +[#enforcedstyle_-conservative-_default_-railsshorti18n] ==== EnforcedStyle: conservative (default) [source,ruby] @@ -5935,6 +6369,7 @@ t :key l Time.now ---- +[#enforcedstyle_-aggressive-railsshorti18n] ==== EnforcedStyle: aggressive [source,ruby] @@ -5948,6 +6383,7 @@ t :key l Time.now ---- +[#configurable-attributes-railsshorti18n] === Configurable attributes |=== @@ -5958,10 +6394,12 @@ l Time.now | `conservative`, `aggressive` |=== +[#references-railsshorti18n] === References * https://rails.rubystyle.guide/#short-i18n +[#railsskipsmodelvalidations] == Rails/SkipsModelValidations |=== @@ -5980,10 +6418,12 @@ https://guides.rubyonrails.org/active_record_validations.html#skipping-validatio Methods may be ignored from this rule by configuring a `AllowedMethods`. +[#safety-railsskipsmodelvalidations] === Safety This cop is unsafe if the receiver object is not an Active Record object. +[#examples-railsskipsmodelvalidations] === Examples [source,ruby] @@ -6005,6 +6445,7 @@ user.update(website: 'example.com') FileUtils.touch('file') ---- +[#allowedmethods_-__touch__-railsskipsmodelvalidations] ==== AllowedMethods: ["touch"] [source,ruby] @@ -6018,6 +6459,7 @@ person.toggle :active user.touch ---- +[#configurable-attributes-railsskipsmodelvalidations] === Configurable attributes |=== @@ -6032,10 +6474,12 @@ user.touch | Array |=== +[#references-railsskipsmodelvalidations] === References * https://guides.rubyonrails.org/active_record_validations.html#skipping-validations +[#railssquishedsqlheredocs] == Rails/SquishedSQLHeredocs |=== @@ -6050,11 +6494,13 @@ user.touch Checks SQL heredocs to use `.squish`. +[#safety-railssquishedsqlheredocs] === Safety Some SQL syntax (e.g. PostgreSQL comments and functions) requires newlines to be preserved in order to work, thus autocorrection for this cop is not safe. +[#examples-railssquishedsqlheredocs] === Examples [source,ruby] @@ -6090,10 +6536,12 @@ execute(<<~SQL.squish, "Post Load") SQL ---- +[#references-railssquishedsqlheredocs] === References * https://rails.rubystyle.guide/#squished-heredocs +[#railsstripheredoc] == Rails/StripHeredoc NOTE: Required Ruby version: 2.3 @@ -6110,6 +6558,7 @@ NOTE: Required Ruby version: 2.3 Enforces the use of squiggly heredoc over `strip_heredoc`. +[#examples-railsstripheredoc] === Examples [source,ruby] @@ -6130,10 +6579,12 @@ EOS EOS ---- +[#references-railsstripheredoc] === References * https://rails.rubystyle.guide/#prefer-squiggly-heredoc +[#railstablenameassignment] == Rails/TableNameAssignment |=== @@ -6163,6 +6614,7 @@ https://api.rubyonrails.org/classes/ActiveRecord/ModelSchema.html#method-c-table STI base classes named `Base` are ignored by this cop. For more information: https://api.rubyonrails.org/classes/ActiveRecord/Inheritance.html +[#examples-railstablenameassignment] === Examples [source,ruby] @@ -6172,6 +6624,7 @@ self.table_name = 'some_table_name' self.table_name = :some_other_name ---- +[#configurable-attributes-railstablenameassignment] === Configurable attributes |=== @@ -6182,10 +6635,12 @@ self.table_name = :some_other_name | Array |=== +[#references-railstablenameassignment] === References * https://rails.rubystyle.guide/#keep-ar-defaults +[#railsthreestatebooleancolumn] == Rails/ThreeStateBooleanColumn |=== @@ -6201,6 +6656,7 @@ self.table_name = :some_other_name Enforces that boolean columns are created with default values (`false` or `true`) and `NOT NULL` constraint. +[#examples-railsthreestatebooleancolumn] === Examples [source,ruby] @@ -6216,6 +6672,7 @@ t.column :active, :boolean, default: true, null: false t.boolean :active, default: true, null: false ---- +[#configurable-attributes-railsthreestatebooleancolumn] === Configurable attributes |=== @@ -6226,10 +6683,12 @@ t.boolean :active, default: true, null: false | Array |=== +[#references-railsthreestatebooleancolumn] === References * https://rails.rubystyle.guide/#three-state-boolean +[#railstimezone] == Rails/TimeZone |=== @@ -6253,10 +6712,12 @@ then only use of `Time.zone` is allowed. When EnforcedStyle is 'flexible' then it's also allowed to use `Time#in_time_zone`. +[#safety-railstimezone] === Safety This cop's autocorrection is unsafe because it may change handling time. +[#examples-railstimezone] === Examples [source,ruby] @@ -6271,8 +6732,11 @@ Time.current Time.zone.now Time.zone.parse('2015-03-02T19:05:37') Time.zone.parse('2015-03-02T19:05:37Z') # Respect ISO 8601 format with timezone specifier. +Time.parse('2015-03-02T19:05:37Z') # Also respects ISO 8601 +'2015-03-02T19:05:37Z'.to_time # Also respects ISO 8601 ---- +[#enforcedstyle_-flexible-_default_-railstimezone] ==== EnforcedStyle: flexible (default) [source,ruby] @@ -6283,6 +6747,7 @@ Time.zone.parse('2015-03-02T19:05:37Z') # Respect ISO 8601 format with timezone Time.at(timestamp).in_time_zone ---- +[#enforcedstyle_-strict-railstimezone] ==== EnforcedStyle: strict [source,ruby] @@ -6293,6 +6758,7 @@ Time.at(timestamp).in_time_zone Time.at(timestamp).in_time_zone ---- +[#configurable-attributes-railstimezone] === Configurable attributes |=== @@ -6307,11 +6773,13 @@ Time.at(timestamp).in_time_zone | Array |=== +[#references-railstimezone] === References * https://rails.rubystyle.guide#time * http://danilenko.org/2012/7/6/rails_timezones +[#railstimezoneassignment] == Rails/TimeZoneAssignment |=== @@ -6331,6 +6799,7 @@ unexpected behavior at a later time. Using `Time.use_zone` ensures the code passed in the block is the only place Time.zone is affected. It eliminates the possibility of a `zone` sticking around longer than intended. +[#examples-railstimezoneassignment] === Examples [source,ruby] @@ -6343,6 +6812,7 @@ Time.use_zone('EST') do end ---- +[#configurable-attributes-railstimezoneassignment] === Configurable attributes |=== @@ -6353,12 +6823,16 @@ end | Array |=== +[#references-railstimezoneassignment] === References * https://thoughtbot.com/blog/its-about-time-zones +[#railstoformatteds] == Rails/ToFormattedS +NOTE: Required Rails version: 7.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -6372,8 +6846,10 @@ end Checks for consistent uses of `to_fs` or `to_formatted_s`, depending on the cop's configuration. +[#examples-railstoformatteds] === Examples +[#enforcedstyle_-to_fs-_default_-railstoformatteds] ==== EnforcedStyle: to_fs (default) [source,ruby] @@ -6385,6 +6861,7 @@ time.to_formatted_s(:db) time.to_fs(:db) ---- +[#enforcedstyle_-to_formatted_s-railstoformatteds] ==== EnforcedStyle: to_formatted_s [source,ruby] @@ -6396,6 +6873,7 @@ time.to_fs(:db) time.to_formatted_s(:db) ---- +[#configurable-attributes-railstoformatteds] === Configurable attributes |=== @@ -6406,12 +6884,16 @@ time.to_formatted_s(:db) | `to_fs`, `to_formatted_s` |=== +[#references-railstoformatteds] === References * https://rails.rubystyle.guide/#prefer-to-fs +[#railstoswithargument] == Rails/ToSWithArgument +NOTE: Required Rails version: 7.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -6424,11 +6906,13 @@ time.to_formatted_s(:db) Identifies passing any argument to `#to_s`. +[#safety-railstoswithargument] === Safety This cop is marked as unsafe because it may detect `#to_s` calls that are not related to Active Support implementation. +[#examples-railstoswithargument] === Examples [source,ruby] @@ -6440,8 +6924,11 @@ obj.to_s(:delimited) obj.to_formatted_s(:delimited) ---- +[#railstoplevelhashwithindifferentaccess] == Rails/TopLevelHashWithIndifferentAccess +NOTE: Required Rails version: 5.1 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -6455,6 +6942,7 @@ obj.to_formatted_s(:delimited) Identifies top-level `HashWithIndifferentAccess`. This has been soft-deprecated since Rails 5.1. +[#examples-railstoplevelhashwithindifferentaccess] === Examples [source,ruby] @@ -6466,6 +6954,7 @@ HashWithIndifferentAccess.new(foo: 'bar') ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') ---- +[#configurable-attributes-railstoplevelhashwithindifferentaccess] === Configurable attributes |=== @@ -6476,10 +6965,12 @@ ActiveSupport::HashWithIndifferentAccess.new(foo: 'bar') | String |=== +[#references-railstoplevelhashwithindifferentaccess] === References * https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#top-level-hashwithindifferentaccess-is-soft-deprecated +[#railstransactionexitstatement] == Rails/TransactionExitStatement |=== @@ -6504,6 +6995,11 @@ desired. If you are defining custom transaction methods, you can configure it with `TransactionMethods`. +NOTE: This cop is disabled on Rails >= 7.2 because transactions were restored +to their historical behavior. In Rails 7.1, the behavior is controlled with +the config `active_record.commit_transaction_on_non_local_return`. + +[#examples-railstransactionexitstatement] === Examples [source,ruby] @@ -6546,6 +7042,7 @@ ApplicationRecord.transaction do end ---- +[#transactionmethods_-__custom_transaction__-railstransactionexitstatement] ==== TransactionMethods: ["custom_transaction"] [source,ruby] @@ -6556,6 +7053,7 @@ CustomModel.custom_transaction do end ---- +[#configurable-attributes-railstransactionexitstatement] === Configurable attributes |=== @@ -6566,10 +7064,12 @@ end | Array |=== +[#references-railstransactionexitstatement] === References * https://github.com/rails/rails/commit/15aa4200e083 +[#railsuniqbeforepluck] == Rails/UniqBeforePluck |=== @@ -6597,13 +7097,16 @@ as the cop cannot distinguish between calls to `pluck` on an ActiveRecord::Relation vs a call to pluck on an ActiveRecord::Associations::CollectionProxy. +[#safety-railsuniqbeforepluck] === Safety This cop is unsafe for autocorrection because the behavior may change depending on the database collation. +[#examples-railsuniqbeforepluck] === Examples +[#enforcedstyle_-conservative-_default_-railsuniqbeforepluck] ==== EnforcedStyle: conservative (default) [source,ruby] @@ -6615,6 +7118,7 @@ Album.pluck(:band_name).uniq Album.distinct.pluck(:band_name) ---- +[#enforcedstyle_-aggressive-railsuniqbeforepluck] ==== EnforcedStyle: aggressive [source,ruby] @@ -6634,6 +7138,7 @@ Album.distinct.where(year: 1985).pluck(:band_name) customer.favourites.distinct.pluck(:color) ---- +[#configurable-attributes-railsuniqbeforepluck] === Configurable attributes |=== @@ -6644,6 +7149,7 @@ customer.favourites.distinct.pluck(:color) | `conservative`, `aggressive` |=== +[#railsuniquevalidationwithoutindex] == Rails/UniqueValidationWithoutIndex |=== @@ -6667,6 +7173,7 @@ the query will be heavy. Note that the cop does nothing if db/schema.rb does not exist. +[#examples-railsuniquevalidationwithoutindex] === Examples [source,ruby] @@ -6681,6 +7188,7 @@ validates :account, uniqueness: true validates :account, length: { minimum: MIN_LENGTH } ---- +[#configurable-attributes-railsuniquevalidationwithoutindex] === Configurable attributes |=== @@ -6691,6 +7199,7 @@ validates :account, length: { minimum: MIN_LENGTH } | Array |=== +[#railsunknownenv] == Rails/UnknownEnv |=== @@ -6709,6 +7218,7 @@ By default the cop allows three environments which Rails ships with: `development`, `test`, and `production`. More can be added to the `Environments` config parameter. +[#examples-railsunknownenv] === Examples [source,ruby] @@ -6722,6 +7232,7 @@ Rails.env.production? Rails.env == 'production' ---- +[#configurable-attributes-railsunknownenv] === Configurable attributes |=== @@ -6736,6 +7247,7 @@ Rails.env == 'production' | Array |=== +[#railsunusedignoredcolumns] == Rails/UnusedIgnoredColumns |=== @@ -6758,6 +7270,7 @@ this cop can cause `ignored_columns` to be removed even though the production sc the column, which can lead to downtime when the migration is actually executed. Only enable this cop if you know your migrations will be run before any of your Rails applications boot with the modified code. +[#examples-railsunusedignoredcolumns] === Examples [source,ruby] @@ -6773,6 +7286,7 @@ class User < ApplicationRecord end ---- +[#configurable-attributes-railsunusedignoredcolumns] === Configurable attributes |=== @@ -6783,6 +7297,7 @@ end | Array |=== +[#railsunusedrendercontent] == Rails/UnusedRenderContent |=== @@ -6800,6 +7315,7 @@ it will be dropped from the response. This cop checks for uses of `render` which specify both body content and a non-content status. +[#examples-railsunusedrendercontent] === Examples [source,ruby] @@ -6813,6 +7329,7 @@ head :continue head 100 ---- +[#configurable-attributes-railsunusedrendercontent] === Configurable attributes |=== @@ -6823,6 +7340,7 @@ head 100 | String |=== +[#railsvalidation] == Rails/Validation |=== @@ -6837,6 +7355,7 @@ head 100 Checks for the use of old-style attribute validation macros. +[#examples-railsvalidation] === Examples [source,ruby] @@ -6870,6 +7389,7 @@ validates :foo, length: true validates :foo, uniqueness: true ---- +[#configurable-attributes-railsvalidation] === Configurable attributes |=== @@ -6880,6 +7400,7 @@ validates :foo, uniqueness: true | Array |=== +[#railswhereequals] == Rails/WhereEquals |=== @@ -6896,11 +7417,13 @@ Identifies places where manually constructed SQL in `where` and `where.not` can be replaced with `where(attribute: value)` and `where.not(attribute: value)`. +[#safety-railswhereequals] === Safety This cop's autocorrection is unsafe because is may change SQL. See: https://github.com/rubocop/rubocop-rails/issues/403 +[#examples-railswhereequals] === Examples [source,ruby] @@ -6922,10 +7445,12 @@ User.where(name: ['john', 'jane']) User.where(users: { name: 'Gabe' }) ---- +[#references-railswhereequals] === References * https://rails.rubystyle.guide/#hash-conditions +[#railswhereexists] == Rails/WhereExists |=== @@ -6946,6 +7471,7 @@ then the cop enforces `exists?(...)` over `where(...).exists?`. When EnforcedStyle is 'where' then the cop enforces `where(...).exists?` over `exists?(...)`. +[#safety-railswhereexists] === Safety This cop is unsafe for autocorrection because the behavior may change on the following case: @@ -6959,8 +7485,10 @@ Author.includes(:articles).exists?(articles: {id: id}) #=> Perform `preload` behavior and `ActiveRecord::StatementInvalid` error occurs. ---- +[#examples-railswhereexists] === Examples +[#enforcedstyle_-exists-_default_-railswhereexists] ==== EnforcedStyle: exists (default) [source,ruby] @@ -6977,6 +7505,7 @@ User.where('length(name) > 10').exists? user.posts.exists?(published: true) ---- +[#enforcedstyle_-where-railswhereexists] ==== EnforcedStyle: where [source,ruby] @@ -6994,6 +7523,7 @@ user.posts.where(published: true).exists? User.where('length(name) > 10').exists? ---- +[#configurable-attributes-railswhereexists] === Configurable attributes |=== @@ -7004,8 +7534,11 @@ User.where('length(name) > 10').exists? | `exists`, `where` |=== +[#railswheremissing] == Rails/WhereMissing +NOTE: Required Rails version: 6.1 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -7020,6 +7553,7 @@ Use `where.missing(...)` to find missing relationship records. This cop is enabled in Rails 6.1 or higher. +[#examples-railswheremissing] === Examples [source,ruby] @@ -7031,10 +7565,12 @@ Post.left_joins(:author).where(authors: { id: nil }) Post.where.missing(:author) ---- +[#references-railswheremissing] === References * https://rails.rubystyle.guide/#finding-missing-relationship-records +[#railswherenot] == Rails/WhereNot |=== @@ -7050,6 +7586,7 @@ Post.where.missing(:author) Identifies places where manually constructed SQL in `where` can be replaced with `where.not(...)`. +[#examples-railswherenot] === Examples [source,ruby] @@ -7071,10 +7608,12 @@ User.where.not(name: ['john', 'jane']) User.where.not(users: { name: 'Gabe' }) ---- +[#references-railswherenot] === References * https://rails.rubystyle.guide/#hash-conditions +[#railswherenotwithmultipleconditions] == Rails/WhereNotWithMultipleConditions |=== @@ -7095,6 +7634,7 @@ The behavior of `where.not` changed in Rails 6.1. Prior to the change, From Rails 6.1 onwards, this executes the query `WHERE NOT (trashed == TRUE AND roles == 'admin')`. +[#examples-railswherenotwithmultipleconditions] === Examples [source,ruby] @@ -7111,6 +7651,7 @@ User.where.not(trashed: true).where.not(role: ['moderator', 'admin']) User.where.not('trashed = ? OR role = ?', true, 'admin') ---- +[#configurable-attributes-railswherenotwithmultipleconditions] === Configurable attributes |=== @@ -7121,14 +7662,18 @@ User.where.not('trashed = ? OR role = ?', true, 'admin') | String |=== +[#references-railswherenotwithmultipleconditions] === References * https://rails.rubystyle.guide/#where-not-with-multiple-attributes +[#railswhererange] == Rails/WhereRange NOTE: Required Ruby version: 2.6 +NOTE: Required Rails version: 6.0 + |=== | Enabled by default | Safe | Supports autocorrection | Version Added | Version Changed @@ -7142,6 +7687,7 @@ NOTE: Required Ruby version: 2.6 Identifies places where manually constructed SQL in `where` can be replaced with ranges. +[#safety-railswhererange] === Safety This cop's autocorrection is unsafe because it can change the query @@ -7151,6 +7697,7 @@ implicitly attach the `end_at` column to the `events` table. But when autocorrec `Booking.joins(:events).where(end_at: ...Time.current)`, it will now be incorrectly explicitly attached to the `bookings` table. +[#examples-railswhererange] === Examples [source,ruby] @@ -7175,6 +7722,7 @@ User.where(users: { age: 18.. }) User.where('age > ?', 18) ---- +[#references-railswhererange] === References * https://rails.rubystyle.guide/#where-ranges diff --git a/lib/rubocop/rails/version.rb b/lib/rubocop/rails/version.rb index 15095dece0..090716add8 100644 --- a/lib/rubocop/rails/version.rb +++ b/lib/rubocop/rails/version.rb @@ -4,7 +4,7 @@ module RuboCop module Rails # This module holds the RuboCop Rails version information. module Version - STRING = '2.26.2' + STRING = '2.27.0' def self.document_version STRING.match('\d+\.\d+').to_s diff --git a/relnotes/v2.27.0.md b/relnotes/v2.27.0.md new file mode 100644 index 0000000000..6abf1141b1 --- /dev/null +++ b/relnotes/v2.27.0.md @@ -0,0 +1,15 @@ +### Bug fixes + +* [#1377](https://github.com/rubocop/rubocop-rails/issues/1377): Fix an error for `Rails/EnumSyntax` when positional arguments are used and options are not passed as keyword arguments. ([@koic][]) +* [#1367](https://github.com/rubocop/rubocop-rails/pull/1367): Fix `Rails/TimeZone` should not report offense on `String#to_time` with timezone specifier. ([@armandmgt][]) + +### Changes + +* [#727](https://github.com/rubocop/rubocop-rails/issues/727): Disable `Rails/TransactionExitStatement` on Rails >= 7.2. ([@earlopain][]) +* [#1374](https://github.com/rubocop/rubocop-rails/pull/1374): Change `Rails/EnvLocal` to handle negated conditions. ([@fatkodima][]) +* [#1195](https://github.com/rubocop/rubocop-rails/issues/1195): Change `Rails/SelectMap` to handle safe navigation operators. ([@fatkodima][]) + +[@koic]: https://github.com/koic +[@armandmgt]: https://github.com/armandmgt +[@earlopain]: https://github.com/earlopain +[@fatkodima]: https://github.com/fatkodima From 1d7f0c4ba127b15a2894fc3284078c64aef83ba0 Mon Sep 17 00:00:00 2001 From: Koichi ITO Date: Sat, 26 Oct 2024 17:18:23 +0900 Subject: [PATCH 52/52] Switch back docs version to master --- docs/antora.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/antora.yml b/docs/antora.yml index f011548566..9e0ff48acb 100644 --- a/docs/antora.yml +++ b/docs/antora.yml @@ -2,6 +2,6 @@ name: rubocop-rails title: RuboCop Rails # We always provide version without patch here (e.g. 1.1), # as patch versions should not appear in the docs. -version: '2.27' +version: ~ nav: - modules/ROOT/nav.adoc