Search code examples
ruby-on-railsrubytwitter-bootstrapsimple-formcocoon-gem

Nested Form not rendering or saving data


I'm new to Ruby and also Rails, and I'm trying to put together a nested form that ultimately creates a page but also allows the user to create individual parts inline before submitting the page. The inline form contains two buttons, one adds a part and the other one removes it. Here are my relevant files (please let me know if you need to see any other) and I'll list the problems I'm having after:

FYI, the gems I'm using are: Slim, Simple Form, cocoon and Bootstrap. On Rails 4.

_form.html.slim

= simple_form_for(@page, html: { class: 'form-horizontal' }) do |f|

  = f.input :title, label: 'Title'
  = f.input :description, label: 'Desc'

  .form-group
    .col-xs-10
      label Parts
      .form-inline
        = f.simple_fields_for :parts do |part|
          = render 'part_fields', f: part
        .links
          = link_to_add_association 'Add Part', f, :parts

  = f.button :submit

_parts_fields.html.slim

= f.input :part_type, collection: ['String 1', 'String 2'], prompt: 'Part type', label: false
= f.input :part_title, placeholder: 'Part title', label: false
= f.input :part_desc, placeholder: 'Part description', label: false
= link_to_remove_association 'Remove Part', f

/models/page.rb

class Page < ActiveRecord::Base
    belongs_to :project
    has_many :parts
    accepts_nested_attributes_for :parts
end

/models/part.rb

class Part < ActiveRecord::Base
    belongs_to :page
end

/controllers/pages_controller.rb

class PagesController < ApplicationController
    def index
        @pages = Page.all

        respond_to do |format|
            format.html 
            format.json { render json: @pages }
        end
    end

    def new
        @page = Page.new

        respond_to do |format|
            format.html 
            format.json { render json: @page }
        end
    end

    def edit
        @page = Page.find(params['id'])
    end

    def create
    @page = Page.new(page_params)

        respond_to do |format|
            if @page.save
                format.html { redirect_to(@page) }
                format.json { render json: @page, status: :created, location: @page }
            else
                format.html { render action: 'new' }
                format.json { render json: @page.errors, status: :unprocessable_entity }
            end
        end
  end

  def update
    @page = Page.find(params['id'])

        respond_to do |format|
            if @page.update_attributes(page_params)
                format.html { redirect_to(action: 'index') }
                format.json { head :ok }
            else
                format.html { render action: 'edit' }
                format.json { render json: @page.errors, status: :unprocessable_entity }
            end
        end
  end

    def page_params
        params.require(:page).permit(:title, :description, parts_attributes: [:id, :part_type, :part_title, :part_desc])
    end
end # End Pages Controller

Routes

resources :projects do
    resources :pages
end

resources :pages

resources :parts

Problems:

1) The form is not saving any data (can't edit/update current pages or create new ones). Update: fixed, see my own answer below.

2) On the partial I'm using a collection to have a dropdown menu, but those test values are hard-coded right now. How can I have a dropdown that populates each field with columns from the db?

3) The inline form elements which come from the partial are not being rendered back on the main form. All I see is the "Parts" label and no elements underneath it. Update: @pages.parts.build solved this.

Appreciate any help you guys can give me.


Solution

  • The form is now saving data as expected. In one of my partials I had two fields that were identical and thus creating a silent conflict for me. In addition, after I resolved this I started to get an Unpermitted parameter: _destroy error, and the fix was to add :_destroy to the list of required params for parts_attributes.