1

I am using acts_as_audited. In the controller on the destroy action I pass the audit comment value. All this works well but when I try to test the destroy action I get:

PurchasesController DELETE /destroy deletes the correct Purchase
 Failure/Error: delete :destroy, id: i
 NoMethodError:
  You have a nil object when you didn't expect it!  
  You might have expected an instance of Array.  
  The error occured while evaluating nil.[] 
# ./app/controllers/purchases_controller.rb:79:in `destroy'
# ./spec/controllers/purchases_controller_spec.rb:156:in `block (3 levels) in <top (required)>'

Line #79 reads: @purchase.audit_comment = params[:purchase][:audit_comment]

Heres my code:

PurchasesController

def destroy
  @purchase = Purchase.find(params[:id])
  @purchase.audit_comment = params[:purchase][:audit_comment]
  respond_to do |format|
    if @purchase.destroy
      format.html { redirect_to(purchases_url, notice: "Successfully destroyed purchase.") }
      format.xml  { render :xml => @purchase, :status => :deleted, :location => @purchase }
    else
      flash[:alert] = "#{@purchase.po_number} could not be destroyed"
      render 'show'
    end
  end
end

Purchases show.html.erb EDITED

<%= form_for @purchase, method: :delete do |builder| %>

<% if @purchase.errors.any? %>
  <div id="error_explanation">
    <h2><%= pluralize(@purchase.errors.count, "error") %> prohibited this purchase from being saved:</h2>

    <ul>
    <% @purchase.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>

<% title "Purchase" %>

<div id="delete_button">    
  <span><strong>PO Number:  <%= @purchase.po_number %></strong></span>
    <%= render "audit_comment", f: builder %>
    <%= builder.submit "Destroy Purchase"%>
</div>  
<% end %>
<p>
  <%= link_to "Edit", edit_purchase_path(@purchase) %> |
  <%= link_to "View All", purchases_path %>
</p>

_audit_comment.html.erb - Purchases

<div id = "audit">
  <%= f.label :audit_comment %>:<br />
  <%= f.text_area :audit_comment, :size => "60x5" %>
</div>

purchase_controller_spec.rb

require 'spec_helper'
require 'ruby-debug'

describe PurchasesController do
  login_user
  render_views

  before(:each) do
    @purchase = Factory(:purchase)
  end

  describe "DELETE /destroy" do
    before(:each) do
      @ability.can :destroy, Purchase      
    end  
    it "deletes the correct Purchase" do
      i = @purchase.id
      c = Purchase.count
      pl = Purchase.find(i).purchase_line_items
      cpl = pl.count
      delete :destroy, id: i
      Purchase.count.should == c-1
      pl.count.should == cpl-1
      response.should redirect_to(purchases_path)
      flash[:notice].should == "Successfully destroyed purchase."
    end
    it "redirects to the index page with an alert when a delete fails" do
      i = @purchase.id
      c = Purchase.count
      pl = Purchase.find(i).purchase_line_items
      cpl = pl.count
      Purchase.any_instance.stubs(:valid?).returns(:false)
      delete :destroy, id: i
      Purchase.count.should_not == c-1
      pl.count.should_not == cpl-1
      response.should render_template('show')
      flash[:alert].should == "#{@purchase.po_number} could not be destroyed"
    end
  end
end

Any help is appreciated. Thanks!

trbrink
  • 137
  • 1
  • 2
  • 9

1 Answers1

2

It's telling you that at line 79, params[:purchase] is nil.

The reason it's nil is that button_to generates its own form tag. Thus, you now have a <form> within a <form>, and your audit comment field is not being submitted. Instead of button_to, you should use builder.submit. You will also need to set the :method option in your call to form_for to make it a DELETE request.

Update after edit to question

The HTML looks OK now, but I see a problem with the spec. I think you're forgetting to pass the audit comment in to your HTTP params. It's there in the HTML, but your spec bypasses the form, because it tests the controller in isolation. (An integration test would use the actual form. Controller tests don't.) Therefore, you'll have to manually add to the request any form params the controller expects. For example:

delete :destroy, :id => 1, :purchase => {:audit_comment => 'Test comment'}
rlkw1024
  • 6,455
  • 1
  • 36
  • 65
  • I changed the form and I can still delete purchases aslong as an audit comment is in the text area. The only thing is that the test still fails with the same error. Thanks for your response. – trbrink Jan 05 '12 at 20:29
  • Can you edit your question with the new HTML? I see it still has button_to in it. Perhaps I can determine what the error is if I can look at what you have now. – rlkw1024 Jan 05 '12 at 23:43
  • That fixed it! I had to remove one set of brackets though: `delete :destroy, id: i, purchase: {audit_comment: 'Test comment'}`. Thanks for your help! – trbrink Jan 06 '12 at 17:16
  • Yep! You're right. I've edited my answer for syntactical correctness. – rlkw1024 Jan 06 '12 at 18:39