Rails nested forms headache – following RailsCast 196

This has been doing my head in for hours and I think I can safely say I cannot solve it.

I was trying to follow this railscast in our project: http://railscasts.com/episodes/196-nested-model-form-revised

It’s really simple. A has_many relationship and the ability to add/remove the related model.

Assets are related to a client_schedule through the asset_client_schedule

Firstly, no matter if I prepopulate the database with some relationships or leave it empty, ONE line always shows up in the fields_for, with the first available client_schedule in the dropdown.

Then, when I add a few lines, they don’t get posted back. I verified with byebug that params only has the last item in it every time. I suspect this is because the select field is given the same “name” every time, despite being passed a child_index

Seriously this is driving me nuts. What am I missing?

Asset.rb

    class Asset < ActiveRecord::Base
  has_many :asset_client_schedules
  has_many :client_schedule_rates, through: :asset_client_schedules:asset_subcontractor_schedules
  accepts_nested_attributes_for :client_schedule_rates, allow_destroy: true

end

asset_client_schedule.rb

class AssetClientSchedule < ActiveRecord::Base
  belongs_to :asset
  belongs_to :client_schedule_rate
end

assets/_form.html.erb – default rails view with

 <%= f.fields_for :asset_client_schedules do |builder| %>
        <%= render 'asset_client_schedule_item', f: builder %>
    <% end %>

    <%= link_to_add_item "Add", f, :asset_client_schedules  %>

assets_helper.rb

module AssetsHelper
  def link_to_add_item(name, f, association)
    new_object = f.object.send(association).klass.new
    id = new_object.object_id
    item = f.fields_for(association, new_object, child_index: id) do |builder|
      render(association.to_s.singularize + "_item", f: builder)
    end
    link_to(name, '#', class: "add-item", data: {id: id, fields: item.gsub("n", "")})
  end
end

And the partial _asset_client_schedule_item.erb

<fieldset>
  <%= f.select :client_schedule_rate_id, options_from_collection_for_select(@client_schedule_rates, "id", "code") %>
  <%= f.hidden_field :_destroy %>
  <%= link_to "Delete", "#", class:"remove-item" %>
</fieldset>

Finally the coffescript for this

jQuery  ->
  $('form').on 'click', '.remove-item', (event) ->
    $(this).prev('input[type=hidden]').val('1')
    $(this).closest('fieldset').hide()
    event.preventDefault()

  $('form').on 'click', '.add-item', (event) ->
    time = new Date().getTime()
    regexp = new RegExp($(this).data('id'), 'g')
    $(this).before($(this).data('fields').replace(regexp, time))
    event.preventDefault()


Source: ruby

Leave a Reply