Search code examples
ruby-on-railspartialpolymorphic-associations

Rails nested polymorphic form with javascripting


I want the following on my form:

enter image description here

Degree is polymorphic partial with has_many relation to profile. This partial is called by main form - profile. By pressing 'Add a Qualification' user can add as many degrees. I've been able to attach only one degree to profile which is the last one others are all ignored. I even know why it's happening because link_to is not able to pass profile instance. so I have to create new profile in degrees_controller as you can see in my code here. Can final profile instance pick up all others above when submitting 'Create Profile'.

Kindly any help so that I can have all of the degrees attached with form, I'm stuck on this for last couple of days with all permutations and combinations from SO and google. I'm ready to change code even....any help with this will be appreciated.


Solution

  • This is a polymorphic nested association and can be handled on client side with javascript. So, finally for nested fields I used the plugin Numerous.js. Just follow as the steps given in the qucikstart part of link by downloading the numerous.js file from the Github and saving to assets/javascripts.

    In my code,

    profile.rb

    class Profile < ApplicationRecord
      has_many :degrees, :as => :degreeable
      accepts_nested_attributes_for :degrees, :reject_if => :all_blank, allow_destroy: true
    
      belongs_to :user, :class_name => 'User', :foreign_key => 'user_id'
    end
    

    degree.rb

    class Degree < ApplicationRecord
       belongs_to :degreeable, polymorphic: true
    end
    

    profiles/_form.html.erb

        <div id="fields-for-list" class="numerous">
          <%= f.fields_for :degrees, Degree.new, :child_index => 'replace_this' do |degree_form| %>
             <%= degree_form.select :level, options_for_select(Job::EDUCATION, params[:level]), include_blank: "Select Degree", :class => 'span5' %>
             <%= degree_form.text_field :description, placeholder: "Add a new Degree here..."%>
             <%= link_to 'x Remove', '#', :class => 'numerous-remove', type: 'button' %>
         <% end %>
       </div>
       <div id="list"></div>
       <%= link_to (fa_icon 'plus').to_s + 'Add a Qualification', '#', :id => 'add-to-list' %>
    

    and finally, with strong parameters,

      def profile_params
        params.require(:profile).permit(:user_id, :first_name, :last_name, degrees_attributes:[:id, :level, :description])
      end
    

    Note that I had already set-up degree table with 2 extra fields for polymorphic association:- "degreeable_id" & "degreeable_type" and when entering in DB, the two fields were automatically filled with newly created profile_id and 'Profile'(the name of the model which is associating polymorphically with degree).

    The trick in numerous.js is creating each nested form record(here degree) with unique temporary id such as Time.now.to_i so now each degree record created/destroyed at client side will have a diff degree_attribute 'id'. Hope it helps others.