Reputation: 8627
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
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