12

ActionControllerの新しいrespond_withメソッドを利用しています...アクション(保存)が成功した場合と失敗した場合に何をレンダリングするかをどのように決定しますか?

足場で生成された仕様(以下に含まれています)を通過させようとしているので、それを理解できるようにするためだけにお願いします。アプリは正常に動作していますが、奇妙なこと/carriersに、検証が失敗するとレンダリングされているように見えます(少なくともブラウザーのURLはそれを示しています)。それでも、仕様は期待してい"new"ます(そして、私もそうです)が、代わりにを受け取ってい<"">ます。スペックを変更し""ても失敗することが予想されます。

そのページをレンダリングする/carriersと、予想どおりに検証に失敗したフィールドの横にerror_messagesが表示されます。

respond_withここで何が起こっているのかを知っている人はいますか?

#carrier.rb
  validates :name, :presence => true 

#carriers_controller.rb
class CarriersController < ApplicationController
  respond_to :html, :json

...

  def new
    respond_with(@carrier = Carrier.new)
  end

  def create
     @carrier = Carrier.new(params[:carrier])
     flash[:success] = 'Carrier was successfully created.' if @carrier.save
     respond_with(@carrier) 
  end

失敗している仕様:

#carriers_controller_spec.rb
require 'spec_helper'

describe CarriersController do

  def mock_carrier(stubs={})
    (@mock_carrier ||= mock_model(Carrier).as_null_object).tap do |carrier|
      carrier.stub(stubs) unless stubs.empty?
    end
  end


  describe "POST create" do
    describe "with invalid params" do
      it "re-renders the 'new' template" do
        Carrier.stub(:new) { mock_carrier(:save => false) }
        post :create, :carrier => {}
        response.should render_template("new")
      end
    end
  end
end

このエラーで:

  1) CarriersController POST create with invalid params re-renders the 'new' template
     Failure/Error: response.should render_template("new")
     expecting <"new"> but rendering with <"">.
     Expected block to return true value.
     # (eval):2:in `assert_block'
     # ./spec/controllers/carriers_controller_spec.rb:81:in `block (4 levels) in <top (required)>'
4

1 に答える 1

23

tl:dr

モックにエラーハッシュを追加します。

Carrier.stub(:new) { mock_carrier(:save => false, 
                       :errors => { :anything => "any value (even nil)" })}

これにより、で目的の動作がトリガーされrespond_withます。

ここで何が起こっているのか

後にこれを追加しますpost :create

response.code.should == "200"

で失敗しexpected: "200", got: "302"ます。そのため、新しいテンプレートをレンダリングすべきではないときにレンダリングするのではなく、リダイレクトしています。どこに行くの?失敗することがわかっているパスを指定します。

response.should redirect_to("/")

今では失敗しますExpected response to be a redirect to <http://test.host/> but was a redirect to <http://test.host/carriers/1001>

仕様は、テンプレートをレンダリングすることで合格することになっています。これは、モックのCarrierオブジェクトがfalseを返したnew後の通常のイベントです。save代わりにrespond_with、にリダイレクトすることになりshow_carrier_pathます。これはまったく間違っています。しかし、なぜ?

ソースコードを掘り下げた後、コントローラーが「carriers/create」をレンダリングしようとしているようです。そのようなテンプレートはないため、例外が発生します。レスキューブロックは、要求がPOSTであり、エラーハッシュに何も存在しないと判断します。エラーハッシュでは、コントローラーがデフォルトのリソースであるモックにリダイレクトしますCarrier

コントローラは有効なモデルインスタンスがあると想定してはならないため、これは不可解です。create結局のところ、これです。この時点で、私はテスト環境が何らかの形で近道を取っていると推測することしかできません。

したがって、回避策は偽のエラーハッシュを提供することです。通常、失敗した後は何かがハッシュにsave含まれるので、ちょっと意味があります。

于 2010-12-15T06:22:27.870 に答える