【问题标题】:Understanding Rails 3's respond_with了解 Rails 3 的 respond_with
【发布时间】:2010-12-15 03:15:58
【问题描述】:

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

【问题讨论】:

  • 您在运营商控制器的#new#create 操作中都调用了Carrier.new。我猜应该是def create动作方法中的Carrier.create(params[:carrier])

标签: ruby-on-rails rspec respond-with


【解决方案1】:

tl:dr

向 mock 中添加错误哈希:

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 &lt;http://test.host/&gt; but was a redirect to &lt;http://test.host/carriers/1001&gt;

规范应该通过渲染new模板来通过,这是模拟Carrier对象上的save返回false之后的正常事件过程。相反,respond_with 最终会重定向到 show_carrier_path。这是完全错误的。但为什么呢?

在对源代码进行一些挖掘之后,控制器似乎试图渲染“carriers/create”。没有这样的模板,因此引发了异常。救援块确定请求是 POST 并且错误哈希中没有任何内容,控制器会重定向到默认资源,即模拟 Carrier

这令人费解,因为控制器不应假定存在有效的模型实例。毕竟这是create。在这一点上我只能推测测试环境在某种程度上走捷径。

所以解决方法是提供一个虚假的错误哈希。通常情况下,save 失败后哈希中会有一些东西,所以这有点道理。

【讨论】:

  • 干得好!你会认为这是一个错误吗?我对 Rails 的了解还不够多,还没有发表意见。但是您的回答正在帮助我学习!再次感谢...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-14
  • 1970-01-01
相关资源
最近更新 更多