了解 Rails 3 的 response_with [英] Understanding Rails 3's respond_with
问题描述
利用 ActionController 的新 respond_with
方法...当动作(保存)成功时,它如何确定渲染什么?
Utilizing ActionController's new respond_with
method...how does it determine what to render when action (save) is successful and when it's not?
我之所以这么问是因为我试图让一个脚手架生成的规范(包括在下面)通过,如果只是为了我能理解它.该应用程序运行良好,但奇怪的是,当验证失败时,它似乎正在呈现 /carriers
(至少浏览器的 URL 是这样说的).然而,规范期望 "new"
(就此而言,我也是如此),而是接收 <"">
.如果我将规范更改为期望 ""
它仍然失败.
I ask because I'm trying to get a scaffold generated spec (included below) to pass, if only so that I can understand it. The app is working fine but, oddly, it appears to be rendering /carriers
(at least that's what the browser's URL says) when a validation fails. Yet, the spec is expecting "new"
(and so am I, for that matter) but instead is receiving <"">
. If I change the spec to expect ""
it still fails.
当它呈现 /carriers
时,该页面会在验证失败的字段旁边显示 error_messages,正如人们所期望的那样.
When it renders /carriers
that page shows the error_messages next to the fields that failed validation as one would expect.
任何熟悉 respond_with
的人都可以看到这里发生了什么吗?
Can anyone familiar with respond_with
see what's happening here?
#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)>'
推荐答案
tl:dr
向模拟添加错误哈希:
Carrier.stub(:new) { mock_carrier(:save => false,
:errors => { :anything => "any value (even nil)" })}
这将在 respond_with
中触发所需的行为.
This will trigger the desired behavior in respond_with
.
这里发生了什么
在 post :create
response.code.should == "200"
它失败了 expected: "200", got: "302"
.因此,它正在重定向而不是在不应该呈现新模板时呈现.它要去哪里?给它一条我们知道会失败的路径:
It fails with expected: "200", got: "302"
. So it is redirecting instead of rendering the new template when it shouldn't. Where is it going? Give it a path we know will fail:
response.should redirect_to("/")
现在它失败了,预期响应是重定向到
规范应该通过渲染 new
模板来传递,这是模拟 Carrier 对象上的 save
返回 false 后事件的正常过程.相反,respond_with
最终会重定向到 show_carrier_path
.这是完全错误的.但为什么?
The spec is supposed to pass by rendering the new
template, which is the normal course of events after the save
on the mock Carrier object returns false. Instead respond_with
ends up redirecting to show_carrier_path
. Which is just plain wrong. But why?
在对源代码进行一些挖掘之后,似乎控制器试图渲染carriers/create".没有这样的模板,因此引发了异常.救援块确定请求是 POST 并且错误哈希中没有任何内容,控制器重定向到默认资源,即模拟 Carrier
.
After some digging in the source code, it seems that the controller tries to render 'carriers/create'. There is no such template, so an exception is raised. The rescue block determines the request is a POST and there is nothing in the error hash, upon which the controller redirects to the default resource, which is the mock Carrier
.
这令人费解,因为控制器不应该假设存在有效的模型实例.毕竟这是一个create
.在这一点上我只能猜测测试环境在某种程度上走捷径.
That is puzzling, since the controller should not assume there is a valid model instance. This is a create
after all. At this point I can only surmise that the test environment is somehow taking shortcuts.
所以解决方法是提供一个假的错误哈希.通常情况下,save
失败后,哈希中会有一些东西,所以这有点道理.
So the workaround is to provide a fake error hash. Normally something would be in the hash after save
fails, so that kinda makes sense.
这篇关于了解 Rails 3 的 response_with的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!