设置:我有一个“: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);
希望这可以帮助!