2010-12-15 78 views
12

使用ActionController的新方法respond_with ...當動作(保存)成功和不成功時,它如何確定呈現內容?Understanding Rails 3's respond_with

我問,因爲我試圖讓腳手架生成規範(包括下面)通過,如果只是爲了我能理解它。該應用程序工作正常,但奇怪的是,當驗證失敗時,它似乎呈現/carriers(至少這就是瀏覽器的URL所說的內容)。然而,規範期待"new"(對於這個問題,我也是如此),而是收到<"">。如果我改變規格以期望""它仍然失敗。

當它呈現/carriers時,該頁面顯示驗證失敗的字段旁邊的error_message,正如人們所期望的那樣。

任何人都可以熟悉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)>' 
+1

您在運營商控制器的'#new'和'#create'操作中調用'Carrier.new'。我想應該是'def create'行爲方法中的'Carrier.create(params [:carrier])'。 – Ernesto 2012-09-26 19:01:31

回答

23

TL:博士

添加誤差散到模擬:

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>

該規範是應該通過渲染new模板,這是事件的save對模擬後的正常過程通過Carrier對象返回false。相反respond_with最終重定向到show_carrier_path。這顯然是錯誤的。但爲什麼?

在源代碼中進行了一些挖掘之後,似乎控制器嘗試渲染'運營商/創建'。沒有這樣的模板,因此引發異常。救援塊確定請求是一個POST,並且錯誤散列中沒有任何內容,控制器將重定向到默認資源,即模擬Carrier

這是令人費解的,因爲控制器不應該假設有一個有效的模型實例。畢竟這是一個create。在這一點上,我只能推測測試環境在某種程度上採取了捷徑。

所以解決方法是提供一個虛假的錯誤散列。通常情況下,save失敗後會出現散列,因此這樣做有道理。

+0

很好地完成了!你會認爲這是一個錯誤?我對Rails還沒有足夠的瞭解。但你的答案正在幫助我學習!再次感謝... – Meltemi 2010-12-16 18:48:52