在 rspec 中传递表单参数

发布于 2024-12-25 06:20:00 字数 3629 浏览 3 评论 0原文

我正在使用acts_as_audited。在销毁操作的控制器中,我传递了审核注释值。所有这些都运行良好,但是当我尝试测试销毁操作时,我得到:

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)>'

第 79 行读取:@purchase.audit_comment = params[:purchase][:audit_comment]

这是我的代码:

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

购买 show.html.erb 已编辑

<%= 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 - 购买

<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

感谢任何帮助。谢谢!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

相对绾红妆 2025-01-01 06:20:00

它告诉您在第 79 行,params[:purchase] 为 nil。

它为零的原因是 button_to 生成自己的表单标记。因此,您现在在

中有一个 ,并且您的审核评论字段未提交。您应该使用 builder.submit,而不是 button_to。您还需要在对 form_for 的调用中设置 :method 选项,以使其成为 DELETE 请求。

编辑问题后更新

HTML 现在看起来不错,但我发现规范存在问题。我认为您忘记将审核注释传递到您的 HTTP 参数中。它位于 HTML 中,但您的规范绕过了表单,因为它单独测试控制器。 (集成测试将使用实际的表单。控制器测试则不会。)因此,您必须手动向请求添加控制器期望的任何表单参数。例如:

delete :destroy, :id => 1, :purchase => {:audit_comment => 'Test comment'}

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'}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文