2

I'm trying to prevent deletion of models from the db and pretty much follow this guide (see 9.2.5.3 Exercise Your Paranoia with before_destroy) from a Rails 4 book.

I have a simple model:

class User < ActiveRecord::Base
  before_destroy do
    update_attribute(:deleted_at, Time.current)
    false
  end

and in the controller:

def destroy
  @user = User.find(params[:id])
  # @user.update!(deleted_at: Time.zone.now) # if I do it here it works
  @user.destroy # if I also comment this line...

  render :show
end

The callback gets called and the attribute gets set, but then the database transaction always gets rolled back. It I leave out the returning of false the model gets deleted because the execution of delete is not halted.

As you can see in the comments I can get it to work but what I really want to do is use a Service Object and put the logic out of the controller.

einSelbst
  • 2,099
  • 22
  • 24

2 Answers2

1

if your callback returns false the transaction will always be rollbacked.

For what you want you should not call to the destroy method on your arel object.
Instead, make your own method like soft_destroy or something like that and update your attribute.

And to prevent others from calling the destroy method on your arel object, just add a callback raising and exception for instance.

Fer
  • 3,247
  • 1
  • 22
  • 33
  • I guessed that the *false* is the reason. Thanks for confirming. It's strange that it is suggested in a book. I will go the route you proposed. Thank you. – einSelbst Nov 04 '14 at 20:47
0

Your model is just an object. If you really want to change the concept of destroy, change it:

def destroy
  condition ? alt_action : super
end
Jesse Farmer
  • 553
  • 4
  • 13