diff --git a/CHANGELOG.md b/CHANGELOG.md index d30b88e11e..351142220d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -519,3 +519,4 @@ [@leoarnold]: https://github.com/leoarnold [@TonyArra]: https://github.com/TonyArra [@tachyons]: https://github.com/tachyons +[@composerinteralia]: https://github.com/composerinteralia diff --git a/changelog/new_allow_ignoring_scopes_for_inverse_of_cop.md b/changelog/new_allow_ignoring_scopes_for_inverse_of_cop.md new file mode 100644 index 0000000000..7af5ed7d76 --- /dev/null +++ b/changelog/new_allow_ignoring_scopes_for_inverse_of_cop.md @@ -0,0 +1 @@ +* [#614](https://github.com/rubocop/rubocop-rails/pull/614): Add `IgnoreScopes` config option for `Rails/InverseOf` cop. ([@composerinteralia][]) diff --git a/config/default.yml b/config/default.yml index 1a17241683..22075396a1 100644 --- a/config/default.yml +++ b/config/default.yml @@ -453,6 +453,7 @@ Rails/InverseOf: Description: 'Checks for associations where the inverse cannot be determined automatically.' Enabled: true VersionAdded: '0.52' + IgnoreScopes: false Include: - app/models/**/*.rb diff --git a/lib/rubocop/cop/rails/inverse_of.rb b/lib/rubocop/cop/rails/inverse_of.rb index e5f08e85e9..892d213e70 100644 --- a/lib/rubocop/cop/rails/inverse_of.rb +++ b/lib/rubocop/cop/rails/inverse_of.rb @@ -126,6 +126,18 @@ module Rails # has_many :physicians, through: :appointments # end # + # @example IgnoreScopes: false (default) + # # bad + # class Blog < ApplicationRecord + # has_many :posts, -> { order(published_at: :desc) } + # end + # + # @example IgnoreScopes: true + # # good + # class Blog < ApplicationRecord + # has_many :posts, -> { order(published_at: :desc) } + # end + # # @see https://guides.rubyonrails.org/association_basics.html#bi-directional-associations # @see https://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#module-ActiveRecord::Associations::ClassMethods-label-Setting+Inverses class InverseOf < Base @@ -189,7 +201,7 @@ def on_send(node) end def scope?(arguments) - arguments.any?(&:block_type?) + !ignore_scopes? && arguments.any?(&:block_type?) end def options_requiring_inverse_of?(options) @@ -236,6 +248,10 @@ def message(options) SPECIFY_MSG end end + + def ignore_scopes? + cop_config['IgnoreScopes'] == true + end end end end diff --git a/spec/rubocop/cop/rails/inverse_of_spec.rb b/spec/rubocop/cop/rails/inverse_of_spec.rb index f0c88ff74c..d0e38df333 100644 --- a/spec/rubocop/cop/rails/inverse_of_spec.rb +++ b/spec/rubocop/cop/rails/inverse_of_spec.rb @@ -25,6 +25,18 @@ class Person end RUBY end + + context 'when `IgnoreScopes: true`' do + let(:cop_config) do + { 'IgnoreScopes' => true } + end + + it 'does not register an offense when not specifying `:inverse_of`' do + expect_no_offenses( + 'has_many :foo, -> () { where(bar: true) }' + ) + end + end end context 'with option preventing automatic inverse' do