Problems testing a destroy failure

276 views
Skip to first unread message

Clem Rock

unread,
Jan 5, 2014, 7:06:28 PM1/5/14
to rubyonra...@googlegroups.com
Hello,
I'm trying to test an active record object destroy failure but I'm
having problems creating a failure situation. I have a before_filter
method called 'require_user_payment_info' which validates the
@payment_info object before the delete method is called so I can't
create a 'bad' @payment_info object before the delete method is called.

Here's the require_user_payment_info method:

[code]
def require_user_payment_info
@payment_info = credit_card_model.slave.find_by_user_guid(user_guid)
if !@payment_info || @payment_info.user_guid != user_guid
redirect_to(:controller => 'store', :action => 'index') and return
false
else
if((@payment_info.card_expires_year.to_i < Date.today.year) ||
((@payment_info.card_expires_month.to_i < Date.today.month) &&
(@payment_info.card_expires_year.to_i == Date.today.year)))
@payment_info.card_account_public = "" #clear this out so the
user is forced to re-enter the credit card number
@payment_info.valid?
flash.now[:error] = t('ui_flash_errors.card_expired_error')
end
end
end
[/code]


And the actual delete method:

[code]
def delete
# required to be called via a delete request
redirect_to :action => 'edit' and return if !request.delete?
if @payment_info.destroy
flash[:notice] = "Delete SUCCESSFUL"
redirect_to :action => 'new'
else
flash[:error] = "Delete failed"
redirect_to :action => 'edit'
end
[/code]

Any ideas?

Thanks!

--
Posted via http://www.ruby-forum.com/.

Walter Lee Davis

unread,
Jan 5, 2014, 8:18:01 PM1/5/14
to rubyonra...@googlegroups.com
Shouldn't this line be 'def destroy'?

Delete is the method that is called without callbacks to actually remove the record. Destroy calls up the before_destroy handlers and checks the validations.

Here's one ripped from a working application:

#group.rb
before_destroy :group_has_children?
...
private
def group_has_children?
errors.add(:base, "Cannot delete a group with members") unless groupings.count == 0
errors.blank?
end

There's probably a better way to do this, but this was how I settled on it. I know there's a way to do this with validations, too. Probably just this:

validate :group_has_children?, :on => :destroy

def group_has_children?
errors.add(:base, "Cannot delete a group with members") unless groupings.count == 0
end

Walter

> # required to be called via a delete request
> redirect_to :action => 'edit' and return if !request.delete?
> if @payment_info.destroy
> flash[:notice] = "Delete SUCCESSFUL"
> redirect_to :action => 'new'
> else
> flash[:error] = "Delete failed"
> redirect_to :action => 'edit'
> end
> [/code]
>
> Any ideas?
>
> Thanks!
>
> --
> Posted via http://www.ruby-forum.com/.
>
> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/2106a78b86d97e1320d111ec5f05223e%40ruby-forum.com.
> For more options, visit https://groups.google.com/groups/opt_out.

Clem Rock

unread,
Jan 6, 2014, 3:56:27 PM1/6/14
to rubyonra...@googlegroups.com
Walter - thanks for getting back to me on this.

First of all, I should have made this more clear - the delete action is
in the controller, not the model and the @payment_info model object is
using the destroy method.

To me, this method seems to be as straight forward as possible - you
attempt to destroy a verified active record object and if the destroy is
successful, then redirect to the the new action, if it fails display the
error and redirect to the edit method. I don't see a logic problem
anywhere in this method so I'm not a big fan of trying to change the
method just to satisfy testing.

Walter Lee Davis

unread,
Jan 6, 2014, 4:15:45 PM1/6/14
to rubyonra...@googlegroups.com
I'm hardly an expert here. I looked in a simple site I did a while back using scaffold, since I don't have my Rails 4 legs under me yet, and scaffold maps the DELETE REST method to YourController::destroy. If you're using the generic routing, then the DELETE request will go to destroy. Apologies if your routes are not the same as mine, and you've already ruled this out.

Walter

>
> --
> Posted via http://www.ruby-forum.com/.
>
> --
> You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to rubyonrails-ta...@googlegroups.com.
> To post to this group, send email to rubyonra...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/rubyonrails-talk/f44747b8a43b50ff9f0e7c93287f60cc%40ruby-forum.com.

Clem Rock

unread,
Jan 6, 2014, 4:22:03 PM1/6/14
to rubyonra...@googlegroups.com
I should add that this is a rails 2.3.18 (*sigh*) app. I see what
you're saying about this code not being as RESTfully optimal as it could
be but I feel that point is diverging off the original question: "how do
I get @payment_info.destroy to fail in a test?"

Frederick Cheung

unread,
Jan 6, 2014, 5:39:41 PM1/6/14
to rubyonra...@googlegroups.com


On Monday, January 6, 2014 4:22:03 PM UTC, Ruby-Forum.com User wrote:
I should add that this is a rails 2.3.18 (*sigh*) app.    I see what
you're saying about this code not being as RESTfully optimal as it could
be but I feel that point is diverging off the original question: "how do
I get @payment_info.destroy to fail in a test?"

I would usually stub it (using mocha, rspec etc) to return/raise as appropriate. Alternatively you could submit data that you know will fail validation

Fred

Clem Rock

unread,
Jan 6, 2014, 6:16:48 PM1/6/14
to rubyonra...@googlegroups.com
That was my original attempt too but the require_user_payment_info
before_filter method checks for a valid payment_info object and will
redirect away from the delete method if the @payment_info object isn't
valid. If I mock the @payment_info object to be invalid, it won't
make it to the delete method.

I must admit my mocking knowledge isn't very strong so my attempts at
mocking have been failures.

Here's the before_filter configuration for require_user_payment_info:

before_filter :require_user_payment_info, :only => [:show, :edit,
:update, :delete]

Frederick Cheung

unread,
Jan 6, 2014, 7:42:09 PM1/6/14
to rubyonra...@googlegroups.com
On Monday, January 6, 2014 6:16:48 PM UTC, Ruby-Forum.com User wrote:
> That was my original attempt too but the require_user_payment_info
>
> before_filter method checks for a valid payment_info object and will
>
> redirect away from the delete method if the @payment_info object isn't
>
> valid. If I mock the @payment_info object to be invalid, it won't
>
> make it to the delete method.
>
>


In which case you want to just stub out the destroy method. In rspec for example you could do

PaymentInfo.any_instance.should_receive(:destroy).and_return(false)

And mocha can do something similar.

Fred

Clem Rock

unread,
Jan 6, 2014, 8:10:28 PM1/6/14
to rubyonra...@googlegroups.com
Fred - big thanks on this. I'm going to give it a try shortly and get
back to you.

Clem Rock

unread,
Jan 8, 2014, 2:15:43 AM1/8/14
to rubyonra...@googlegroups.com
Bingo - that totally worked and here's my solution:

[code]
def test_unsuccessful_delete
payment_info = Factory.create(:payment_info, :user_guid=>@user.guid,
:card_expires_month=>'04',
:card_expires_year=>(Date.today.year+2).to_s,
:cardholder_city=>"test city",
:cardholder_state=>'NC',
:cardholder_country=>'US', :cardholder_zip=>'27612')
PaymentInfo.any_instance.stubs(:destroy).returns(false)

delete(:delete, {}, @session)
assert_response(:redirect)
assert_equal false, assigns(:payment_info).blank?
assert_redirected_to({:controller=>'account', :action=>'edit'})
assert_equal flash[:error], "There was an error deleting your credit
card information. Please try again."
end
[/code]

Thanks for your help!
Reply all
Reply to author
Forward
0 new messages