设置:我有一个“:household”类:accepts_nested_attributes_for“:members(people)”.我正在运行开发服务器.我将nested_form.js移动到/ app / assets / javascripts目录.我几乎肯定它只被采购一次.
问题:如果在家庭控制器“新”方法中,我这样做:
@household = Household.new
我只看到视图中的家庭原生字段(预期),并且“link_to_remove”和“link_to_add”链接呈现/删除成员字段部分(预期).但是,如果我这样做:
@household = Household.new @household.members.build
我在视图中看到了家庭原生字段(预期),成员本地字段的一个呈现部分(预期),但“link_to_remove”和“link_to_add”什么都不做(意外).我不能添加另一个:成员部分在那一点,也不删除已经显示的:成员部分.
我很难过.以下是看似相关的精简源文件.我从git存储库获取了nested_form插件(最后捆绑了2012.04.18)…
/app/models/household.rb
class Household < ActiveRecord::Base has_many :members,:class_name => "Person" accepts_nested_attributes_for :members attr_accessible :id,:name,:member_ids attr_accessible :members_attributes end #class
/app/models/person.rb
class Person < ActiveRecord::Base belongs_to :household attr_accessible :id,:name_given,:name_middle,:name_family,:household_id end #class
/app/controllers/households_controller.rb
<snip> # GET /households/new # GET /households/new.json def new @household = Household.new @household.members.build # <---- Removing this changes the behavior respond_to do |format| format.html # new.html.erb format.json { render json: @household } end end
/app/views/households/new.html.haml
.headbg .pad %h2 Enter a New Household = render 'form'
/app/views/households/_form.html.haml
= nested_form_for @household,:html => { :class => "form-horizontal"} do |f| %fieldset %legend Household .control-group = f.label( :name,{ :class => 'control-label'} ) .controls = f.text_field( :name,{ :class => 'span5',:placeholder => '[household name]'} ) %fieldset %legend Household Members = f.fields_for :members,:html => { :class => "form-inline"} do |nested_f| = render :partial => 'people/nested_person_form',:locals => { :f => nested_f } = yield :nested_person_form %p = f.link_to_add "New Household Member",:members .form-actions = button_tag( :class => "btn btn-primary",:disable_with => "Saving..." ) do %i.icon-ok.icon-white Save = link_to households_path do .btn.btn-info %i.icon-arrow-left.icon-white Back to Households
/app/views/people/_nested_person_form.html.haml
- content_for :nested_person_form do .nested-fields .row .span8 .control-group = f.label( "Name",{ :class => 'control-label'} ) .controls = f.text_field( :name_given,{ :class => 'span2',:placeholder => '[first]'} ) = f.text_field( :name_middle,:placeholder => '[middle]'} ) = f.text_field( :name_family,:placeholder => '[last]'} ) .span1 = f.link_to_remove "Remove"
/app/assets/javascripts/nested_form/nested_form.js
jQuery(function($) { window.NestedFormEvents = function() { this.addFields = $.proxy(this.addFields,this); this.removeFields = $.proxy(this.removeFields,this); }; NestedFormEvents.prototype = { addFields: function(e) { // Setup var link = e.currentTarget; var assoc = $(link).attr('data-association'); // Name of child var content = $('#' + assoc + '_fields_blueprint').html(); // Fields template // Make the context correct by replacing new_<parents> with the generated ID // of each of the parent objects var context = ($(link).closest('.fields').find('input:first').attr('name') || '').replace(new RegExp('\[[a-z]+\]$'),''); // context will be something like this for a brand new form: // project[tasks_attributes][new_1255929127459][assignments_attributes][new_1255929128105] // or for an edit form: // project[tasks_attributes][0][assignments_attributes][1] if (context) { var parentNames = context.match(/[a-z_]+_attributes/g) || []; var parentIds = context.match(/(new_)?[0-9]+/g) || []; for(var i = 0; i < parentNames.length; i++) { if(parentIds[i]) { content = content.replace( new RegExp('(_' + parentNames[i] + ')_.+?_','g'),'$1_' + parentIds[i] + '_'); content = content.replace( new RegExp('(\\[' + parentNames[i] + '\\])\\[.+?\\]','$1[' + parentIds[i] + ']'); } } } // Make a unique ID for the new child var regexp = new RegExp('new_' + assoc,'g'); var new_id = new Date().getTime(); content = content.replace(regexp,"new_" + new_id); var field = this.insertFields(content,assoc,link); $(link).closest("form") .trigger({ type: 'nested:fieldAdded',field: field }) .trigger({ type: 'nested:fieldAdded:' + assoc,field: field }); return false; },insertFields: function(content,link) { return $(content).insertBefore(link); },removeFields: function(e) { var link = e.currentTarget; var hiddenField = $(link).prev('input[type=hidden]'); hiddenField.val('1'); // if (hiddenField) { // $(link).v // hiddenField.value = '1'; // } var field = $(link).closest('.fields'); field.hide(); $(link).closest("form").trigger({ type: 'nested:fieldRemoved',field: field }); return false; } }; window.nestedFormEvents = new NestedFormEvents(); $('form a.add_nested_fields').live('click',nestedFormEvents.addFields); $('form a.remove_nested_fields').live('click',nestedFormEvents.removeFields); });
解决方法
确保你头脑中有一个最新的jQuery.js文件.加载后,请不要使用从gem安装的nested_form.js文件.而是使用jquery_nested_form.js.
只要在jquery_nested_form文件之前有jquery链接,这个解决方案就可以正常工作:
<%= javascript_include_tag :defaults,'jquery_nested_form' %>
以下是jquery_nested_form.js文件的代码:
jQuery(function($) { window.NestedFormEvents = function() { this.addFields = $.proxy(this.addFields,this); }; NestedFormEvents.prototype = { addFields: function(e) { // Setup var link = e.currentTarget; var assoc = $(link).attr('data-association'); // Name of child var content = $('#' + assoc + '_fields_blueprint').html(); // Fields template // Make the context correct by replacing new_<parents> with the generated ID // of each of the parent objects var context = ($(link).closest('.fields').closestChild('input,textarea').eq(0).attr('name') || '').replace(new RegExp('\[[a-z]+\]$'),link); // bubble up event upto document (through form) field .trigger({ type: 'nested:fieldAdded',removeFields: function(e) { var $link = $(e.currentTarget),assoc = $link.data('association'); // Name of child to be removed var hiddenField = $link.prev('input[type=hidden]'); hiddenField.val('1'); var field = $link.closest('.fields'); field.hide(); field .trigger({ type: 'nested:fieldRemoved',field: field }) .trigger({ type: 'nested:fieldRemoved:' + assoc,nestedFormEvents.removeFields); }); // http://plugins.jquery.com/project/closestChild /* * Copyright 2011,Tobias Lindig * * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.PHP) * and GPL (http://www.opensource.org/licenses/gpl-license.PHP) licenses. * */ (function($) { $.fn.closestChild = function(selector) { // breadth first search for the first matched node if (selector && selector != '') { var queue = []; queue.push(this); while(queue.length > 0) { var node = queue.shift(); var children = node.children(); for(var i = 0; i < children.length; ++i) { var child = $(children[i]); if (child.is(selector)) { return child; //well,we found one } queue.push(child); } } } return $();//nothing found }; })(jQuery);
希望这可以帮助!