Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save olivierlacan/1151572 to your computer and use it in GitHub Desktop.
Save olivierlacan/1151572 to your computer and use it in GitHub Desktop.
Issue testing create action with invalid parameters when using respond_to/respond_with in Rails 3.x
# Issue testing create action with invalid parameters when using respond_to/respond_with in Rails 3.x
When a new "thing" is saved without invalid params, the respond_with behavior is to render :new again.
But since the form has been submitted to :root/things/, what actually displays in the browser is http://:root/things and not http://:root/things/new.
Somehow this confuses the render_template test in RSpec and it believes the current template is "" instead of "new", which results in a failed test.
The only solution I found was to write the create action like this:
if @thing.save
respond_with @thing
else
render :new
end
But that kind of defeats the purpose of the respond_with elegance, doesn't it?
I'd love to hear feedback on this. I'm still new to Rails and especially new to testing.
You can find all the details below.
## Model
class Thing < ActiveRecord::Base
### schema
# name string
# store_id integer
###
has_and_belongs_to_many :stores
attr_accessible :name
validates :name, presence: true
end
## Controller
class ThingController < ApplicationController
respond_to :html, :json
(...)
def new
@thing = Thing.new
respond_with @thing
end
def create
@thing = Device.new(params[:thing])
@thing.save
respond_with @thing
end
(...)
## RSpec Controller test
describe ThingController do
describe "POST create" do
describe "with invalid params" do
it "assigns a newly created but unsaved device as @thing" do
Thing.any_instance.stub(:save).and_return(false)
post :create, :thing => {}
assigns(:thing).should be_a_new(Thing)
end
it "re-renders the 'new' template" do
Thing.any_instance.stub(:save).and_return(false)
post :create, :thing => {}
response.should render_template("new")
end
end
end
## RSpec result
Failures:
1) ThingsController POST create with invalid params re-renders the 'new' template
Failure/Error: response.should render_template("new")
expecting <"new"> but rendering with <"">
# ./spec/controllers/things_controller_spec.rb:93:in `block (4 levels) in <top (required)>'
Finished in 0.78002 seconds
9 examples, 1 failure
## Log output
Started POST "/en/things" for 127.0.0.1 at 2011-08-17 09:35:38 -0400
Processing by ThingsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7J/MfJ/BHqVhIT4SCGlIYVy0lv+lpfkrHU63gFKZhUQ=", "thing"=>{"name"=>""}, "commit"=>"Save", "locale"=>"en"}
Rendered devices/_form.html.haml (4.5ms)
Rendered devices/new.html.haml within layouts/application (6.0ms)
User Load (0.2ms) SELECT "users".* FROM "users" WHERE "users"."id" = 1 LIMIT 1
(0.2ms) SELECT COUNT(*) FROM "stores" WHERE "stores"."user_id" = 1
Completed 200 OK in 248ms (Views: 235.8ms | ActiveRecord: 1.7ms)
## Visual result
http://link.olivierlacan.com/9NRg
@alabeduarte
Copy link

Try this:

      it "re-renders the 'new' template" do
        Record.stub(:new) { mock_record(:save => false) }
        post :create, :record => {}
        response.should redirect_to(record_url(mock_record)) #add
        # response.should render_template("new") #remove
      end

@tute
Copy link

tute commented Feb 14, 2013

Having the same issue, news on this?

@tute
Copy link

tute commented Feb 14, 2013

be_redirect works, but in logs you see how it doesn't redirect.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment