class RuboCop::Cop::Rails::ActiveRecordCallbacksOrder
end
after_commit :after_commit_callback
before_validation :before_validation_callback
class Person < ApplicationRecord
# good
end
before_validation :before_validation_callback
after_commit :after_commit_callback
class Person < ApplicationRecord
# bad
@example
in the order in which they will be executed.
Checks that Active Record callbacks are declared
def autocorrect(corrector, node)
def autocorrect(corrector, node) previous = node.left_siblings.reverse_each.find do |sibling| callback?(sibling) end current_range = source_range_with_comment(node) previous_range = source_range_with_comment(previous) corrector.insert_before(previous_range, current_range.source) corrector.remove(current_range) end
def begin_pos_with_comment(node)
def begin_pos_with_comment(node) annotation_line = node.first_line - 1 first_comment = nil processed_source.each_comment_in_lines(0..annotation_line).reverse_each do |comment| if comment.location.line == annotation_line && !inline_comment?(comment) first_comment = comment annotation_line -= 1 end end start_line_position(first_comment || node) end
def buffer
def buffer processed_source.buffer end
def callback?(node)
def callback?(node) node.send_type? && CALLBACKS_ORDER_MAP.key?(node.method_name) end
def defined_callbacks(class_node)
def defined_callbacks(class_node) class_def = class_node.body if class_def class_def.each_child_node.select { |c| callback?(c) } else [] end end
def end_position_for(node)
def end_position_for(node) end_line = buffer.line_for_position(node.source_range.end_pos) buffer.line_range(end_line).end_pos end
def inline_comment?(comment)
def inline_comment?(comment) !comment_line?(comment.source_range.source_line) end
def on_class(class_node)
def on_class(class_node) previous_index = -1 previous_callback = nil defined_callbacks(class_node).each do |node| callback = node.method_name index = CALLBACKS_ORDER_MAP[callback] if index < previous_index message = format(MSG, current: callback, previous: previous_callback) add_offense(node, message: message) do |corrector| autocorrect(corrector, node) end end previous_index = index previous_callback = callback end end
def source_range_with_comment(node)
def source_range_with_comment(node) begin_pos = begin_pos_with_comment(node) end_pos = end_position_for(node) Parser::Source::Range.new(buffer, begin_pos, end_pos) end
def start_line_position(node)
def start_line_position(node) buffer.line_range(node.loc.line).begin_pos - 1 end