mercredi 18 janvier 2017

Unpermitted parameters from nested attributes

I've looked through every post I can imagine regarding this, but can't come across a solution. I have a Task with a nested resource of Task Products which grabs its ID's from another database. There can be multiple Task Products nested in a Task, and each one is dynamically created with some Javascript and an Application Helper (both of which are purely a copy/paste on my part).

I built up the code for these nested parameters with the help of Railscast 196/197 and this post. All the relevant code is below, and then onto the problem:

task.rb:

class Task < ApplicationRecord
  has_many :task_products, :dependent => :destroy
  accepts_nested_attributes_for :task_products, :reject_if => lambda { |p| p.values.all?(&:blank?) }, :allow_destroy => true
end

task_controller.rb:

class TasksController < ApplicationController

  def new
    @task = Task.new
    @task.task_products.build
  end

    def task_params
  params.require(:task).permit(:id, :task_name, . . ., :created_at, :updated_at, 
                               :task_products_attributes => [:task_id, :product_id, :created_at, :updated_at])
end

application_helper.rb:

module ApplicationHelper

  def new_child_fields_template(form_builder, association, options = {})
    options[:object] ||= form_builder.object.class.reflect_on_association(association).klass.new
    options[:partial] ||= association.to_s.singularize
    options[:form_builder_local] ||= :f

    content_tag(:div, :id => "#{association}_fields_template", :style => "display: none") do
      form_builder.fields_for(association, options[:object], :child_index => "new_#{association}") do |f|
        render(:partial => options[:partial], :locals => { options[:form_builder_local] => f })
      end
    end
  end

application.js:

$(function() {
  $('form a.add_child').click(function() {
    var association = $(this).attr('data-association');
    var template = $('#' + association + '_fields_template').html();
    var regexp = new RegExp('new_' + association, 'g');
    var new_id = new Date().getTime();
    $(this).parent().before(template.replace(regexp, new_id));
    return false;
  });
});

_form.html.erb:

<%= form_for @task, url: tasks_path, method: :post, :html => {:multipart => true } do |f| %>
    <%= f.fields_for :task_products, TaskProduct.new do |builder| %>
      <%= render "task_product", :f => builder %>
    <% end %>
    <p><%= add_child_link "Add Product", :task_products %></p>
    <%= new_child_fields_template f, :task_products %>

_task_product.html.erb:

<div class="fields">
  <div class="form-group">
    <%= f.label :product_id, "Product:", class: 'col-sm-3 control-label' %>
      <%= f.collection_select(:product_id, @items, :id, :item_select, {:include_blank => 'Select Item...'}, {:class => 'form-control'}) %>
      <%= remove_child_link "Remove Product", f %>
  </div>
</div>

Code in console after submit along with the error it produced:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"KDQ...8bxur2A==", 
"task"=>{"task_type"=>"Store Order", 
    "task_products_attributes"=>{
    "0"=>{"product_id"=>"1", "_destroy"=>"false"}, 
    "1484792726712"=>{"product_id"=>"2", "_destroy"=>"false"}, 
    "new_task_products"=>{"product_id"=>"", "_destroy"=>"false"}}, 
    "initiated_by"=>"1", "initiated_for"=>"5", "active"=>"true", "status"=>"Pending Acceptance"}, 
"commit"=>"Create Task"}

Unpermitted parameters: 0, 1484792726712, new_task_products

Generated HTML examples of error producing code of multiple generated selects:

<select class="form-control" name="task[task_products_attributes][0][product_id]" id="task_task_products_attributes_0_product_id">
<select class="form-control" name="task[task_products_attributes][1484794199756][product_id]" id="task_task_products_attributes_1484794199756_product_id">

and its template, which I thought should be throwing back ' "_destroy"=>true' in the console?:

<select class="form-control" name="task[task_products_attributes][new_task_products][product_id]" id="task_task_products_attributes_new_task_products_product_id">

The problem, as seen above, is that my generated Task Product form is adding an additional bracketed identifier(child index?) into my select box for each item, and I don't know how to dive into the Application Helper to remove it, or move it where it belongs. Or does it actually belong there and I'm doing something else wrong? I get the feeling that each individual Task Product should have it's own unique identifier, but Rails isn't having any of that and says its unpermitted.

The 'new_child_fields_template' in the Application Helper is a bit over my head, and while I understand how it's getting the unique identifier to inject into my Task Product form, I don't know how it's throwing it into the "name=" field of my select that is apparently screwing everything up. Anybody have some guidance on how I can overcome this problem? Thanks!

Aucun commentaire:

Enregistrer un commentaire