Class: RuboCop::Cop::Rails::SaveBang
- Includes:
- NegativeConditional
- 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 allow:
-
update or save calls, assigned to a variable, or used as a condition in an if/unless/case statement.
-
create calls, assigned to a variable that then has a call to ‘persisted?`.
-
calls if the result is explicitly returned from methods and blocks, or provided as arguments.
-
calls whose signature doesn’t look like an ActiveRecord persistence method.
By default it will also allow implicit returns from methods and blocks. that behavior can be turned off with ‘AllowImplicitReturn: false`.
You can permit receivers that are giving false positives with ‘AllowedReceivers: []`
Constant Summary collapse
- MSG =
'Use `%<prefer>s` instead of `%<current>s` if the return ' \ 'value is not checked.'.freeze
- CREATE_MSG =
(MSG + ' Or check `persisted?` on model returned from ' \ '`%<current>s`.').freeze
- CREATE_CONDITIONAL_MSG =
'`%<current>s` returns a model which is ' \ 'always truthy.'.freeze
- CREATE_PERSIST_METHODS =
%i[create first_or_create find_or_create_by].freeze
- MODIFY_PERSIST_METHODS =
%i[save update update_attributes destroy].freeze
- PERSIST_METHODS =
(CREATE_PERSIST_METHODS + MODIFY_PERSIST_METHODS).freeze
Constants included from Util
Instance Attribute Summary
Attributes inherited from Cop
#config, #corrections, #offenses, #processed_source
Instance Method Summary collapse
- #after_leaving_scope(scope, _variable_table) ⇒ Object
- #autocorrect(node) ⇒ Object
- #check_assignment(assignment) ⇒ Object
- #join_force?(force_class) ⇒ Boolean
-
#on_send(node) ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity.
Methods included from NodePattern::Macros
#def_node_matcher, #def_node_search, #node_search, #node_search_all, #node_search_body, #node_search_first
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, lint?, match?, #message, #messages, non_rails, #parse, qualified_cop_name, #relevant_file?, #target_rails_version, #target_ruby_version
Methods included from AST::Sexp
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
Methods included from PathUtil
absolute?, 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
#after_leaving_scope(scope, _variable_table) ⇒ Object
121 122 123 124 125 126 127 |
# File 'lib/rubocop/cop/rails/save_bang.rb', line 121 def after_leaving_scope(scope, _variable_table) scope.variables.each_value do |variable| variable.assignments.each do |assignment| check_assignment(assignment) end end end |
#autocorrect(node) ⇒ Object
150 151 152 153 154 155 |
# File 'lib/rubocop/cop/rails/save_bang.rb', line 150 def autocorrect(node) save_loc = node.loc.selector new_method = "#{node.method_name}!" ->(corrector) { corrector.replace(save_loc, new_method) } end |
#check_assignment(assignment) ⇒ Object
129 130 131 132 133 134 135 136 137 |
# File 'lib/rubocop/cop/rails/save_bang.rb', line 129 def check_assignment(assignment) node = right_assignment_node(assignment) return unless node && node.send_type? return unless persist_method?(node, CREATE_PERSIST_METHODS) return if persisted_referenced?(assignment) add_offense_for_node(node, CREATE_MSG) end |
#join_force?(force_class) ⇒ Boolean
117 118 119 |
# File 'lib/rubocop/cop/rails/save_bang.rb', line 117 def join_force?(force_class) force_class == VariableForce end |
#on_send(node) ⇒ Object
rubocop:disable Metrics/CyclomaticComplexity
139 140 141 142 143 144 145 146 147 148 |
# File 'lib/rubocop/cop/rails/save_bang.rb', line 139 def on_send(node) # rubocop:disable Metrics/CyclomaticComplexity return unless persist_method?(node) return if return_value_assigned?(node) return if check_used_in_conditional(node) return if argument?(node) return if implicit_return?(node) return if explicit_return?(node) add_offense_for_node(node) end |