Steve Folly
Steve Folly

Reputation: 8627

Rails dependent (nullify or destroy) in one action

I have this following relationship between 2 models:

class Transaction < ApplicationRecord
  has_many :transfer_sources, dependent: :nullify, foreign_key: "transaction_source_id", class_name: "Transfer"
  has_many :transfer_dests, dependent: :nullify, foreign_key: "transaction_dest_id", class_name: "Transfer"
  ...
end

class Transfer < ApplicationRecord
  belongs_to :transaction_source, optional: true, class_name: "Transaction"
  belongs_to :transaction_dest, optional: true, class_name: "Transaction"
  ...
end

So in a Transfer record transaction_source or transaction_dest can be nil if the other one is set, the only invalid scenario would be to have both set to nil.

If both are set and I destroy one of the transactions, that's fine and I still want the Transfer to exist, the reference gets nulled.

But if I then destroy the other related transaction, then both transaction references will be nullified.

What I'd like to do in this case is automatically destroy the Transfer record if both transactions (source and dest) become nil.

I tried an after_update callback on Transfer, but nullifying the dependency doesn't seem to load the Transfer object into memory, it just executes the UPDATE SQL statement directly.

Upvotes: 0

Views: 48

Answers (1)

Taras
Taras

Reputation: 822

You can try something like this:

class Transfer < ApplicationRecord
  # ...
  scope :with_single_transaction, lambda {
    where(transaction_source_id: nil).or(where(transaction_dest_id: nil))
  }

  scope :related_to, lambda(transaction_id) {
    where(transaction_source_id: transaction_id).or(where(transaction_dest_id: transaction_id))
  }
  # ...
end

class Transaction < ApplicationRecord
  # ...
  before_destroy do
    ::Transfer.with_single_transaction.related_to(transaction_id: id).destroy_all
  end
  # ...
end

The before_destroy callback is wrapped into the database transaction. So if removing Transfer goes wrong at some point then removing the related Transaction will be rolled back.

Upvotes: 0

Related Questions