Class: RuboCop::Cop::DevDoc::Rails::NoDeliverLaterInTransaction

Inherits:
Base
  • Object
show all
Defined in:
lib/rubocop/cop/dev_doc/rails/no_deliver_later_in_transaction.rb

Overview

Avoid ‘deliver_later` and `perform_later` inside a `transaction` block.

## Rationale Do not use ‘perform_later` or `deliver_later` inside a transaction block because there is a possibility that the job will use stale data, as the transaction has not yet completed (not yet committed changes to the database).


organization.transaction do
  if organization.save
    # This mailer may receive the organization with stale data
    # (data before `save()`)
    OrganizationMailer.with(organization: organization).deliver_later
  end
end

✔️
organization.transaction do
  save_succeeded = organization.save
end
if save_succeeded
  OrganizationMailer.with(organization: organization).deliver_later
end

## Watch out for indirect calls Some libraries call ‘perform_later` / `deliver_later` behind the scenes — e.g. `@user.send_verification_email!` from the Devise gem. This cop cannot detect those wrappers; reviewers should still flag them when they appear inside a `transaction` block.

Examples:

# bad
organization.transaction do
  organization.save!
  OrganizationMailer.with(organization: organization).deliver_later
end

# good
organization.transaction do
  organization.save!
end
OrganizationMailer.with(organization: organization).deliver_later

Constant Summary collapse

MSG =
'`%<method>s` inside a `transaction` block may use stale data. Move it outside the transaction.'.freeze
RESTRICT_ON_SEND =
%i[deliver_later perform_later].freeze

Instance Method Summary collapse

Instance Method Details

#on_send(node) ⇒ Object



52
53
54
55
56
# File 'lib/rubocop/cop/dev_doc/rails/no_deliver_later_in_transaction.rb', line 52

def on_send(node)
  return unless inside_transaction?(node)

  add_offense(node.loc.selector, message: format(MSG, method: node.method_name))
end