Skip to content
This repository has been archived by the owner on Dec 12, 2021. It is now read-only.

3 Level nested form bug #276

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
1 change: 0 additions & 1 deletion .rvmrc

This file was deleted.

1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ gemspec :path => '.'
instance_eval File.read(File.expand_path('../gemfiles/Gemfile.base', __FILE__))

gem 'rails', '~> 3.2.0'
gem 'test-unit'
21 changes: 14 additions & 7 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
require 'rubygems'
require 'rake'

module TempFixForRakeLastComment
def last_comment
last_description
end
end
Rake::Application.send :include, TempFixForRakeLastComment

begin
require 'rspec/core/rake_task'
desc "Run RSpec"
Expand All @@ -24,11 +31,11 @@ namespace :spec do
desc 'Install gems from additional gemfiles'
task :install do
system 'bundle install'
ENV.delete('GEM_HOME')
ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_1', __FILE__)
system 'bundle install'
ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_0', __FILE__)
system 'bundle install'
# ENV.delete('GEM_HOME')
# ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_1', __FILE__)
# system 'bundle install'
# ENV['BUNDLE_GEMFILE'] = File.expand_path('../gemfiles/Gemfile.rails3_0', __FILE__)
# system 'bundle install'
end

desc 'Run tests with Rails 3.1.x'
Expand All @@ -47,7 +54,7 @@ namespace :spec do

task :all do
Rake::Task["spec"].execute
Rake::Task["spec:rails3_1"].execute
Rake::Task["spec:rails3_0"].execute
# Rake::Task["spec:rails3_1"].execute
# Rake::Task["spec:rails3_0"].execute
end
end
5 changes: 0 additions & 5 deletions gemfiles/Gemfile.rails3_0

This file was deleted.

2 changes: 1 addition & 1 deletion gemfiles/Gemfile.rails3_1 → gemfiles/Gemfile.rails3_2
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
gemspec :path => '../'
instance_eval File.read(File.expand_path('../Gemfile.base', __FILE__))
gem "rails", "~> 3.1.0"
gem "rails", "~> 3.2.0"
Binary file added spec/.DS_Store
Binary file not shown.
Binary file added spec/dummy/.DS_Store
Binary file not shown.
Binary file added spec/dummy/app/.DS_Store
Binary file not shown.
Binary file added spec/dummy/app/assets/.DS_Store
Binary file not shown.
Empty file modified spec/dummy/app/assets/javascripts/application.js
100644 → 100755
Empty file.
Empty file modified spec/dummy/app/assets/javascripts/jquery.js
100644 → 100755
Empty file.
Empty file modified spec/dummy/app/assets/javascripts/jquery_events_test.js
100644 → 100755
Empty file.
Empty file modified spec/dummy/app/assets/javascripts/projects.js
100644 → 100755
Empty file.
Empty file modified spec/dummy/app/assets/javascripts/prototype.js
100644 → 100755
Empty file.
Empty file modified spec/dummy/app/assets/javascripts/prototype_events_test.js
100644 → 100755
Empty file.
17 changes: 17 additions & 0 deletions spec/dummy/app/views/projects/with_target_links.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<%= nested_form_for Project.new do |f| -%>
<%= f.text_field :name %>
<div id="task-fields">
<%= f.fields_for :tasks do |tf| -%>
<%= tf.text_field :name %>
<div id="milestone-fields">
<%= tf.fields_for :milestones do |mf| %>
<%= mf.text_field :name %>
<%= mf.link_to_remove 'Remove milestone' %>
<% end %>
</div>
<%= tf.link_to_add 'Add new milestone', :milestones, data: {target: '#milestone-fields'} %>
<%= tf.link_to_remove 'Remove' %>
<% end -%>
</div>
<%= f.link_to_add 'Add new task', :tasks, data: {target: '#task-fields'} %>
<% end -%>
11 changes: 11 additions & 0 deletions spec/form_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ def check_form
inputs.first[:name].should_not eq(inputs.last[:name])
end

it 'works when specify target', :js => true do
visit '/projects/with_target_links'
click_link 'Add new task'
click_link 'Remove'
click_link 'Add new task'
click_link 'Add new milestone'

# page.should have_selector('#milestone-fields .fields', :visible => true)
find(:css, "#milestone-fields .fields").should be_visible
end

it 'generates correct name for the nested input', :js => true do
visit '/projects/new?type=jquery'
click_link 'Add new task'
Expand Down
74 changes: 43 additions & 31 deletions vendor/assets/javascripts/jquery_nested_form.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,37 +16,15 @@
// of each of the parent objects
var context = ($(link).closest('.fields').closestChild('input, textarea, select').eq(0).attr('name') || '').replace(/\[[a-z_]+\]$/, '');

// If the parent has no inputs we need to strip off the last pair
var current = content.match(new RegExp('\\[([a-z_]+)\\]\\[new_' + assoc + '\\]'))[1];
if (current) {
context = context.replace(new RegExp('\\['+current+'\\]\\[(new_)?\\d+\\]$'), '');
}

// context will be something like this for a brand new form:
// project[tasks_attributes][1255929127459][assignments_attributes][1255929128105]
// or for an edit form:
// project[tasks_attributes][0][assignments_attributes][1]
if (context) {
var parentNames = context.match(/[a-z_]+_attributes(?=\]\[(new_)?\d+\])/g) || [];
var parentIds = context.match(/[0-9]+/g) || [];
if (context){
var parentNames = context.match(/[a-z_]+_attributes(?=\]\[(new_)?.+\])/g) || [];
var parentIds = context.match(/[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] + '\\])\\[.+?\\]', 'g'),
'$1[' + parentIds[i] + ']');
}
}
content = this.replaceContentFromParents(content, assoc, parentNames, parentIds)
}
else{
content = this.replaceContentFromParents(content, assoc)
}

// Make a unique ID for the new child
var regexp = new RegExp('new_' + assoc, 'g');
var new_id = this.newId();
content = $.trim(content.replace(regexp, new_id));

var field = this.insertFields(content, assoc, link);
// bubble up event upto document (through form)
Expand All @@ -60,8 +38,12 @@
},
insertFields: function(content, assoc, link) {
var target = $(link).data('target');
if (target) {
return $(content).appendTo($(target));
if (target) {
if($(link).closest('.fields').length > 0) {
return $(content).appendTo($(link).closest('.fields').find($(link).data('target')));
} else {
return $(content).appendTo($(target));
}
} else {
return $(content).insertBefore(link);
}
Expand All @@ -80,6 +62,36 @@
.trigger({ type: 'nested:fieldRemoved', field: field })
.trigger({ type: 'nested:fieldRemoved:' + assoc, field: field });
return false;
},
replaceContentFromParents: function(content, assoc, parentNames, parentIds){
parentNames = parentNames || [];
parentIds = parentIds || [];

if (parentNames.length > 0 && parentNames.length == parentIds.length){
// we need to get a name pattern and id pattern that is mapped to parent
var fullNameRegexp = ""; // regexp used to find the full name pattern in blueprint
var fullIdRegexp = ""; // regexp used to find the full id pattern in blueprint
var fullNameReplace = ""; // name part from parents, eg. [parameters_attributes][0][children_attributes][1]
var fullIdReplace = ""; // id part from parents, eg. _parameters_attributes_0_children_attributes_1
for (var i=0; i< parentNames.length; i++){
fullNameRegexp += "\\[" + parentNames[i] + "\\]\\[.+?\\]";
fullNameReplace += "[" + parentNames[i] + "][" + parentIds[i] + "]";
fullIdRegexp += "_" + parentNames[i] + "_.+?";
fullIdReplace += "_" + parentNames[i] + "_" + parentIds[i];

if (i== parentNames.length -1){
fullIdRegexp += "(?=_" + assoc + "_attributes)"
}
}
content = content.replace(new RegExp(fullNameRegexp, 'g'), fullNameReplace);
content = content.replace(new RegExp(fullIdRegexp, 'g'), fullIdReplace);
}

// Make a unique ID for the new child
var regexp = new RegExp('new_' + assoc, 'g');
var new_id = this.newId();
content = $.trim(content.replace(regexp, new_id));
return content;
}
};

Expand Down