title: Using Rspec, how do I test the JSON format of my controller in Rails 3.0.11?
body: <p>I've scoured the web, but, alas, I just can't seem to get Rspec to correctly send content-type so I can test my JSON API. I'm using the RABL gem for templates, Rails 3.0.11, and Ruby 1.9.2-p180.</p>
  
  <p>My curl output, which works fine (should be a 401, I know):</p>
  
  <pre><code>mrsnuggles:tmp gaahrdner$ curl -i -H "Accept: application/json" -X POST -d @bleh http://localhost:3000/applications
  HTTP/1.1 403 Forbidden 
  Content-Type: application/json; charset=utf-8
  Cache-Control: no-cache
  X-Ua-Compatible: IE=Edge
  X-Runtime: 0.561638
  Server: WEBrick/1.3.1 (Ruby/1.9.2/2011-02-18)
  Date: Tue, 06 Mar 2012 01:10:51 GMT
  Content-Length: 74
  Connection: Keep-Alive
  Set-Cookie: _session_id=8e8b73b5a6e5c95447aab13dafd59993; path=/; HttpOnly
  
  {"status":"error","message":"You are not authorized to access this page."}
  </code></pre>
  
  <p>Sample from one of my test cases:</p>
  
  <pre><code>describe ApplicationsController do
    render_views
    disconnect_sunspot
  
    let(:application) { Factory.create(:application) }
  
    subject { application }
  
    context "JSON" do
  
      describe "creating a new application" do
  
        context "when not authorized" do
          before do
            json = { :application =&gt; { :name =&gt; "foo", :description =&gt; "bar" } }
            request.env['CONTENT_TYPE'] = 'application/json'
            request.env['RAW_POST_DATA'] = json
            post :create
          end 
  
          it "should not allow creation of an application" do
            Application.count.should == 0
          end 
  
          it "should respond with a 403" do
            response.status.should eq(403)
          end 
  
          it "should have a status and message key in the hash" do
            JSON.parse(response.body)["status"] == "error"
            JSON.parse(response.body)["message"] =~ /authorized/
          end 
        end 
  
        context "authorized" do
        end 
      end
    end
  end
  </code></pre>
  
  <p>These tests never pass though, I always get redirected and my content-type is always <code>text/html</code>, regardless of how I seem to specify the type in my before block:</p>
  
  <pre><code># nope
  before do
    post :create, {}, { :format =&gt; :json }
  end
  
  # nada
  before do
    post :create, :format =&gt; Mime::JSON
  end
  
  # nuh uh
  before do
    request.env['ACCEPT'] = 'application/json'
    post :create, { :foo =&gt; :bar }
  end
  </code></pre>
  
  <p>Here is the rspec output:</p>
  
  <pre><code>Failures:
  
    1) ApplicationsController JSON creating a new application when not authorized should respond with a 403
       Failure/Error: response.status.should eq(403)
  
         expected 403
              got 302
  
         (compared using ==)
       # ./spec/controllers/applications_controller_spec.rb:31:in `block (5 levels) in &lt;top (required)&gt;'
  
    2) ApplicationsController JSON creating a new application when not authorized should have a status and message key in the hash
       Failure/Error: JSON.parse(response.body)["status"] == "errors"
       JSON::ParserError:
         756: unexpected token at '&lt;html&gt;&lt;body&gt;You are being &lt;a href="http://test.host/"&gt;redirected&lt;/a&gt;.&lt;/body&gt;&lt;/html&gt;'
       # ./spec/controllers/applications_controller_spec.rb:35:in `block (5 levels) in &lt;top (required)&gt;'
  </code></pre>
  
  <p>As you can see I'm getting the 302 redirect for the HTML format, even though I'm trying to specify 'application/json'.</p>
  
  <p>Here is my <code>application_controller.rb</code>, with the rescue_from bit:</p>
  
  <pre><code>class ApplicationController &lt; ActionController::Base
  
   rescue_from ActiveRecord::RecordNotFound, :with =&gt; :not_found
  
    protect_from_forgery
    helper_method :current_user
    helper_method :remove_dns_record
  
   rescue_from CanCan::AccessDenied do |exception|
      flash[:alert] = exception.message
      respond_to do |format|
        h = { :status =&gt; "error", :message =&gt; exception.message }
        format.html { redirect_to root_url }
        format.json { render :json =&gt; h, :status =&gt; :forbidden }
        format.xml  { render :xml =&gt; h, :status =&gt; :forbidden }
      end 
    end
  
    private
  
    def not_found(exception)
      respond_to do |format|
        h = { :status =&gt; "error", :message =&gt; exception.message }
        format.html { render :file =&gt; "#{RAILS_ROOT}/public/404.html", :status =&gt; :not_found }
        format.json { render :json =&gt; h, :status =&gt; :not_found }
        format.xml  { render :xml =&gt; h, :status =&gt; :not_found }
      end
    end
  end
  </code></pre>
  
  <p>And also <code>applications_controller.rb</code>, specifically the 'create' action which is what I'm trying to test. It's fairly ugly at the moment because I'm using <code>state_machine</code> and overriding the delete method.</p>
  
  <pre><code>  def create
      # this needs to be cleaned up and use accepts_attributes_for
      @application = Application.new(params[:application])
      @environments = params[:application][:environment_ids]
      @application.environment_ids&lt;&lt;@environments unless @environments.blank?
  
      if params[:site_bindings] == "new"
        @site = Site.new(:name =&gt; params[:application][:name])
        @environments.each do |e|
          @site.siteenvs &lt;&lt; Siteenv.new(:environment_id =&gt; e)
        end
      end
  
      if @site
        @application.sites &lt;&lt; @site
      end
  
      if @application.save
        if @site
          @site.siteenvs.each do |se|
            appenv = @application.appenvs.select {|e| e.environment_id == se.environment_id }
            se.appenv = appenv.first
            se.save
          end
        end
        flash[:success] = "New application created."
        respond_with(@application, :location =&gt; @application)
      else
        render 'new'
      end
  
      # super stinky :(
      @application.change_servers_on_appenvs(params[:servers]) unless params[:servers].blank?
      @application.save
    end
  </code></pre>
  
  <p>I've looked at the source code here: <a href="https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/responder.rb" rel="noreferrer">https://github.com/rails/rails/blob/master/actionpack/lib/action_controller/metal/responder.rb</a>, and it seems it should respond correctly, as well as a number of questions on stack overflow that seem to have similar issues and possible solutions, but none work for me.</p>
  
  <p>What am I doing wrong?</p>