Class: RuboCop::Cop::Rails::SaveBang

Inherits:
Cop
  • Object
show all
Defined in:
lib/rubocop/cop/rails/save_bang.rb

Overview

This cop identifies possible cases where Active Record save! or related should be used instead of save because the model might have failed to save and an exception is better than unhandled failure.

This will ignore calls that are assigned to a variable or used as the condition in an if/unless statement. It will also ignore any call with more than 2 arguments as that is likely not an Active Record call or if a Model.update(id, attributes) call.

Examples:


# bad
user.save
user.update(name: 'Joe')
user.find_or_create_by(name: 'Joe')
user.destroy

# good
unless user.save
   . . .
end
user.save!
user.update!(name: 'Joe')
user.find_or_create_by!(name: 'Joe')
user.destroy!

Constant Summary collapse

MSG =
'Use `%s` instead of `%s` if the return value is not checked.'
.freeze
PERSIST_METHODS =
[:save, :create, :update, :destroy,
:first_or_create, :find_or_create_by].freeze

Constants included from Util

Util::ASGN_NODES, Util::BYTE_ORDER_MARK, Util::EQUALS_ASGN_NODES, Util::LITERAL_REGEX, Util::OPERATOR_METHODS, Util::SHORTHAND_ASGN_NODES

Instance Attribute Summary

Attributes inherited from Cop

#config, #corrections, #offenses, #processed_source

Instance Method Summary collapse

Methods inherited from Cop

#add_offense, all, #config_to_allow_offenses, #config_to_allow_offenses=, #cop_config, #cop_name, cop_name, cop_type, #correct, #debug?, #details, #display_cop_names?, #display_style_guide?, #excluded_file?, #extra_details?, #highlights, inherited, #initialize, #join_force?, lint?, match?, #message, #messages, non_rails, #parse, qualified_cop_name, #reference_url, #relevant_file?, #style_guide_url, #target_ruby_version

Methods included from Sexp

#s

Methods included from NodePattern::Macros

#def_node_matcher, #def_node_search, #node_search_body

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?, block_length, comment_line?, directions, double_quotes_acceptable?, double_quotes_required?, effective_column, ends_its_line?, escape_string, first_part_of_call_chain, interpret_string_escapes, line_range, move_pos, needs_escaping?, numeric_range_size, on_node, operator?, parentheses?, parenthesized_call?, range_with_surrounding_comma, range_with_surrounding_space, source_range, strip_quotes, to_string_literal, to_symbol_literal, within_node?

Methods included from PathUtil

absolute?, match_path?, relative_path

Constructor Details

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

Instance Method Details

#autocorrect(node) ⇒ Object



50
51
52
53
54
55
# File 'lib/rubocop/cop/rails/save_bang.rb', line 50

def autocorrect(node)
  save_loc = node.loc.selector
  new_method = "#{node.method_name}!"

  ->(corrector) { corrector.replace(save_loc, new_method) }
end

#on_send(node) ⇒ Object



39
40
41
42
43
44
45
46
47
48
# File 'lib/rubocop/cop/rails/save_bang.rb', line 39

def on_send(node)
  return unless PERSIST_METHODS.include?(node.method_name)
  return if return_value_used?(node)
  return unless expected_signature?(node)

  add_offense(node, node.loc.selector,
              format(MSG,
                     "#{node.method_name}!",
                     node.method_name.to_s))
end