accepts_nested_attributes_for doesn't show output

Hello,
     An earlier post where I asked how to put mulitple tables's input
on one screen was answered with "accepts_nested_attributes_for" and
that seems to be what I need, but nothing appears on the screen for
the nested section. I've been using ideas from:

http://masonoise.wordpress.com/2010/07/23/rails-and-forms-using-accepts_nested_attributes_for/
http://railscasts.com/episodes/196-nested-model-form-part-1
http://asciicasts.com/episodes/196-nested-model-form-part-1
http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html#method-i-accepts_nested_attributes_for

The following are my classes and a little code from the
"_form.html.erb" that I'm trying to make work:

class Person < ActiveRecord::Base
  default_scope :order => 'last_name'
  has_many :people_skills

  accepts_nested_attributes_for :people_skills, :update_only =>
true, :allow_destroy => true
end

class PeopleSkill < ActiveRecord::Base
  belongs_to :person
end

Also, there is a field in the people_skills table that is person_id,
which I remember reading in the "Agile.." book creates an FK there.

<%= form_for(@person) do |f| %>
  <% if @person.errors.any? %>
    # ... usual code concerning errors
  <% end %>

  <%= f.fields_for :people_skills do |builder| %>
      <%= builder.label :skill, "Skill" %><br />
      <%= builder.text_field :skill %>
    </p>
    <p>
      <%= builder.label :competency, "Competency" %><br />
      <%= builder.text_field :competency %>
    </p>
  <% end %>

  <table>
    <tr>
      <td>
        <div class="field">
          <%= f.label :first_name %><br />
          <%= f.text_field :first_name %>
  </div>
      </td>
      <td>
AND THEN MANY OTHER ROWS AND FIELDS OF THIS TABLE.

The table data for the class "Person" shows up fine, but anything with
the "f.fields_for..." is invisible (but doesn't cause a syntax
error). What DOES cause an error is to put
"@Person.people_skills.build" in the "new" method of
people_controller.rb.

So, I'm looking for a way to have one screen which creates entries in
2 tables, linked by the PK-FK. What am I doing wrong or forgetting to
do?
     Thanks,
          Barney

Hi Barney,

I believe I am having the same problem you experienced, though my code is a little different. If you or anyone else can tell me how to solve it that would be great!

I am creating a db of Universities and resources. One University can have many resources, but one resource can only come from one University. I am trying to create a form with nested attributes, so hat users wil be encouraged to give details about the University where the resource comes from.

Code from views/universities/_form:

<%= form_for(@university) do |f| %>
<% if @university.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@university.errors.count, "error") %> prohibited this university from being saved:</h2>

<ul>
<% @university.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :address %><br />
<%= f.text_field :address %>
</div>
<div class="field">
<%= f.label :country %><br />
<%= f.text_field :country %>
</div>

<% f.fields_for :resources do |builder| %>
<%= render "resources/form", :f => builder %>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

Code from views/resources/_form:

<div class="field">
<%= f.label :subject %><br />
<%= f.text_field :subject %>
</div>
<div class="field">
<%= f.label :course %><br />
<%= f.text_field :course %>
</div>
<div class="field">
<%= f.label :alternative_use %><br />
<%= f.text_field :alternative_use %>
</div>
<div class="field">
<%= f.label :author %><br />
<%= f.text_field :author %>
</div>
<div class="field">
<%= f.label :resource_type %><br />
<%= f.text_field :resource_type %>
</div>

Code from models:

     class University < ActiveRecord::Base
has_many :resources
accepts_nested_attributes_for :resources, :allow_destroy => :true,
     :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
attr_accessible :resource_attributes
end

class Resource < ActiveRecord::Base
#Defines the relationship between resource and user.
belongs_to :user
belongs_to :university
attr_accessible :resource_type, :subject, :author, :course, :alternative_use,
#Need to add some more validation to the fields.
def self.search(search)
   if search
     find(:all, :conditions => ['subject LIKE ?', "%#{search}%"])
   else
     find(:all)
   end
end
#End class.
end

Thanks in advance,
Jen!

I forgot to mention that currently each of my tables is handled by a separate controller.

I thought this would be ok and anything entered in my resources _form partial would be handled by the 'resources' controller etc. However looking at the rails cast source code has confused me a bit, as it seems that all the tables are managed by one controller. Are my nested fields not rendering because the universities table and resources have their own totally separate controllers?

I will be experimenting with this more tomorrow. If someone could clarify this point about the controllers it would really help.

Thanks,
Jen!

Hello,
An earlier post where I asked how to put mulitple tables's input
on one screen was answered with "accepts_nested_attributes_for" and
that seems to be what I need, but nothing appears on the screen for
the nested section. I've been using ideas from:

http://masonoise.wordpress.com/2010/07/23/rails-and-forms-using-accep...http://railscasts.com/episodes/196-nested-model-form-part-1http://asciicasts.com/episodes/196-nested-model-form-part-1http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/Clas

The following are my classes and a little code from the
"_form.html.erb" that I'm trying to make work:

class Person < ActiveRecord::Base
default_scope :order => 'last_name'
has_many :people_skills

    accepts\_nested\_attributes\_for :people\_skills, :update\_only =&gt;

true, :allow_destroy => true
end

class PeopleSkill < ActiveRecord::Base
belongs_to :person
end

Also, there is a field in the people_skills table that is person_id,
which I remember reading in the "Agile.." book creates an FK there.

<%= form_for(@person) do |f| %>
<% if @person.errors.any? %>
# ... usual code concerning errors
<% end %>

<%= f.fields_for :people_skills do |builder| %>
<%= builder.label :skill, "Skill" %><br />
<%= builder.text_field :skill %>
</p>
<p>
<%= builder.label :competency, "Competency" %><br />
<%= builder.text_field :competency %>
</p>
<% end %>

<table>
<tr>
<td>
<div class="field">
<%= f.label :first_name %><br />
<%= f.text_field :first_name %>
</div>
</td>
<td>
AND THEN MANY OTHER ROWS AND FIELDS OF THIS TABLE.

The table data for the class "Person" shows up fine, but anything with
the "f.fields_for..." is invisible (but doesn't cause a syntax
error). What DOES cause an error is to put

What is the error message? What's the stack trace?

"@Person.people_skills.build" in the "new" method of
people_controller.rb.

What's the code in your controller - @Person.people... or
@person.people... - is the error message due to a capitalization typo?
(wouldn't know without seeing the error msg

I forgot to mention that currently each of my tables is handled by a separate controller.

I thought this would be ok and anything entered in my resources _form partial would be handled by the 'resources' controller etc. However looking at the rails cast source code has confused me a bit, as it seems that all the tables are managed by one controller. Are my nested fields not rendering because the universities table and resources have their own totally separate controllers?

I will be experimenting with this more tomorrow. If someone could clarify this point about the controllers it would really help.

Thanks,
Jen!

   Hi Barney,

I believe I am having the same problem you experienced, though my code is a little different. If you or anyone else can tell me how to solve it that would be great!

I am creating a db of Universities and resources. One University can have many resources, but one resource can only come from one University. I am trying to create a form with nested attributes, so hat users wil be encouraged to give details about the University where the resource comes from.

Code from views/universities/_form:

<%= form_for(@university) do |f| %>
<% if @university.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@university.errors.count, "error") %> prohibited this university from being saved:</h2>

<ul>
<% @university.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :address %><br />
<%= f.text_field :address %>
</div>
<div class="field">
<%= f.label :country %><br />
<%= f.text_field :country %>
</div>

<% f.fields_for :resources do |builder| %>

You have to make sure that a resource has been built for it to show the fields, otherwise the fields_for call will not display the form fields as there is not a model Instance behind the fields. This is usually done by scoping a build through the association. For example if a university has a has_many association named resources then somewhere in the controller or view you would have to make a call similar to: @university.resources.build. This will create a new instance of the resources model to be used by fields for.

I forgot to mention that currently each of my tables is handled by a
separate controller.

A controller is simply an entry/access point, you can pull in data
from any model in any controller and pass it to any view to be used.

I thought this would be ok and anything entered in my resources _form
partial would be handled by the 'resources' controller etc. However

No.

The form 'decides' which controller to pass _all_ the form data to,
you then need to ensure that the receiving controller saves/updates
the model and its relations.

looking at the rails cast source code has confused me a bit, as it seems
that all the tables are managed by one controller. Are my nested fields

Controllers don't 'manage' tables, they simply collect model data and
pass it to a view, any required business logic should be handled by
the models. You should keep the code in your controllers to a minimum,
if you find that you are beginning to bloat your controller actions,
or start adding loads of private methods, then you need to look at
your code, and find a way to re-factor out into helpers or models or
lib modules etc.

For Example;

class ExamplesController < ApplicationController
  def show
    @example = Example.find(params[:id])
    @authors = Author.all
    render 'show'
  end
end

views/examples/show.html.erb
# This view can now display the example by accessing @example
# It can also display a list of authors of all the examples by
accessing @authors
# So you can create whatever data you want in your controller, and it
can be accessed in the view that is rendered.

not rendering because the universities table and resources have their
own totally separate controllers?

No.

You need to build any relations prior to rendering the view, you do
this in your new and edit actions in your controller.

Example:

class Person < ActiveRecord::Base
  belongs_to :address
  accepts_nested_attributes_for :address
end

class Address < ActiveRecord::Base
has_many :people
accepts_nested_attributes_for :people
end

class PeopleController < ApplicationController
  def new
    @person = Person.new
    @person.build_address
  end

  def edit
    @person = Person.find(params[:id])
    @person.build_address unless @person.address #don't build an
address if the person already has one
  end
end

class AddressController < ApplicationController
  def new
    @address = Address.new
    @address.people.build
  end

  # This is untested, I haven't needed to set up a nested form for a
model that has a has_many relation
  def edit
    @address = Address.find(params[:id])
    @address.people.build unless @address.people.size > 0 #don't build
people if the address already has people
  end
end

Also, if you take a look at your Resources form, unless you have
removed some of the code, it is not a form, just a list of fields for
a form. If you try and use that partial on it's own, you will not be
able to.

When I want to re-use form fields in other forms, I move the fields
out into a separate partial and render it as you have done in your
University form. The only difference, is that I create an assets
folder in the relevant view folder for any additional 'out of the
norm' views/partials. Surprisingly, I call the partial
_form_fields..... Then, both the University form, and the resources
form can both use the same views/resources/assets/
_form_fields.html.erb partial.

The fields can then be used by any other nested form. So, if you
decide to add another model that utilises the resources model, you can
easily create another nested form by calling in the resources
_form_fields partial.

HTH

Paul

Hi Paul,
Thanks for the reply!

Am I correct in thinking that for the data my user enters in the

fields relating to resources to be inserted in to the resources
table I need to render a complete form, not just a list of fields?

I have tried this approach and am receiving the following error:

NoMethodError in Universities#new

Showing /home/resource_portal/website/app/views/resources/_form.html.erb
where line #1 raised:

undefined method `model_name' for NilClass:Class

Extracted source (around line #1):

1: <%= form_for(@resource) do |f| %>
2: <% if @resource.errors.any? %>
3: <div id="error_explanation">
4: <h2><%= pluralize(@resource.errors.count, "error") %> prohibited this resource from being saved:</h2>

  Trace of template inclusion:

app/views/universities/_form.html.erb,
app/views/universities/new.html.erb

``

Any further assistance with this would be great.

Thanks in advance,

Jen!

The error simply means that @resource is nil. If you set this in the
controller using find then maybe the find did not find a matching
record.

Colin

Hi Colin,
I can't see anything in my controller that indicates I have set @resource to nil.
When I go directly to the resources form it renders fine and I can add data about new resources. It's just when trying to render the form as a partial within the universities/_form view.

Do I need to add something in the 'universities_controller' that gives @resource a value. Perhaps '@resource = Resource.new'?

Below is the code from the 'universities_controller' so far:

class UniversitiesController < ApplicationController
#insure users are signed in before viewing these pages
before_filter :authenticate

   # GET /universities
   # GET /universities.xml
   def index
     @universities = University.all

     respond_to do |format|
       format.html # index.html.erb
       format.xml { render :xml => @universities }
     end
   end

   # GET /universities/1
   # GET /universities/1.xml
   def show
     @university = University.find(params[:id])

     respond_to do |format|
       format.html # show.html.erb
       format.xml { render :xml => @university }
     end
   end

   # GET /universities/new
   # GET /universities/new.xml
   def new
     @university = University.new

     respond_to do |format|
       format.html # new.html.erb
       format.xml { render :xml => @university }
resource = @university.resources.build

     end
   end

   # GET /universities/1/edit
   def edit
     @university = University.find(params[:id])
   end

   # POST /universities
   # POST /universities.xml
   def create
     @university = University.new(params[:university])

     respond_to do |format|
       if @university.save
         format.html { redirect_to(@university, :notice => 'University was successfully created.') }
         format.xml { render :xml => @university, :status => :created, :location => @university }
       else
         format.html { render :action => "new" }
         format.xml { render :xml => @university.errors, :status => :unprocessable_entity }
       end
     end
   end

   # PUT /universities/1
   # PUT /universities/1.xml
   def update
     @university = University.find(params[:id])

     respond_to do |format|
       if @university.update_attributes(params[:university])
         format.html { redirect_to(@university, :notice => 'University was successfully updated.') }
         format.xml { head :ok }
       else
         format.html { render :action => "edit" }
         format.xml { render :xml => @university.errors, :status => :unprocessable_entity }
       end
     end
   end

   # DELETE /universities/1
   # DELETE /universities/1.xml
   def destroy
     @university = University.find(params[:id])
     @university.destroy

     respond_to do |format|
       format.html { redirect_to(universities_url) }
       format.xml { head :ok }
     end
   end
end

Thanks,
Jen.

Please don't top post, it makes it difficult to follow the thread.
Insert your reply at appropriate point(s) in previous post. Thanks.

Hi Colin,
I can't see anything in my controller that indicates I have set @resource to
nil.
When I go directly to the resources form it renders fine and I can add data
about new resources. It's just when trying to render the form as a partial
within the universities/_form view.

I had missed the fact that you were in a partial. Have a look at the
Rails Guide on Layouts and Rendering, specifically the section on
using partials and passing values to it.

If you have not already done so, also have a good look the other
guides, it will be time well spent.

Colin

Hi,
After getting nowhere I decided to follow this article:

http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes

This meant replicating some already existing fields in my universities/_form, but I felt it would atleast rule out the possibility I was doing something silly with partials. Now I am receiving the following error:

NoMethodError in Universities#new

Showing /home/resource_portal/website/app/views/universities/_form.html.erb where line #26 raised:

undefined method `fields_for' for nil:NilClass

Extracted source (around line #26):

23: <%= f.label :country %><br />
24: <%= f.text_field :country %>
25: </div>
26: <%= form.fields_for :resources do |resource| %>
27: <%= f.label :resource_type %><br />
28: <%= f.text_field :resource_type %>
29: </div>

Trace of template inclusion: app/views/universities/new.html.erb

Rails.root: /home/resource_portal/website
Application Trace | Framework Trace | Full Trace

rake-0.8.7/ruby/1.9.1/gems/activesupport-3.0.3/lib/active_support/whiny_nil.rb:48:in `method_missing'

My code for the models, universities controller and view is attached. Can someone please point out what I am doing wrong? I have read many articles, posts and have tried many variations to achieve this. Do I need to set @resources and @universities to equal some value before rendering the form?

Code for controller:

class UniversitiesController < ApplicationController
#insure users are signed in before viewing these pages
before_filter :authenticate

   # GET /universities
   # GET /universities.xml
   def index
     @universities = University.all

     respond_to do |format|
       format.html # index.html.erb
       format.xml { render :xml => @universities }
     end
   end

   # GET /universities/1
   # GET /universities/1.xml
   def show
     @university = University.find(params[:id])

     respond_to do |format|
       format.html # show.html.erb
       format.xml { render :xml => @university }
     end
   end

   # GET /universities/new
   # GET /universities/new.xml
   def new
     @university = University.new
@resource = @university.resources.build
     respond_to do |format|
       format.html # new.html.erb
       format.xml { render :xml => @university }

     end
   end

   # GET /universities/1/edit
   def edit
     @university = University.find(params[:id])
   end

   # POST /universities
   # POST /universities.xml
   def create
     @university = University.new(params[:university])

     respond_to do |format|
       if @university.save
         format.html { redirect_to(@university, :notice => 'University was successfully created.') }
         format.xml { render :xml => @university, :status => :created, :location => @university }
       else
         format.html { render :action => "new" }
         format.xml { render :xml => @university.errors, :status => :unprocessable_entity }
       end
     end
   end

   # PUT /universities/1
   # PUT /universities/1.xml
   def update
     @university = University.find(params[:id])

     respond_to do |format|
       if @university.update_attributes(params[:university])
         format.html { redirect_to(@university, :notice => 'University was successfully updated.') }
         format.xml { head :ok }
       else
         format.html { render :action => "edit" }
         format.xml { render :xml => @university.errors, :status => :unprocessable_entity }
       end
     end
   end

   # DELETE /universities/1
   # DELETE /universities/1.xml
   def destroy
     @university = University.find(params[:id])
     @university.destroy

     respond_to do |format|
       format.html { redirect_to(universities_url) }
       format.xml { head :ok }
     end
   end
end

Code for models:

class University < ActiveRecord::Base
has_many :resources
accepts_nested_attributes_for :resources, :allow_destroy => :true,
     :reject_if => proc { |attrs| attrs.all? { |k, v| v.blank? } }
attr_accessible :resource_attributes
end

class Resource < ActiveRecord::Base
#Defines the relationship between resource and user.
belongs_to :user
belongs_to :university
attr_accessible :resource_type, :subject, :author, :course, :alternative_use,
#Need to add some more validation to the fields.
def self.search(search)
   if search
     find(:all, :conditions => ['subject LIKE ?', "%#{search}%"])
#Join tables here

   else
     find(:all)
   end
end
#End class.
end

Code for views:

<%= form_for(@university) do |f| %>
<% if @university.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(@university.errors.count, "error") %> prohibited this university from being saved:</h2>

<ul>
<% @university.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>

<div class="field">
<%= f.label :name %><br />
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :address %><br />
<%= f.text_field :address %>
</div>
<div class="field">
<%= f.label :country %><br />
<%= f.text_field :country %>
</div>
<%= form.fields_for :resources do |resource| %>
<%= f.label :resource_type %><br />
<%= f.text_field :resource_type %>
</div>
<% end %>
<div class="actions">
<%= f.submit %>
</div>
<% end %>

<h1>New university</h1>

<%= render 'form' %>
<ul>
<li> <%= link_to 'Back', universities_path %> </li>
</ul>

Thanks in advance for any further assistance,
Jen.

guy,

you're using f.label, so then you have to use

f.fields_for :something do |smth|
  smth.label :label, "description"
  smth.text_field

...

Hi,
After getting nowhere I decided to follow this article:

http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes

This meant replicating some already existing fields in my universities/_form, but I felt it would atleast rule out the possibility I was doing something silly with partials. Now I am receiving the following error:

NoMethodError in Universities#new

Showing /home/resource_portal/website/app/views/universities/_form.html.erb where line #26 raised:

undefined method `fields_for' for nil:NilClass

Extracted source (around line #26):

23: <%= f.label :country %><br />
24: <%= f.text_field :country %>
25: </div>
26: <%= form.fields_for :resources do |resource| %>

You have form.fields_for here while all your other form fields refer to f and your form_for defines |f|. Change this line to f.fields_for and that should fix your nil error

Hi, list.

Thanks for the help, nested forms working now.

Cheers,
Jen!