1

I have Rails 4 Application with TravelNotes. Travel notes has 3 kind of statuses: draft, published, archived. If the status is draft, then it can be deleted otherwise not.

In the TravelNote-Model:

  before_destroy :check_for_draft

  def check_for_draft
    if status == 'draft'
      delete
    else
      errors.add(:scope, 'Only drafts can be deleted')
      return false
    end
  end

And i use RSpec for testing:

it "should delete a travel note if its status is draft"  do
  expect{ draft.destroy! }.to change{ TravelNote.count }.by(-1)
end


it "should not delete a travel note if its status is published or archived" do
  expect{ published.destroy! }.to_not change{ TravelNote.count }

When i run the test the draft-deleting-test passes but for published-deleting-test i get:

Failures:
  1) TravelNote delete should not delete a travel note if its status is published or archived
 Failure/Error: expect{ published.destroy! }.to_not change{ TravelNote.count }
 ActiveRecord::RecordNotDestroyed:
   ActiveRecord::RecordNotDestroyed

Obviously the code is working and only travel notes with other statuses than draft can be deleted.

How can i turn the Failure-Message ActiveRecord::RecordNotDestroyed to green?

StandardNerd
  • 4,093
  • 9
  • 46
  • 77

3 Answers3

1

There are several issues here:

  1. You are using the bang! version of destroy! which coerces any before_destroy callback from returning false to raise ActiveRecord::RecordNotDestroyed.
  2. You are using delete in your method and destroy! in your tests. delete doesn't invoke the callbacks - see Difference between Destroy and Delete
  3. You shouldn't call delete or destroy of self inside the before_destroy callback. Not returning false will cause the original destroy action to work.

@Felipe posted the link to destroy, you should also look at the link to destroy!:

http://api.rubyonrails.org/classes/ActiveRecord/Persistence.html#method-i-destroy-21

which states

There's a series of callbacks associated with destroy!. If the before_destroy callback return false the action is cancelled and destroy! raises ActiveRecord::RecordNotDestroyed. See ActiveRecord::Callbacks for further details.

Community
  • 1
  • 1
Chris Beck
  • 1,899
  • 2
  • 19
  • 26
  • To be clear, you can `delete` or `destroy` other related records, but you shouldn't `self.delete` since the callback does that for you – Chris Beck Feb 14 '15 at 19:36
0

Try this:

expect{ published.destroy! }.to raise_error(ActiveRecord::RecordNotDestroyed)

For more information:

http://apidock.com/rails/ActiveRecord/Persistence/destroy%21

Joel
  • 4,503
  • 1
  • 27
  • 41
  • Thanks Felipe, your approach is working. But after removing the bang in destroy! the test passes, too. I'm not sure if this is the rspec-way to check but i stick with "to_not change". – StandardNerd Oct 16 '14 at 16:52
0

i just had to remove the bang in destroy! to get the test pass:

it "should not delete a travel note if its status is published or archived" do
  expect{ published.destroy }.to_not change{ TravelNote.count }
  expect{ archived.destroy }.to_not change{ TravelNote.count }
end
StandardNerd
  • 4,093
  • 9
  • 46
  • 77