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

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

Overview

This cop 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

See Also:

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'

Constants included from Util

Util::LITERAL_REGEX

Instance Attribute Summary

Attributes inherited from Cop

#config, #corrections, #offenses, #processed_source

Instance Method Summary collapse

Methods included from TargetRailsVersion

minimum_target_rails_version, support_target_rails_version?

Methods inherited from Cop

#add_offense, all, autocorrect_incompatible_with, badge, #config_to_allow_offenses, #config_to_allow_offenses=, #cop_config, cop_name, #cop_name, #correct, department, #duplicate_location?, #excluded_file?, #find_location, #highlights, inherited, #initialize, #join_force?, lint?, match?, #message, #messages, non_rails, #parse, qualified_cop_name, #relevant_file?, #target_rails_version, #target_ruby_version

Methods included from NodePattern::Macros

#def_node_matcher, #def_node_search, #node_search, #node_search_all, #node_search_body, #node_search_first

Methods included from AST::Sexp

#s

Methods included from AutocorrectLogic

#autocorrect?, #autocorrect_enabled?, #autocorrect_requested?, #support_autocorrect?

Methods included from IgnoredNode

#ignore_node, #ignored_node?, #part_of_ignored_node?

Methods included from Util

begins_its_line?, comment_line?, double_quotes_required?, escape_string, first_part_of_call_chain, interpret_string_escapes, line_range, needs_escaping?, on_node, parentheses?, same_line?, to_string_literal, to_supported_styles, tokens, trim_string_interporation_escape_character

Methods included from PathUtil

absolute?, chdir, hidden_dir?, hidden_file_in_not_hidden_dir?, match_path?, pwd, relative_path, reset_pwd, smart_path

Constructor Details

This class inherits a constructor from RuboCop::Cop::Cop

Instance Method Details

#autocorrect(node) ⇒ Object



87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/rubocop/cop/rails/belongs_to.rb', line 87

def autocorrect(node)
  option_node, option_value = match_belongs_to_with_options(node)
  return unless option_node

  lambda do |corrector|
    if option_value.true_type?
      corrector.replace(option_node.loc.expression, 'optional: false')
    elsif option_value.false_type?
      corrector.replace(option_node.loc.expression, 'optional: true')
    end
  end
end

#on_send(node) ⇒ Object



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

def on_send(node)
  match_belongs_to_with_options(node) do |_option_node, option_value|
    message =
      if option_value.true_type?
        SUPERFLOUS_REQUIRE_TRUE_MSG
      elsif option_value.false_type?
        SUPERFLOUS_REQUIRE_FALSE_MSG
      end

    add_offense(node, message: message, location: :selector)
  end
end