How to write a correct RSpec for Polymorphic Association

I don’t know what is need to set in the variable ADDRESSES:
Organization.stub!(:find_by_id).with(“100”).and_return(mock_organization(:id
=> “100”, :addresses => ??? ))

Somebody help me. Any ideas? I tried to find the solution of problem but
I can’t.

— rspec - controllers
def mock_organization(stubs={})
@parent_object ||= mock_model(Organization, stubs)
end

it “assigns a newly created address as @address” do
Organization.stub!(:find_by_id).with(“100”).and_return(
mock_organization(:id => “100”, :addresses => ??? )) <<!— here
@parent_object.stub(:addresses).stub(:new).with({:these => ‘params’})

post :create, :address => {:these => ‘params’}, :organization_id =>
@parent_object.id
assigns[:address].should equal(mock_address)
end

---- models ----
class Organization < ActiveRecord::Base
has_many :addresses, :as => :addressable
end

class Address < ActiveRecord::Base
belongs_to :addressable, :polymorphic => true
end

----- controllers -----
class AddressesController < ApplicationController
before_filter :load_parent_object

def create
@address = @parent_object.addresses.new(params[:address])

respond_to do |format|
  if @address.save
    flash[:notice] = 'Address was successfully created.'
    format.html { redirect_to(@parent_object) }
    format.xml  { render :xml => @address, :status => :created,

:location => @address }
else
format.html { render :action => “new” }
format.xml { render :xml => @address.errors, :status =>
:unprocessable_entity }
end
end
end

private

def load_parent_object
if params[:organization_id]
@parent_object = Organization.find_by_id(params[:organization_id])
end
end

end

David C. wrote:

On Fri, Oct 16, 2009 at 7:21 AM, Sergey R. [email protected]
wrote:

David

Hi David,

It doesn’t work, I got the following message:
Mock ‘addresses’ recieved unexcepted message :new with ({:these =>
‘params’})

Regards,
Sergey

On Fri, Oct 16, 2009 at 7:21 AM, Sergey R. [email protected]
wrote:

end

class AddressesController < ApplicationController
:location => @address }
def load_parent_object
if params[:organization_id]
@parent_object = Organization.find_by_id(params[:organization_id])
end
end

end

Hi Sergey,

This is a great example of why it’s helpful to write the examples
first. There is no need for this controller to know anything about
organizations - that can be handled by the model, where the
association is defined. Here’s how I might have done this:

it “assigns a newly created address as @address” do
address = stub_model(Address)
Address.stub(:new).
with({:these => ‘params’}).
and_return(address)

post :create, :address => {:these => ‘params’}

assigns[:address].should equal(address)
end

class AddressesController < ApplicationController
def create
@address = Address.new(params[:address])

respond_to do |format|
  if @address.save
    flash[:notice] = 'Address was successfully created.'
    format.html { redirect_to(@address.addressable) }
    format.xml  { render :xml => @address, :status => :created,

:location => @address }
else
format.html { render :action => “new” }
format.xml { render :xml => @address.errors, :status =>
:unprocessable_entity }
end
end
end
end

Now the post to the create action can include :organization_id within
params[:address] instead of as a separate hash key, and all is well.

That said, the following should work w/ your current design:

it “assigns a newly created address as @address” do
address = mock(‘address’)
addresses = mock(‘addresses’)
addressable = mock_model(Organization, :id => “100”, :addresses =>
addresses)

Organization.stub!(:find_by_id).with(“100”).and_return(addressable)
addressable.stub(:addresses).and_return(addresses)
addresses.stub(:new).with({:these => ‘params’}).and_return(address)

post :create, :address => {:these => ‘params’}, :organization_id =>
“100”

assigns[:address].should equal(address)
end

class AddressesController < ApplicationController
before_filter :load_addressable

def create
@address = @addressable.addresses.new(params[:address])

respond_to do |format|
  if @address.save
    flash[:notice] = 'Address was successfully created.'
    format.html { redirect_to(@addressable) }
    format.xml  { render :xml => @address, :status => :created,

:location => @address }
else
format.html { render :action => “new” }
format.xml { render :xml => @address.errors, :status =>
:unprocessable_entity }
end
end
end

private

def load_addressable
if params[:organization_id]
@addressable = Organization.find_by_id(params[:organization_id])
end
end

end

Notes:

  • I changed @parent_object to @addressable, since that’s how the
    association is labeled in the code.
  • The only object in the code example that uses mock_model is the one
    that is actually needs to behave like an AR model in the context of
    this example

Let me know if you have any questions.

Cheers,
David

*unexpected message

On Mon, Oct 19, 2009 at 10:48 AM, Sergey R.
[email protected]wrote:

*unexpected message

Please copy the exact error instead of re-typing it.