Route is valid but not found :(

Hi, guys,

After reading the rspec book (dec 2010 edition), I went on to write
controller specs for an application I’m porting over from rails 2.3.x
to rails 3.

  1. I ran ‘rake routes’ and got the following:

    parts GET /parts(.:format)
    {:action=>“index”, :controller=>“parts”}
    POST /parts(.:format)
    {:action=>“create”, :controller=>“parts”}
    new_part GET /parts/new(.:format)
    {:action=>“new”, :controller=>“parts”}
    edit_part GET /parts/:id/edit(.:format)
    {:action=>“edit”, :controller=>“parts”}
    part GET /parts/:id(.:format)
    {:action=>“show”, :controller=>“parts”}
    PUT /parts/:id(.:format)
    {:action=>“update”, :controller=>“parts”}
    DELETE /parts/:id(.:format)
    {:action=>“destroy”, :controller=>“parts”}

  2. I ran ‘rake spec:controllers’ and got the error below.

Pending:
PartsController the new part object’s updates are saved successfully
saves updates to a new part
# Not Yet Implemented
# ./spec/controllers/parts_controller_spec.rb:59

Failures:

  1. PartsController saves updates to an existing part object
    successfully
    Failure/Error: put :update#, :part => { ‘title’ => ‘Grimspeed’ }
    ActionController::RoutingError:
    No route matches {:controller=>“parts”, :action=>“update”}

    ./spec/controllers/parts_controller_spec.rb:55

  2. Here’s what the spec reads:

    it ‘saves updates to an existing part object successfully’ do
    Part.should_receive(:update).
    with( ‘title’ => ‘Brake pads’ ).
    and_return(part)
    put :update#, :part => { ‘title’ => ‘Brake pads’ }
    end

What I do not understand is that
the :controller=>“parts”, :action=>“update” route actually exists
(when I ran “rake routes”) but the tests does not acknowledge the
existence of the ‘update’ method in the controller with PUT request.

On Mon, Aug 22, 2011 at 12:14 AM, ct9a [email protected] wrote:

{:action=>“index”, :controller=>“parts”}
POST /parts(.:format)
{:action=>“create”, :controller=>“parts”}
new_part GET /parts/new(.:format)
{:action=>“new”, :controller=>“parts”}
edit_part GET /parts/:id/edit(.:format)
{:action=>“edit”, :controller=>“parts”}
part GET /parts/:id(.:format)
{:action=>“show”, :controller=>“parts”}
PUT /parts/:id(.:format)

The :id means you need to pass an “id” to the route helper method.

./spec/controllers/parts_controller_spec.rb:59

  1. Here’s what the spec reads:

    it ‘saves updates to an existing part object successfully’ do
    Part.should_receive(:update).
    with( ‘title’ => ‘Brake pads’ ).
    and_return(part)
    put :update#, :part => { ‘title’ => ‘Brake pads’ }
    end

So you need to “find” the part first:

part = double(‘part’)
Part.should_receive(:find).with(1).and_return(part)
Part.should_receive(:update).with(‘title’ => ‘Brake
pads’).and_return(part)
put :update, :id => 1, :part => {‘title’ => ‘Brake pads’}

What I do not understand is that
the :controller=>“parts”, :action=>“update” route actually exists
(when I ran “rake routes”) but the tests does not acknowledge the
existence of the ‘update’ method in the controller with PUT request.

You need to pass in the :id for Rails to recognize the route.

Thanks, Justin.

I have the part object mocked up before each spec runs.

------- Extract begins -----------------

let(:part){
    mock_model('Part').as_null_object
}

before do
    Part.stub(:new).and_return(part)
end

------- Extract ends -----------------

With that in mind, I just made changes to my spec as below:

------- Extract begins -----------------

it 'saves updates to an existing part object successfully' do
    Part.should_receive(:find).with(1).and_return(part)
    Part.should_receive(:update).with( 'title' =>

‘Grimspeed’ ).and_return(part)
put :update, :id => 1, :part => { ‘title’ => ‘Grimspeed’ }
end

------- Extract ends -----------------

When I run the ‘rake spec:controllers’, I get the following error:

------- Error extract begins -----------------

  1. PartsController saves updates to an existing part object
    successfully
    Failure/Error: Part.should_receive(:update).with( ‘title’ =>
    ‘Brake pads’ ).and_return(part)
    (<Part(id: integer, title: string, description: text,
    created_by: string, updated_by: string, created_at: datetime,
    updated_at: datetime) (class)>).update({“title”=>“Brake pads”})
    expected: 1 time
    received: 0 times

    ./spec/controllers/parts_controller_spec.rb:53

------- Error extract ends -----------------

I then put in Justin’s change with the use of double() as follows:

------- Source code extract begins -----------------

it 'saves updates to an existing part object successfully' do
    part = double(part)
    Part.should_receive(:find).with(1).and_return(part)
    Part.should_receive(:update).with( 'title' => 'Brake

pads’ ).and_return(part)
put :update, :id => 1, :part => { ‘title’ => ‘Brake pads’ }
end

------- Source code extract ends -----------------

and I got the following error:

------- Error extract begins -----------------

  1. PartsController saves updates to an existing part object
    successfully
    Failure/Error: put :update, :id => 1, :part => { ‘title’ =>
    ‘Brake pads’ }
    Double received unexpected message :update_attributes with
    ({“title”=>“Brake pads”})

    ./app/controllers/parts_controller.rb:63:in `update’

    ./app/controllers/parts_controller.rb:62:in `update’

    ./spec/controllers/parts_controller_spec.rb:55

------- Error extract ends -----------------

I have also looked at a few other posts in the group but can’t figure
out what’s causing
update_attributes not to be recognised :frowning:

http://groups.google.com/group/rspec/browse_thread/thread/9bfb4a348799c30f/30de6b7953222b5a?lnk=gst&q=update_attributes#30de6b7953222b5a

http://groups.google.com/group/rspec/browse_thread/thread/fe4985e2b8be16da/f590a9e0510ff4fb?lnk=gst&q=update_attributes#f590a9e0510ff4fb

My update message in the parts controller reads as below:

------- Source code extract starts -----------------
def update
@part = Part.find(params[:id])

respond_to do |format|
  if @part.update_attributes(params[:part])
    format.html { redirect_to(@part, :notice => 'Part was

successfully updated.') }
format.xml { head :ok }
else
format.html { render :action => “edit” }
format.xml { render :xml => @part.errors, :status
=> :unprocessable_entity }
end
end
end

------- Source code extract ends -----------------

I have used this bit of code without problems in the past.
update_attributes, like save, is part of the ActiveRecord api (http://
ar.rubyonrails.org/).

Well, given that controllers are not to know of the implementation of
messages,
I have then stubbed the message to the update_attributes method in the
parts controller.

------- Source code extract starts -----------------
context ‘saves updates to an existing part object successfully’ do
before do
part =
double(‘part’).stub(:update_attributes).and_return(true)
end

    it 'does its job in saving the update' do
        Part.should_receive(:find).with(1).and_return(part)
        Part.should_receive(:update).with('title' => 'Brake

pads’).and_return(part)
put :update, :id => 1, :part => {‘title’ => ‘Brake pads’}
end
end
------- Source code extract ends -----------------

Alas, I got the error below :frowning:

------- Error extract starts -----------------

  1. PartsController saves updates to an existing part object
    successfully does its job in saving the update
    Failure/Error: Part.should_receive(:update).with(‘title’ =>
    ‘Brake pads’).and_return(part)
    (<Part(id: integer, title: string, description: text,
    created_by: string, updated_by: string, created_at: datetime,
    updated_at: datetime) (class)>).update({“title”=>“Brake pads”})
    expected: 1 time
    received: 0 times

    ./spec/controllers/parts_controller_spec.rb:61

------- Error extract ends -----------------

On Mon, Aug 22, 2011 at 9:09 PM, ct9a [email protected] wrote:

}
------- Extract begins -----------------

it ‘saves updates to an existing part object successfully’ do
Part.should_receive(:find).with(1).and_return(part)
Part.should_receive(:update).with( ‘title’ =>
‘Grimspeed’ ).and_return(part)

Should be:

Part.should_receive(:update_attributes).with(‘title’ =>
‘Grimspeed’).and_return(part)

No where do you call update on Part.

Sent from my iPhone

On Aug 22, 2011, at 10:14 PM, ct9a [email protected] wrote:

With that in mind, I just made changes to my spec as below:
Part.should_receive(:update_attributes).with(‘title’ =>
Part.should_receive(:find).with(1).and_return(part)
I’ve already got a put request to the ‘update’ method with an id and
Part.should_receive(:update_attributes).with(‘title’ => 'Brake
8 examples, 1 failure, 1 pending

----------------- Error extract end

Hmm… What is missing?

Do you have a before filter somewhere that is preventing the
:update_attributes message from being received?

On Aug 23, 1:55pm, Justin Ko [email protected] wrote:

}

No where do you call update on Part.
Yes, I have done that and the spec looks like below.

------------------ Spec extract begins

context 'saves updates to an existing part object successfully' do
    it 'does its job in saving the update' do
        Part.should_receive(:find).with(1).and_return(part)
        Part.should_receive(:update_attributes).with('title' =>

‘Brake pads’).and_return(part)
put :update, :id => 1, :part => {‘title’ => ‘Brake pads’}
end
end
------------------ Spec extract ends

Alas, it’s still giving out an error indicating the update_attributes
message is never called.
I’ve already got a put request to the ‘update’ method with an id and
the part hash parameter
and yet it looks like ‘update’ is not called (which in will call
update_attributes in it).

----------------- Error extract starts

  1. PartsController saves updates to an existing part object
    successfully does its job in saving the update
    Failure/Error:
    Part.should_receive(:update_attributes).with(‘title’ => ‘Brake
    pads’).and_return(part)
    (<Part(id: integer, title: string, description: text,
    created_by: string, updated_by: string, created_at: datetime,
    updated_at: datetime) (class)>).update_attributes({“title”=>“Brake
    pads”})
    expected: 1 time
    received: 0 times

    ./spec/controllers/parts_controller_spec.rb:54

Finished in 0.25483 seconds
8 examples, 1 failure, 1 pending

----------------- Error extract end

I found out why it was not working.

The line, ‘Part.should_receive(:update_attributes).with(‘title’ =>
‘Brake
pads’).and_return(part)’ should not be there because the controller
specs
should not care about implementation (ie. how things are processed,
rather
just what is done). I realised this when I looked at my specs for
creation
of new objects.

I commented the line and the spec now passes as expected.

------------ Spec extract starts -------------------------

context 'saves updates to an existing part object successfully' do
    it 'does its job in saving the update' do
        Part.should_receive(:find).with(1).and_return(part)
    #   Part.should_receive(:update_attributes).with('title' => 

‘Brake
pads’).and_return(part)
put :update, :id => 1, :part => {‘title’ => ‘Brake pads’}
flash[:notice].should eq(‘Part was successfully updated.’)
end
end

------------ Spec extract ends -------------------------

Thank you for your help, Justin!

Gordon Y. :slight_smile:

Do you have a before filter somewhere that is preventing the
:update_attributes message from being received?

I have checked my application’s controllers
(app/controllers/application_controller.rb and
app/controllers/parts_controller.rb) and controller spec
(spec/controllers/parts_controller_spec.rb) and found no before filter
that
is preventing the :update_attributes message from being received by
Parts.

Below is what my spec/controllers/parts_controller_spec.rb looks like:

------- Source code, spec/controllers/parts_controller_spec.rb starts

require ‘spec_helper’

describe PartsController do
let(:part){
mock_model(‘Part’).as_null_object
}

before do
    Part.stub(:new).and_return(part)
end

it "creates a new part" do
    Part.should_receive(:new).
        with('title' => 'HKS boost controller').
        and_return(part)
    post :create, :part => { 'title' => 'HKS boost controller' }
end

context "saves the new part object successfully" do
    it "sets the flash with a success message" do
        post :create
        flash[:notice].should eq('Part was successfully created.')
    end

    it "redirects the user back to the Parts index page" do
        post :create
        response.should redirect_to( :action => 'index' )
    end
end

context "the new part object fails to save" do
    before do
        # sabotage and make the save fail
        part.stub(:save).and_return(false)
        # call the create method which will have save in its process
        post :create
    end

    it "assigns @part with the data from db (or a blank one if it's 

the
first time" do
assigns[:part].should eq(part)
end

    it "renders the 'new' template again" do
        # test that the template, 'new' is rendered. Of course, for 

this
# work, the part’s attribute variable values must be passed
to
the
# view for rails to successfully render the template
response.should render_template(‘new’)
end
end

context 'saves updates to an existing part object successfully' do
    it 'does its job in saving the update' do
        Part.should_receive(:find).with(1).and_return(part)
        Part.should_receive(:update_attributes).with('title' => 

‘Brake
pads’).and_return(part)
put :update, :id => 1, :part => {‘title’ => ‘Brake pads’}
flash[:notice].should eq(‘Part was successfully updated.’)
end
end

end

------- Source code, spec/controllers/parts_controller_spec.rb ends

On Aug 23, 2011, at 7:22 AM, Gordon Y. wrote:

    it 'does its job in saving the update' do
        Part.should_receive(:find).with(1).and_return(part)
    #   Part.should_receive(:update_attributes).with('title' => 'Brake 

pads’).and_return(part)

^^ Change the class name Part to the variable part ^^:

part.should_receive(:update_attributes).with(‘title’ => ‘Brake
pads’).and_return(part)

It’s the part object, not the Part class that will receive
update_attributes.

HTH,
David


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

Cheers,
David

I think you were closer when you had:
------- Source code extract starts -----------------
context ‘saves updates to an existing part object successfully’ do
before do
part =
double(‘part’).stub(:update_
attributes).and_return(true)
end

   it 'does its job in saving the update' do
        Part.should_receive(:find).with(1).and_return(part)
       Part.should_receive(:update).with('title' => 'Brake

pads’).and_return(part)
put :update, :id => 1, :part => {‘title’ => ‘Brake pads’}
end
end
------- Source code extract ends -----------------

However, you were setting part equal to the return value from
“stub(:update_attributes).and_return(true)” which returns a Proc, not a
double.
Instead, try this:

let(:part) { double(‘part’) }

it ‘does its job in saving the update’ do
part.stub(:update_attributes).and_return(true) # <— moved
this
from the before method

      Part.should_receive(:find).with(1).and_return(part)
       Part.should_receive(:update).with('title' => 'Brake

pads’).and_return(part)
put :update, :id => 1, :part => {‘title’ => ‘Brake pads’}
end
end

On Tue, Aug 23, 2011 at 6:22 AM, Gordon Y. [email protected]
wrote:

I found out why it was not working.

The line, ‘Part.should_receive(:update_attributes).with(‘title’ => ‘Brake
pads’).and_return(part)’ should not be there because the controller specs
should not care about implementation (ie. how things are processed, rather
just what is done).

Depends on what you want to do. Now, your controller spec is coupled to
your
model, so if “update_attributes” fails, your controller spec will fail
too.

On Tue, Aug 23, 2011 at 6:11 AM, Gordon Y. [email protected]
wrote:

Below is what my spec/controllers/parts_controller_spec.rb looks like:

end

first time" do
end
end

context 'saves updates to an existing part object successfully' do
    it 'does its job in saving the update' do
        Part.should_receive(:find).with(1).and_return(part)
        Part.should_receive(:update_attributes).with('title' => 'Brake

pads’).and_return(part)

Oh duh. You’re calling should_receive(:update_attributes) on Part
when
it should be called on part:

part.should_receive(:update_attributes).with(‘title’ => ‘Brake
pads’).and_return(true)