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://asciicasts.com/episodes/196-nested-model-form-part-1

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!