开发者

Working with and Testing Rails ActionController's respond_with

Apologies in advance for the verbosity of this question. If you bear with me I think you'll find it's actually quite simple...just hard for me to explain given my limited Rails domain knowledge.

Given this comment in an ActionController commit dated Aug 6:

 === Builtin HTTP verb semantics

 Rails default renderer holds semantics for each HTTP verb. Depending on the
 content type, verb and the resource status, it will behave differently.

 Using Rails default renderer, a POST request for creating an object could
 be written as:

   def create   
     @user = User.new(params[:user])    
     flash[:notice] = 'User was successfully created.' if @user.save
     respond_with(@user)
       end

 Which is exactly the same as:

   def create
     @user = User.new(params[:user])

     respond_to do |format|
       if @user.save
         flash[:notice] = 'User was successfully created.'
         format.html { redirect_to(@user) }
         format.xml { render :xml => @user, :status => :created, :location => @user }
       else
         format.html { render :action => "new" }
         format.xml { render :xml => @user.errors, :status => :unprocessable_entity }
       end
     end
   end

 The same happens for PUT and DELETE requests.

I've modified a very basic controller to use respond_with. Everything seems to work fine except 2 specs fail when开发者_运维技巧 the Rails auto-generated tests try to pass empty params to update & create methods. I can correct this behavior with a simple if save/else BUT I'm trying to understand this "new" functionality. I think the default spec may possibly be written in an out-of-date way.

From the commit comments: "Since the request is a POST, respond_with will check wether @people resource have errors or not. If it has errors, it will render the error object with unprocessable entity status (422)."

So scrolling down to the last test/spec under POST (below) could I be re-writing that in such a way that it tests for "unprocessable entity status (422)" and passes and thus everything is peachy-keen?

My Controller:

class ClownsController < ApplicationController
  respond_to :html, :json

  def index
    respond_with(@clowns = Clown.all)
  end

  def show
    respond_with(@clown = Clown.find(params[:id]))
  end

  def new
    respond_with(@clown = Clown.new)
  end

  def edit
    respond_with(@clown = Clown.find(params[:id]))
  end

  def create
     @clown = Clown.new(params[:clown])
     flash[:notice] = 'Clown was successfully created.' if @clown.save
     respond_with(@clown) 
  end

  # Replacing def create above with this won't Fail the spec ##
  #
  # def create
  #    @clown = Clown.new(params[:clown])
  #    respond_with(@clown) do |format|
  #      if @clown.save
  #        flash[:notice] = 'Clown was successfully created.'
  #        format.html { redirect_to @clown }
  #      else
  #        format.html { render :action => :new }
  #      end
  #    end
  # end


  def update
    @clown = Clown.find(params[:id])
    flash[:notice] = 'Clown has been updated.' if @clown.update_attributes(params[:clown])
    respond_with(@clown)
  end

  def destroy
    @clown = Clown.find(params[:id])
    flash[:notice] = 'Successfully deleted clown.' if @clown.destroy
    respond_with(@clown)
  end
end

Testing the specs:

$ rspec spec/
.......F....F..............

Failures:

  1) ClownsController 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/clowns_controller_spec.rb:69:in `block (4 levels) in <top (required)>'

  2) ClownsController PUT update with invalid params re-renders the 'edit' template
     Failure/Error: response.should render_template("edit")
     expecting <"edit"> but rendering with <"">.
     Expected block to return true value.
     # (eval):2:in `assert_block'
     # ./spec/controllers/clowns_controller_spec.rb:107:in `block (4 levels) in <top (required)>'

Here is part of clowns_controller_spec.rb:

require 'spec_helper'

describe ClownsController do

  def mock_clown(stubs={})
    (@mock_clown ||= mock_model(Clown).as_null_object).tap do |clown|
      clown.stub(stubs) unless stubs.empty?
    end
  end

...

  describe "POST create" do

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


Try mocking your Clown class with the following

Clown.stub(:new) { mock_clown(:errors => {:any => 'error'}) }

This way the respond_with method will know that the model saving failed and it will render the new template.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜