diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fe94d53f1..c1fb07bc0f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ * [#403](https://github.com/rubocop/rubocop-rails/pull/403): Mark `Rails/WhereEquals` as unsafe auto-correction. ([@koic][]) * [#379](https://github.com/rubocop/rubocop-rails/issues/379): Mark `Rails/DynamicFindBy` as unsafe. ([@koic][]) * [#106](https://github.com/rubocop/rubocop-rails/issues/106): Mark `Rails/ReflectionClassName` as unsafe. ([@koic][]) +* [#106](https://github.com/rubocop/rubocop-rails/issues/106): Make `Rails/ReflectionClassName` aware of the use of string with `to_s`. ([@koic][]) * [#456](https://github.com/rubocop/rubocop-rails/pull/456): Drop Ruby 2.4 support. ([@koic][]) * [#462](https://github.com/rubocop/rubocop-rails/pull/462): Require RuboCop 1.7 or higher. ([@koic][]) diff --git a/lib/rubocop/cop/rails/reflection_class_name.rb b/lib/rubocop/cop/rails/reflection_class_name.rb index 2cd3a0e52b..4c1e2bfcf0 100644 --- a/lib/rubocop/cop/rails/reflection_class_name.rb +++ b/lib/rubocop/cop/rails/reflection_class_name.rb @@ -18,6 +18,7 @@ module Rails class ReflectionClassName < Base MSG = 'Use a string value for `class_name`.' RESTRICT_ON_SEND = %i[has_many has_one belongs_to].freeze + ALLOWED_REFLECTION_CLASS_TYPES = %i[dstr str sym].freeze def_node_matcher :association_with_reflection, <<~PATTERN (send nil? {:has_many :has_one :belongs_to} _ _ ? @@ -26,7 +27,7 @@ class ReflectionClassName < Base PATTERN def_node_matcher :reflection_class_name, <<~PATTERN - (pair (sym :class_name) [!dstr !str !sym]) + (pair (sym :class_name) #reflection_class_value?) PATTERN def on_send(node) @@ -34,6 +35,16 @@ def on_send(node) add_offense(reflection_class_name.loc.expression) end end + + private + + def reflection_class_value?(class_value) + if class_value.send_type? + !class_value.method?(:to_s) || class_value.receiver.const_type? + else + !ALLOWED_REFLECTION_CLASS_TYPES.include?(class_value.type) + end + end end end end diff --git a/spec/rubocop/cop/rails/reflection_class_name_spec.rb b/spec/rubocop/cop/rails/reflection_class_name_spec.rb index 96716ba159..abd62608dd 100644 --- a/spec/rubocop/cop/rails/reflection_class_name_spec.rb +++ b/spec/rubocop/cop/rails/reflection_class_name_spec.rb @@ -16,6 +16,13 @@ RUBY end + it '.to_s' do + expect_offense(<<~RUBY) + has_many :accounts, class_name: Account.to_s + ^^^^^^^^^^^^^^^^^^^^^^^^ Use a string value for `class_name`. + RUBY + end + it 'has_one' do expect_offense(<<~RUBY) has_one :account, class_name: Account @@ -46,6 +53,12 @@ RUBY end + it 'does not register an offense when using `class_name: do_something.to_s`' do + expect_no_offenses(<<~'RUBY') + has_many :accounts, class_name: do_something.to_s + RUBY + end + it 'does not register an offense when using `foreign_key :account_id`' do expect_no_offenses(<<~RUBY) has_many :accounts, class_name: 'Account', foreign_key: :account_id