yerassyl
yerassyl

Reputation: 3048

How to handle data from nested forms in Rails 4 with cocoon gem?

I am using Cocoon gem to do nested forms. I have models like that:

# request.rb
has_many :filled_cartridges, inverse_of: :request, dependent: :destroy
	accepts_nested_attributes_for :filled_cartridges, :reject_if => :all_blank, allow_destroy: true

#filled_cartridge.rb
belongs_to :request

Inside of my form_for @request i have nested form like that:

<div id="filled_cartridges">
  <%= f.fields_for :filled_cartridges do |filled_cartridge| %>
    <%= render 'filled_cartridge_fields', f: filled_cartridge %> 	
  <% end %>
<div class="links">
  <%= link_to_add_association 'add', f, :filled_cartridges %>
</div>

Where filled_cartridge_fields partial is like that:

<fieldset>
  <%= f.text_field :cartridge_id %>
  <%= f.hidden_field :_destroy %>
  <%= link_to_remove_association "remove", f %>
</fieldset>

When i click on "add" it adds one more . When clicking on "remove" it removes that . When i submit form the params for nested form look like that:

filled_cartridges_attributes: !ruby/hash:ActionController::Parameters
    '0': !ruby/hash:ActionController::Parameters
      cartridge_id: '12'
      _destroy: 'false'
    '1429260587813': !ruby/hash:ActionController::Parameters
      cartridge_id: '2'
      _destroy: 'false'
How do i access these params, and how to save them. How to traverse over these params and save them, or do Cocoon gem has some built in functionality? And finally how to check if these params are set? Since it is nested, it tricks me. EDIT: My request_controllers#create:

def create 
  @request = Request.new( request_params )
  # code for handling Request model	 
  # here i want to handle nested model too (filled_cartridge)
  @request.save
  if @request.save
     flash[:success] = "Заявка была добавлена"
     redirect_to @request
  else 
     render 'new'	
  end
end

EDIT2: my strong params:

def request_params
  params.require(:request).permit(:name, :address, :phone, :mobile, :type, :description, :priority, :responsible, :price, :payed, :date, filled_cartridges_attributes: [:cartridge_id, :_destroy], :stype_ids => [], :social_media =>[])
end

Upvotes: 2

Views: 410

Answers (1)

Antoine
Antoine

Reputation: 569

In a recent project using cocoon I had to access the params of the attributes about to be saved. I figured a code in my create action in my controller. The trick is to understand how to retrieve the key of the hash of the attribute that is about to be saved. The key of the hash is that number '1429260587813' that is in your params

 ...
'1429260587813': !ruby/hash:ActionController::Parameters
  cartridge_id: '2'
  _destroy: 'false'

So you need to create a loop in your create action to retrieve this key using ruby hash method "keys". I do a loop because when using cocoon dynamic nested field I might create more than one nested attributes at once so it means more than one key to retrieve.

Here is a the code that worked for me, read my comments which explains the different steps of this code. I hope it will help you to adapt it to your needs.

    #Here I just initialize an empty array for later use
    info_arr = []
    #First I check that the targeted params exist (I had this need for my app) 
    if not params[:recipe]["informations_attributes"].nil?
        #z variable will tell me how many attributes are to be saved
        z = params[:recipe]["informations_attributes"].keys.count
        x = 0
        #Initiate loop to go through each of the attribute to be saved
        while x < z
            #Get the key (remember the number from above) of the first hash (params) attribute
            key = params[:recipe]["informations_attributes"].keys[x]
            #use that key to get the content of the attribtue
            value = params[:recipe]["informations_attributes"][key]
            #push the content to an array (I had to do this for my project)
            info_arr.push(value)
            #Through the loop you can perform actions to each single attribute
            #In my case, for each attributes I creates a new information association with recipe
            @recipe.informations.new(title: info_arr[x]["title"]).save
            x = x +1
        end
    end

This work to access cocoon nested attribute content and apply actions based on your need. This worked for me so you should be able to use this sample code and adapt it to your need.

Upvotes: 2

Related Questions