LearningRoR
LearningRoR

Reputation: 27192

Nested Form: Resource adds dynamically but doesnt get created?

I am using the nested form gem and i add products dynamically to the form. When i do click "add", another product resource appears but on creation it ERASES the former ones from being created entirely. This is how the scenario goes:

  1. Fill in Location
  2. Choose Date
  3. Fill in Product ( one is already on form)
  4. Add 5 more products (Products 2, 3, 4, 5)
  5. Fill in All Products
  6. "click" Create
  7. Created Product 5

This is how my nested form looks:

<%= nested_form_for @location, :url => products_path(@product) do |f| %>
    <%= f.label :business %>
    <%= f.text_field :business %>
    <%= f.label :address %>
    <%= f.text_field :address %>

 <%= f.fields_for :product_dates, :url => products_path(@product) do |d| %>
     <%= d.label :date %>
     <%= d.date_select :date %>

 <%= d.fields_for :products, :url => products_path(@product) do |p| %>
     <%= p.text_field :name %>
     <%= p.text_field :price %>
     <%= p.text_field :tag_list %>
     <%= p.link_to_remove "Remove Product" %>       
     <% end %>
     <%= d.link_to_add "Add", :products %>
 <% end %>
 <%= f.submit "Finish" %>
<% end %>

Controller:

class ProductsController < ApplicationController

    def new
        @location = Location.new
        @product = Product.new
        product_date = @location.product_dates.build
        product_date.products.build
    end

    def create
        @location = Location.create(params[:location])
        if @location.save
            flash[:notice] = "Products Created."
            redirect_to :action => 'index' 
        else
            render :action => 'new'
        end
  end

Models:

class User < ActiveRecord::Base
  devise
  attr_accessible :email, :password, :password_confirmation, :remember_me
  has_many :products,  :dependent => :destroy
end


class Location < ActiveRecord::Base
    attr_accessible :address, :business, :product_dates_attributes
    has_many :products
    has_many :product_dates 
    accepts_nested_attributes_for :product_dates    
end

class ProductDate < ActiveRecord::Base
    attr_accessible :date, :products_attributes
    belongs_to :location
    belongs_to :user
    has_many :products
    accepts_nested_attributes_for :products
end

class Product < ActiveRecord::Base
    attr_accessible :name, :price, :tag_list
    belongs_to :user
    belongs_to :location
    belongs_to :product_date
end

Any Suggestions?

Upvotes: 0

Views: 315

Answers (1)

jamesc
jamesc

Reputation: 12837

First of all remove the url_for declarations on the fields_for declarations so you get

<%= nested_form_for @location, :url => products_path(@product) do |f| %>
    <%= f.label :business %>
    <%= f.text_field :business %>
    <%= f.label :address %>
    <%= f.text_field :address %>

    <%= f.fields_for :product_dates do |d| %>
       <%= d.label :date %>
       <%= d.date_select :date %>

       <%= d.fields_for :products do |p| %>
         <%= p.text_field :name %>
         <%= p.text_field :price %>
         <%= p.text_field :tag_list %>
         <%= p.link_to_remove "Remove Product" %>       
       <% end %>
       <%= d.link_to_add "Add", :products %>
    <% end %>
 <%= f.submit "Finish" %>
<% end %>

What is really confusing is your whole routing and params approach. It's just not right. You have a form_for @location with a :url products_path(@product) This will right royally cause issues with the params that are sent back and there in lies the problem. Stick with routing to location controller not the products controller by removing the products_path(@product) form your nested_form_for declaration and you will find that you will have all the necessary records saved but you will most likely need to change the redirect_to declaration in the locations_controller create action and the same for the update_action.

But why use the products controller at all when you are dealing with a location? Again this just isn't natural or intuitive.

One last thing. Your remove links won't work as you have not added the necessary :dependent => :destroy declaration to the has_many declarations and you are also missing the :reject_if procs and the :allow_destroy => true declarations on the accepts_nested_attributes declarations.

Can I strongly suggest that you 1) Use either the locations controller or the products controller not both I mean link to get to this form link_to the locations controller and set everything up there or use form_for @product rather than @location and handle everything in the products controller

2) watch the railscasts that this gem is based on very closely http://railscasts.com/episodes/196-nested-model-form-part-1 http://railscasts.com/episodes/197-nested-model-form-part-2

3) Spend some time learning about how rails form view helpers arrange for the params hash to be organised in the controllers actions. In your case, have a close look at your log file for the parameters that come into the create action as things currently stand. You will most likely see that the params are not nested as you would exect them to be which is why the nested attributes declaration is not behaving as expected

Upvotes: 1

Related Questions