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]
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
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
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.
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.
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.
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 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
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: