I've created a small application to demonstrate the problem in more detail:

http://github.com/cs/nested_attributes_spec_demo

Just clone it, migrate the sqlite database and run `rake spec`. You'll see 1 failing and 1 succeeding spec. The failing one uses Mocking to the view. The succeeding example tests exactly the same thing but actually creates real records in the database (as Matt suggested). I hope there's a genius somewhere who's able to tell me what I'm doing wrong or to fix the bug.

Here's the shell script to get it running (for copy and paste):

git clone git://github.com/cs/nested_attributes_spec_demo.git
cd nested_attributes_spec_demo
rake db:migrate
rake db:test:clone
rake spec

On Aug 23, 2009, at 1:57 PM, Matt Wynne wrote:


On 23 Aug 2009, at 10:51, Christoph Schiessl wrote:

I have two models in a has_many relationship. The parent model
(Invoice) accepts the attributes for it's children (InvoiceItem).
The models and the associated controller (InvoicesController) are
absolutely standard stuff. This is the significant part of the model
code:

class Invoice < ActiveRecord::Base
has_many :items, :class_name => "InvoiceItem", :dependent => :destroy

accepts_nested_attributes_for :items, :allow_destroy => true, :reject_if => Proc.new { |attributes| attributes['quantity'].blank? && attributes['description'].blank? && attributes['unit_price'].blank?
 }

 validates_presence_of :recipient, :recipient_street
 validates_presence_of :recipient_zipcode, :recipient_city
end

class InvoiceItem < ActiveRecord::Base
 belongs_to :invoice
 validates_presence_of :invoice_id
 validates_presence_of :quantity, :description, :unit_price
end

Now, here's part of the view I'm trying to test:

<% form_for @invoice, :html => {:multipart => true} do |f| %>
<p>text fields for recipient, recipient_street, recipient_zipcode, recipient_city and so on go here</p>
 <% f.fields_for :items do |form_item| %>
<p>text fields for quantity, description, unit_price and so on go here</p>
   <% # exception is thrown in the next line: %>
   <% unless form_item.object.new_record? %>
     <br/><%= form_item.check_box :_delete %>
     <%= form_item.label :_delete, "Remove" %>
   <% end %>
 <% end %>
<% end %>

Everything is working just fine if i test it manually in the browser.
However, I don't get any rspec tests to work.

describe "/invoices/_form.html.erb" do
 before do
   @items = [mock_model(InvoiceItem), mock_model(InvoiceItem)]
assigns[:invoice] = @invoice = mock_model(Invoice, :items => @items)
   render
 end
 it "renders the invoice form" do
   response.should have_tag("form")
 end
end

When i run `rake spec:views` i get the following error (line numbers do not match with supplied sample code):

ActionView::TemplateError in '/invoices/_form.html.erb renders the invoice form'
You have a nil object when you didn't expect it!
You might have expected an instance of ActiveRecord::Base.
The error occurred while evaluating nil.new_record?
On line #3 of app/views/invoices/_form.html.erb

   1: <% form_for @invoice, :html => {:multipart => true} do |f| %>
   2:   <% f.fields_for :items do |form_item| %>
   3:     <% unless form_item.object.new_record? %>
   4:     <br/><%= form_item.check_box :_delete %>
   5:     <%= form_item.label :_delete, "Remove" %>
   6:   <% end %>

   app/views/invoices/_form.html.erb:3
   app/views/invoices/_form.html.erb:2
   app/views/invoices/_form.html.erb:1
   /spec/views/invoices/_form.html.erb_spec.rb:7
   /usr/local/lib/ruby/1.8/timeout.rb:53:in `timeout'
   vendor/plugins/rspec/bin/spec:4

So, how do i prevent this? I can't imagine that no one has tried that
before. I appreciate ANY advice or pointers greatly!

I'm just going to make a guess, but I'd say this could be to do with ActiveRecord's association proxy. I've had a few issues in the past trying to fake it with an array, as you've done here.

It's ugly, I know, but could you try building a real Invoice instance in the database (use FactoryGirl, Fixjour or something) and adding a couple of InvoiceItems to it in your before block? If that works it would help us to narrow down the problem.

cheers,
Matt
_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

_______________________________________________
rspec-users mailing list
rspec-users@rubyforge.org
http://rubyforge.org/mailman/listinfo/rspec-users

Reply via email to