S.Martignier
S.Martignier

Reputation: 403

Rails 4, edit multiple model in one form

I'm working on the following feature :

In one page, the user can upload multiple pictures at one time, and then on the following page he can edit the fields for those pictures.

So what i want is basically a form to edit multiple model at one time (the model are not yet saved in the database).

The application use the https://github.com/bootstrap-ruby/rails-bootstrap-forms to generate forms, but if you have a solution with only the form helpers from rails it would maybe be enough to help me to solve my problem.

I'm currently trying

<%= bootstrap_form_tag(url: import_save_client_pictures_path(@client), layout: :horizontal) do |f| %>
<% @imported_pictures.each_with_index do |picture, index| %>
  <%= bootstrap_form_for([@client, picture], url: import_save_client_pictures_path(@client), layout: :horizontal) do |ff| %>
  <div class="row">
    <div class="col-xs-12 col-sm-12 col-md-4 col-lg-4">
      <%= image_tag(picture.file_tmp_url, class: 'img-responsive') %>
    </div>
    <div class="col-xs-12 col-sm-12 col-md-8 col-lg-8">
      <%= ff.text_field :title, value: picture.title, required: true %>
      <%= ff.text_field :description_en, value: picture.description_en %>
      <%= ff.text_field :description_fr, value: picture.description_fr %>
      <%= ff.text_field :description_de, value: picture.description_de %>
      <%= ff.text_field :copyright, value: picture.copyright %>
      <%= ff.collection_select :country, country_sorted_list_with_first_country(:XX), :first, :second, selected: picture.country %>
      <%= ff.collection_check_boxes :category_ids, @client.categories.visible_for(current_user), :id, :title %>
      <%= ff.text_field(:reference) if current_user.global_admin? %>
    </div>
  </div>

  <%= '<hr />'.html_safe if (index + 1) != @imported_pictures.count %>
<% end %>
  <% end %>

<div class="form-actions">
  <%= f.primary %>
 <% end %>
 <%= link_to t(:cancel), [@client, :pictures], class: 'btn btn-default' %>
 </div>

But when i click on sending the form, nothing happen.

I'm thinking on going to only one form and generate all the fields for each picture with setting the fields's names to something like 'field_name_index', but it's not very elegant.

What i try to achieve is to have some sort of array that is passed to the controller with the data being like pictures = [picture_1_fields, picture_2_fields] and so

Do you guys can help me?

Thanks :)

Edit: To be precise, Pictures are not nested form or some other models

Upvotes: 0

Views: 402

Answers (1)

max
max

Reputation: 101811

This answer requires you to make an effort to understand the concepts and actually impliment it yourself. Make sure you read the documentation thoughly!

Setup accepts_nested_attributes_for in the parent model:

class Client < ApplicationRecord
  has_many :pictures
  accepts_nested_attributes_for :pictures
  validates_associated :pictures
end

class Picture < ApplicationRecord
  belongs_to :client
end

Then use fields_for to generate fields for the nested records:

<%= bootstrap_form_tag(url: import_save_client_pictures_path(@client), layout: :horizontal) do |f| %>
  <%= f.fields_for :pictures do |ff| %>
      <%= ff.text_field :title, value: picture.title, required: true %>
      <%= ff.text_field :description_en, value: picture.description_en %>
      # ...
  <% end %>
<% end %>

You might notice that there are no inputs if a Client has no pictures. To solve this you need to seed the association with new records. This is usually done in in the action that presents the form:

def new
  3.times { @client.pictures.new }
end

To permit the nested params you want to use a nested array of keys:

def import_save_client_pictures
  if @client.update(picture_params)
    redirect_to '/somewhere'
  else
    render :some_view
  end
end

def picture_params
  params.require(:client)
    .permit(pictures_attributes: [:title, :description_en])
end

But consider using AJAX to save/update the child records in individual POST/PATCH requests behind the scenes. It usually gives a better user experience and only requires a standard CRUD controller.

Upvotes: 0

Related Questions