Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

document.destroy now returns false if before_destroy callback returns fa... #290

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

tpjg
Copy link

@tpjg tpjg commented May 14, 2012

I'm rendering different views in my rails controller depending on the outcome of @record.destroy. It could be just me, I'm still a relative riak/ripple newbie but it appears that when a callback returned false this didn't get through. I've changed a single line and wrote (my first) RSpec test for it.

@@ -90,8 +90,7 @@ def destroy!
end

def destroy
destroy!
true
(destroy!)==false ? false : true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If destroy! returns false, this line seems unnecessary. Just return the value of destroy! or !!destroy!.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree. It's an unnecessary check - although it makes sure it only ever returns true or false and not somethings else (like a Ripple::Document).

@myronmarston
Copy link
Contributor

I'm not sure if the behavior demonstrated by the spec is actually behavior we want. @seancribbs and I had a conversation a while back about callbacks, and we both disliked the fact that ActiveRecord halts the action if the callback returns false. This conflates command/query separation semantics and, in my experience, can be a subtle source of bugs. In ripple we decided we didn't want that behavior.

Furthermore, I'm not sure that before_destroy { false } is actually preventing the destroy action here. I think what you have here passes the spec because destroy! is defined in lib/ripple/callbacks.rb as:

    # @private
    def destroy!(*args, &block)
      run_callbacks(:destroy) do
        super
      end
    end

I'm not totally sure about this, but I think that run_callbacks here may be returning the value of the last callback (which is why the spec passes), while still yielding to the block (which supers to the main implementation of destroy!)--hence, I think the destroy actually may be succeeding. If my hunch is true, then I think this change is unhelpful, since it makes the API confusing. destroy should only return false if the deletion did not happen.

@tpjg
Copy link
Author

tpjg commented May 14, 2012

@myronmarston you could be right about the destroy actually succeeding and maybe the ActiveRecord conventions are not the best solution. So how to implement some checks before allowing a destroy? I'm currently using (trying to use...) a before_destroy to prevent a document from getting destroyed if it has links to some other documents and using before_destroy seemed like an elegant solution to me.

@myronmarston
Copy link
Contributor

@tpjg -- you should be able to override destroy, and conditionally super to ripple's implementation based on whatever logic you need.

@tpjg
Copy link
Author

tpjg commented May 14, 2012

I have written a different spec and it seems that the destroy is not succeeding, so it is as expected from a typical ActiveRecord implementation.

  it "destroy should return false and not destroy the document when a callback returns false" do
    User.before_destroy { false }
    u = User.create!(:email => 'nobody@domain.com')
    u.destroy.should be false
    User.find(u.key).should be_an_instance_of(User)
  end

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants