1

Currently working on nested forms with the following railscast http://railscasts.com/episodes/196-nested-model-form-revised

I have an Opportunity model,

class Opportunity < ActiveRecord::Base
    has_many :headings
    accepts_nested_attributes_for :headings
end

a Heading model

class Heading < ActiveRecord::Base
    belongs_to :opportunity
    has_many :subheadings
    accepts_nested_attributes_for :subheadings
end

and a Subheading model

class Subheading < ActiveRecord::Base
    belongs_to :heading
end

Right now I am just working on the view for the new action for the Opportunity model.

<h1>Add an opportunity</h1>
<%= form_for(@opportunity, :html => {:role => 'form'}) do |f| %>
    <%= f.fields_for :headings do |builder| %>
        <%= render 'heading_fields', f: builder %>
    <% end %>
    <%= link_to_add_fields "Add heading", f, :headings %>
    <%= f.submit %>
<% end %>

And the _heading_fields.html.erb partial:

<fieldset>
    <%= f.label :title, "Heading" %>
    <%= f.text_field :title %>
    <%= f.hidden_field :_destroy %>
    <%= link_to "Remove section", '#', class: "remove_fields" %>
    <%= link_to_add_fields "Add section", f, :subheadings %>
</fieldset>

And finally the link_to_add_fields method in the application helper:

def link_to_add_fields(name, f, association)
    new_object = f.object.send(association).klass.new
    id = new_object.object_id
    fields = f.fields_for(association, new_object, child_index: id) do |builder|
        render(association.to_s.singularize + "_fields", f: builder)
    end
    link_to(name, '#', class: "add_fields", data: {id: id, fields: fields.gsub("\n", "")})
end

Now I am receiving the following error for the render call in the link_to_add_fields function:

syntax error, unexpected tIDENTIFIER, expecting keyword_end

It seems to have something to do with the underscore in the name of the partial being rendered in the link_to_add_fields method as it goes away when the underscore is not present.

Greatly appreciate any help at solving this headache!

Aventuris
  • 630
  • 5
  • 21
  • 1
    Can you paste full error? `syntax error, unexpected tIDENTIFIER, expecting keyword_end` this type of error generally occurs when you haven't closed your loops properly – Mandeep Jun 08 '14 at 06:48

2 Answers2

1

Debug

As mentioned in the comments, you're basically going to have an issue with the closing of your loops - Rails is expecting an end call, but you've set an identifier of sorts instead.

Having looked through your code, I cannot see where the issue might be, so I'll give you some details on how I'd debug it:

I would remove any elements which I would presume would be causing the issue, until I got it to work

For example, I would begin by replacing the def link_to_add_fields(name, f, association) with a piece of demo content:

def link_to_add_fields(name, f, association)
    "test"
end

If this outputs the correct string, it means the error is inside this method (which I'm guessing anyway). If this was the case, I would then try this:

def link_to_add_fields(name, f, association)
    new_object = f.object.send(association).klass.new
    id = new_object.object_id
    fields = "test"
    link_to(name, '#', class: "add_fields", data: {id: id, fields: fields})
end

If this works, it means the problem is likely going to be with the f.fields_for loop which you're using. Although this is just my guess, it's basically how I'd debug - sequentially remove things until it actually works


Fields

If you're looking to add fields dynamically to your form, you may wish to use the cocoon gem. The Railscast you're using is firstly a little out of date, and only allows you to add single fields to your form

The "right" way to do it is to use an ajax method, which I detail here

There's a very good site I found which showed you how to do it, but the site has since gone offline. Anyway, I'll explain it for you here:

#config/routes.rb
resources :controller do
   collection do
      get :add_field
   end
end

This gives you a route to send ajax requests to:

Controller

#app/views/controller/form.html.erb
<%= form_for @model do |f| %>
   <%= render partial: "fields", locals: { builder: f } %>
   <%= link_to "Add Field", controller_add_field_path, id: "add_field", remote: true %>
   <%= f.submit "test" %>
<% end %>

#app/views/controllers/your_controller.rb
Class YourController < ActiveRecord::Base
   def add_field
      @model = Model.new
      @model.association.build
      render "add_field", layout: false
   end
end

Views

Now you need to render the add_field view, with the fields_for partial

#app/views/controller/_form.html.erb
<%= form_for @model do |f| %>
    <%= render partial: "fields", locals: { builder: f } %>
<% end %>


#app/views/controller/_fields.html.erb
<%= f.fields_for :association, child_index: Time.now.to_i do |a| %>
    <%= a.text_feld :your_fields %>
<% end %>

JQuery

All you need to do then is create a way to fetch the new fields:

#app/assets/javascripts/application.js.coffee
$ ->
  $(document).on "ajax:success", "#add_field", (data) ->
       el_to_add = $(data).html()
       $('#new_form').append(el_to_add)
Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
  • 1
    I have solved the problem! After lots of work I found the culprit. I had an embedded ruby comment that isn't shown here that broke the whole thing. Learned about another little trap and learned a lot in the process. Thanks so much for the help. Much appreciated. – Aventuris Jun 09 '14 at 01:01
  • Nice! No problem - maybe you'll want to accept to ensure people know the answer is the one which helped? – Richard Peck Jun 09 '14 at 08:08
  • 1
    Completely forgot. Apologies. :) – Aventuris Jun 10 '14 at 00:04
0

I was able to achieve the dynamic form fields with https://github.com/nathanvda/cocoon For some reason rBates video is outdated for rails 4.+, Cocoon was able to fix was i had spent how debugging but in Vain. Thank you Rick Peck.

kalibbala
  • 498
  • 6
  • 12