In my book model, I have a "before_destroy" callback (with a potentially ugly method) as follows:
before_destroy :destroy_fallback
private
def destroy_fallback
unless self.fallback?
format_fallback = BookFormat.find_by(fallback: true)
Book.where(book_format_id: self.id).update(book_format_id: format_fallback.id)
else
errors.add(:base, :undestroyable)
throw :abort
end
end
However when I test that this really happens, it doesn't seem to. This spec here results in an error (saying that the two id's are not the same): require 'rails_helper'
RSpec.describe BookFormat, type: :model do
before(:all) do
@book = create(:hobbit)
@book_format_default = create(:not_defined)
end
it 'should reassign to the fallback book_format if their book_format is deleted' do
format = @book.book_format
format.destroy
expect(@book.book_format.id).to eq(@book_format_default.id)
end
end
Looks like the destroy_fallback is never executed, i.e. the before_destroy callback is not used? In dev, when I do this via website - everything seems to works as desired.
CodePudding user response:
Might just be copy-paste error, but you don't seem to have a destroy_fallback
method in your model.
Make sure you're actually defining a method:
class Book < ApplicationRecord
before_destroy :destroy_fallback
...
private
def destroy_fallback
unless self.fallback?
format_fallback = BookFormat.find_by(fallback: true)
Book.where(book_format_id: self.id).update(book_format_id: format_fallback.id)
else
errors.add(:base, :undestroyable)
throw :abort
end
end
end
And, I find unless - else
to be really hard to reason about.
class Book < ApplicationRecord
before_destroy :destroy_fallback
...
private
def destroy_fallback
if self.fallback?
errors.add(:base, :undestroyable)
throw :abort
else
format_fallback = BookFormat.find_by(fallback: true)
Book.where(book_format_id: self.id).update(book_format_id: format_fallback.id)
end
end
end
CodePudding user response:
(upon request promoting my comment to an answer)
Since your destroy callback is being called on the web request, the problem lies in the Rspec code...
You need to reload the @book
model in the expect
statement, so:
expect(@book.reload.book_format.id).to... etc.