class RuboCop::Cop::Rails::BelongsTo
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.
@example
# 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 guides.rubyonrails.org/5_0_release_notes.html @see github.com/rails/rails/pull/18937
Constants
- RESTRICT_ON_SEND
- SUPERFLOUS_REQUIRE_FALSE_MSG
- SUPERFLOUS_REQUIRE_TRUE_MSG
Public Instance Methods
# File lib/rubocop/cop/rails/belongs_to.rb, line 76 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.loc.expression, replacement) end end end