Class: RuboCop::Cop::Rails::BelongsTo

Inherits:
Base
  • Object
show all
Extended by:
AutoCorrector, TargetRailsVersion
Defined in:
lib/rubocop/cop/rails/belongs_to.rb

Overview

Looks for belongs_to associations where we control whether the association is required via the deprecated ‘required` option instead.

Since Rails 5, belongs_to associations are required by default and this can be controlled through the use of ‘optional: true`.

From the release notes:

belongs_to will now trigger a validation error by default if the
association is not present. You can turn this off on a
per-association basis with optional: true. Also deprecate required
option in favor of optional for belongs_to. (Pull Request)

In the case that the developer is doing ‘required: false`, we definitely want to autocorrect to `optional: true`.

However, without knowing whether they’ve set overridden the default value of ‘config.active_record.belongs_to_required_by_default`, we can’t say whether it’s safe to remove ‘required: true` or whether we should replace it with `optional: false` (or, similarly, remove a 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:

# bad
class Post < ApplicationRecord
  belongs_to :blog, required: false
end

# good
class Post < ApplicationRecord
  belongs_to :blog, optional: true
end

# bad
class Post < ApplicationRecord
  belongs_to :blog, required: true
end

# good
class Post < ApplicationRecord
  belongs_to :blog, optional: false
end

Constant Summary collapse

SUPERFLOUS_REQUIRE_FALSE_MSG =
'You specified `required: false`, in Rails > 5.0 the required ' \
'option is deprecated and you want to use `optional: true`.'
SUPERFLOUS_REQUIRE_TRUE_MSG =
'You specified `required: true`, in Rails > 5.0 the required ' \
'option is deprecated and you want to use `optional: false`. ' \
'In most configurations, this is the default and you can omit ' \
'this option altogether'
RESTRICT_ON_SEND =
%i[belongs_to].freeze

Constants included from TargetRailsVersion

TargetRailsVersion::TARGET_GEM_NAME, TargetRailsVersion::USES_REQUIRES_GEM_API

Instance Method Summary collapse

Methods included from TargetRailsVersion

minimum_target_rails_version, support_target_rails_version?

Instance Method Details

#on_send(node) ⇒ Object



73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rubocop/cop/rails/belongs_to.rb', line 73

def on_send(node)
  match_belongs_to_with_options(node) do |option_node, option_value|
    message, replacement =
      if option_value.true_type?
        [SUPERFLOUS_REQUIRE_TRUE_MSG, 'optional: false']
      elsif option_value.false_type?
        [SUPERFLOUS_REQUIRE_FALSE_MSG, 'optional: true']
      end

    add_offense(node.loc.selector, message: message) do |corrector|
      corrector.replace(option_node, replacement)
    end
  end
end