问题
I want the following on my form:
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.
回答1:
I've got this little helper to get me through these cases. Its reusable so you don't ever have to write all this stuff for different cases in the same app.
First the code:
module FormsHelper
def data_for_field(f, subclass, options={})
new_object = f.object.class.new.send(subclass.to_s).new(options[:attributes])
id = new_object.object_id
partial_path = options[:path] || new_object
fields = f.fields_for(subclass, new_object, child_index: id) do |builder|
render(partial_path, f: builder)
end
{id: id, fields: fields.gsub("\n", "")}
end
end
Some JS magic:
$(document).on('click', '.add-fields', function(e){
var time = new Date().getTime();
var regexp = new RegExp($(this).data('id'), 'g');
var content = $(this).data('fields').replace(regexp, time);
$(target).append(content);
e.preventDefault();
});
Now a view call:
<%= form_tag .... do |f|
<div id="list"></div>
<%= link_to 'Add an Organisation', '#', class: 'add-fields', data: data_for_field(f, :degrees, path: "/degrees/fields").merge(target: "#list") %></p>
<% end %>
Now create a partial where the degree fields to use.
/degrees/_fields.html.erb
<%= content_tag :div do %>
<%= f.input :name %>
<% end %>
Now the explanation:
For data_for_field you pass: f (form), :degrees (the plural name of the associated model as a symbol), and any additional options like the path to the partial for the fields. It basically creates a scaffold of the form fields and sets them as a data attribute on the "Add Qualification" link. I've merged in a data-target which has the css ID of where to insert the new fields into the page as well.
When you click the JS event fires and replaces the id in the form fields with a timestamp so for each qualification you'll have a unique key.
I also usually have a little extra JS event for removing the fields as well.
Hope this helps.
回答2:
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.
来源:https://stackoverflow.com/questions/42503139/rails-nested-polymorphic-form-with-javascripting