3

How can I add one more same set of inputs for example for education object, so I will have 2 new education objects after submitting? Preferable new set needs to be shown by clicking on icon that goes after existing set of inputs.

This is my new method:

def new
  @user = User.new
  @user.educations.build
  @user.works.build
end

And my view for it:

<%= simple_form_for [:admin, @user] do |u| %>
      <%= u.error_notification %>

      <%= u.input :name, label: "Name" %>
      <p><b>Photo</b></p>
      <%= image_tag(@user.photo_url, size: "80x90",
                    class:"img-rounded") if @user.photo? %>
      <%= u.input :photo, label: false %>
      <%= u.input :tel, label: "Tel.:" %>

      <h3>Education</h3>
      <hr>
      <%= u.simple_fields_for :educations do |e| %>
        <%= e.input :name, label: "University" %>
        <%= e.input :year_started, label: "Started" %>
        <%= e.input :year_finished, label: "Ended" %>
      <% end %>

      # icon `+`
      <i class="fa fa-plus fa-2x"></i>

      <h3>Work</h3>
      <hr>
      <%= u.simple_fields_for :works do |w| %>
        <%= w.input :name, label: "Name" %>
        <%= w.input :year_started, label: "Started" %>
        <%= w.input :year_finished, label: "Ended" %>
      <% end %>


      <%= u.button :submit, "Надіслати" %>
<% end %>
tetiross
  • 192
  • 3
  • 17

2 Answers2

2

If you wanted to add the extra objects when you invoke the new method, you'd just need to "build" more associated objects:

def new
  @user = User.new
  2.times do
    @user.educations.build
  end
  @user.works.build
end

This would give you two sets of education fields (no more code changes required).


If you wanted to invoke the extra objects/fields after you've already rendered the new method, you'll have to do it dynamically, through, as @Tom Walpole suggested, using something like Cocoon.

There is a dated, but good tutorial here.

I've written about it too.

--

Adding fields on the fly relies on a simple pattern:

  1. Button / Icon press
  2. Ajax call to controller
  3. Controller builds form with fields_for
  4. Ajax response puts new fields_for in DOM

The main difference between this (ajax) and something like the "Railscast" (static) method is it builds the fields_for properly in rails. No hack jobs...

#app/views/admin/users/new.html.erb
<%= link_to fa-icon("plus 2x"), admin_new_user_path, remote: true %>

If you're using font-awesome, you'll be best with the font-awesome-rails gem, as you get the fa-icon helper.

#app/controllers/users_controller.rb
class UsersController < ApplicationController
   respond_to :js, :html

   def new
     @user = User.new
     @user.educations.build
     @user.works.build unless request.xhr?
   end
end

#app/views/users/new.js.erb
var form = $("<%=j render 'users/new' ");
$("form#new_admin_user [[fields_for_identifier]]").html($(form).html());

The big trick with this is the child_index: Time.now.to_i method. The big problem with the "static" approach is that the id of each new field will be exactly the same as the last, messing up your params:

#app/views/users/new.html.erb
<% if request.xhr? %>
  <%= simple_form_for [:admin, @user] do |u| %>
      <%= u.simple_fields_for :educations, child_index: Time.now.to_i do |e| %>
         <%= e.input :name, label: "University" %>
         <%= e.input :year_started, label: "Started" %>
         <%= e.input :year_finished, label: "Ended" %>
      <% end %>
  <% end %>
<% else %>
   ... your code ...
<% end %>

The above should work, although may need tweaking.

Community
  • 1
  • 1
Richard Peck
  • 76,116
  • 9
  • 93
  • 147
1

Easiest solution is probably the cocoon gem - https://github.com/nathanvda/cocoon

Thomas Walpole
  • 48,548
  • 5
  • 64
  • 78