diff --git a/History.md b/History.md
index 0dcc9d9..dc52de1 100644
--- a/History.md
+++ b/History.md
@@ -1,5 +1,15 @@
# Change History / Release Notes
+## Version 1.1.2
+
+* pull #118 (thanks @ahmozkya): remove the deprecated `.live` function, and use `.on` instead.
+ Note: at least jquery 1.7 is required now!
+
+## Version 1.1.1
+
+* added the to be added/deleted element to the event, this allows to add animations/actions onto them
+* added extra option :wrap_object, allowing to use Decorators instead of the association object
+* added an option :force_non_association_create, that will allow to use `link_to_add_association` inside the fields-partial
## Version 1.1.0
diff --git a/README.markdown b/README.markdown
index 44e8365..a421c0f 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,6 +1,6 @@
# cocoon
-[![Build Status](http://travis-ci.org/nathanvda/cocoon.png)](http://travis-ci.org/nathanvda/cocoon)
+[![Build Status](https://travis-ci.org/nathanvda/cocoon.png)](https://travis-ci.org/nathanvda/cocoon)
cocoon is a Rails3 gem to allow easier handling of nested forms.
@@ -273,6 +273,7 @@ It takes four parameters:
- `render_options` : options passed through to the form-builder function (e.g. `simple_fields_for`, `semantic_fields_for` or `fields_for`).
If it contains a `:locals` option containing a hash, that is handed to the partial.
- `wrap_object` : a proc that will allow to wrap your object, especially useful if you are using decorators (e.g. draper). See example lower.
+ - `force_non_association_create`: if true, it will _not_ create the new object using the association (see lower)
Optionally you could also leave out the name and supply a block that is captured to give the name (if you want to do something more complicated).
@@ -344,6 +345,22 @@ link_to_add_association('add something', @form_obj, :comments,
:wrap_object => Proc.new { |comment| comment.name = current_user.name; comment })
```
+#### :force_non_association_create
+
+In normal cases we create a new nested object using the association relation itself. This is the cleanest way to create
+a new nested object. But this has a side-effect: for each call of `link_to_add_association` a new element is added to the association.
+
+In most cases this is not a problem, but if you want to render a `link_to_add_association` for each nested element this will result
+in an infinite loop.
+
+To resolve this, specify that `:force_non_association_create` should be `true`, as follows:
+
+```
+link_to_add_association('add something', @form_obj, :comments, :force_non_association_create => true)
+```
+
+By default `:force_non_association_create` is `false`.
+
> A cleaner option would be to call a function that performs this initialisation and returns `self` at the end.
### link_to_remove_association
diff --git a/VERSION b/VERSION
index 1cc5f65..8428158 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.0
\ No newline at end of file
+1.1.2
\ No newline at end of file
diff --git a/app/assets/javascripts/cocoon.js b/app/assets/javascripts/cocoon.js
index 8ce999b..ac826aa 100644
--- a/app/assets/javascripts/cocoon.js
+++ b/app/assets/javascripts/cocoon.js
@@ -58,7 +58,7 @@
});
- $('.remove_fields.dynamic, .remove_fields.existing').live('click', function(e) {
+ $(document).on('click', '.remove_fields.dynamic, .remove_fields.existing', function(e) {
var $this = $(this);
var node_to_delete = $this.closest(".nested-fields");
var trigger_node = node_to_delete.parent();
diff --git a/cocoon.gemspec b/cocoon.gemspec
index e582d6c..df0b20c 100644
--- a/cocoon.gemspec
+++ b/cocoon.gemspec
@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = "cocoon"
- s.version = "1.1.0"
+ s.version = "1.1.2"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Nathan Van der Auwera"]
- s.date = "2012-10-08"
+ s.date = "2013-01-21"
s.description = "Unobtrusive nested forms handling, using jQuery. Use this and discover cocoon-heaven."
s.email = "nathan@dixis.com"
s.extra_rdoc_files = [
diff --git a/lib/cocoon.rb b/lib/cocoon.rb
index 3570373..1284222 100644
--- a/lib/cocoon.rb
+++ b/lib/cocoon.rb
@@ -4,7 +4,9 @@ module Cocoon
class Engine < ::Rails::Engine
config.before_initialize do
- config.action_view.javascript_expansions[:cocoon] = %w(cocoon)
+ if config.action_view.javascript_expansions
+ config.action_view.javascript_expansions[:cocoon] = %w(cocoon)
+ end
end
# configure our plugin on boot
diff --git a/lib/cocoon/view_helpers.rb b/lib/cocoon/view_helpers.rb
index 3309aad..7aa1ee4 100644
--- a/lib/cocoon/view_helpers.rb
+++ b/lib/cocoon/view_helpers.rb
@@ -51,6 +51,8 @@ module Cocoon
# - *:render_options* : options passed to `simple_fields_for, semantic_fields_for or fields_for`
# - *:locals* : the locals hash in the :render_options is handed to the partial
# - *:partial* : explicitly override the default partial name
+ # - *:wrap_object : !!! document more here !!!
+ # - *!!!add some option to build in collection or not!!!*
# - *&block*: see link_to
def link_to_add_association(*args, &block)
@@ -69,16 +71,14 @@ module Cocoon
render_options ||= {}
override_partial = html_options.delete(:partial)
wrap_object = html_options.delete(:wrap_object)
+ force_non_association_create = html_options.delete(:force_non_association_create) || false
html_options[:class] = [html_options[:class], "add_fields"].compact.join(' ')
html_options[:'data-association'] = association.to_s.singularize
html_options[:'data-associations'] = association.to_s.pluralize
- if wrap_object.respond_to?(:call)
- new_object = wrap_object.call(create_object(f, association))
- else
- new_object = create_object(f, association)
- end
+ new_object = create_object(f, association, force_non_association_create)
+ new_object = wrap_object.call(new_object) if wrap_object.respond_to?(:call)
html_options[:'data-association-insertion-template'] = CGI.escapeHTML(render_association(association, f, new_object, render_options, override_partial)).html_safe
@@ -90,10 +90,10 @@ module Cocoon
# `` has_many :admin_comments, class_name: "Comment", conditions: { author: "Admin" }
# will create new Comment with author "Admin"
- def create_object(f, association)
+ def create_object(f, association, force_non_association_create=false)
assoc = f.object.class.reflect_on_association(association)
- assoc ? create_object_on_association(f, association, assoc) : create_object_on_non_association(f, association)
+ assoc ? create_object_on_association(f, association, assoc, force_non_association_create) : create_object_on_non_association(f, association)
end
def get_partial_path(partial, association)
@@ -116,13 +116,12 @@ module Cocoon
raise "Association #{association} doesn't exist on #{f.object.class}"
end
- def create_object_on_association(f, association, instance)
- if instance.class.name == "Mongoid::Relations::Metadata"
- conditions = instance.respond_to?(:conditions) ? instance.conditions.flatten : []
- instance.klass.new(*conditions)
+ def create_object_on_association(f, association, instance, force_non_association_create)
+ if instance.class.name == "Mongoid::Relations::Metadata" || force_non_association_create
+ create_object_with_conditions(instance)
else
# assume ActiveRecord or compatible
- if instance.collection?
+ if instance.collection?
f.object.send(association).build
else
f.object.send("build_#{association}")
@@ -130,5 +129,10 @@ module Cocoon
end
end
+ def create_object_with_conditions(instance)
+ conditions = instance.respond_to?(:conditions) ? instance.conditions.flatten : []
+ instance.klass.new(*conditions)
+ end
+
end
end
diff --git a/spec/cocoon_spec.rb b/spec/cocoon_spec.rb
index ec46dca..161a4f6 100644
--- a/spec/cocoon_spec.rb
+++ b/spec/cocoon_spec.rb
@@ -10,11 +10,15 @@ describe Cocoon do
it { should respond_to(:link_to_add_association) }
it { should respond_to(:link_to_remove_association) }
+ before(:each) do
+ @tester = TestClass.new
+ @post = Post.new
+ @form_obj = stub(:object => @post, :object_name => @post.class.name)
+ end
+
+
context "link_to_add_association" do
before(:each) do
- @tester = TestClass.new
- @post = Post.new
- @form_obj = stub(:object => @post)
@tester.stub(:render_association).and_return('form')
end
@@ -41,6 +45,25 @@ describe Cocoon do
@tester.should_receive(:render_association).with(anything(), anything(), kind_of(CommentDecorator), anything(), anything()).and_return('partiallll')
@tester.link_to_add_association('add something', @form_obj, :comments, :wrap_object => Proc.new {|comment| CommentDecorator.new(comment) })
end
+
+ context "force non association create" do
+ it "default it uses the association" do
+ @tester.should_receive(:create_object).with(anything, :comments , false)
+ result = @tester.link_to_add_association('add something', @form_obj, :comments)
+ result.to_s.should == 'add something'
+ end
+ it "specifying false is the same as default: create object on association" do
+ @tester.should_receive(:create_object).with(anything, :comments , false)
+ result = @tester.link_to_add_association('add something', @form_obj, :comments, :force_non_association_create => false)
+ result.to_s.should == 'add something'
+ end
+ it "specifying true will not create objects on association but using the conditions" do
+ @tester.should_receive(:create_object).with(anything, :comments , true)
+ result = @tester.link_to_add_association('add something', @form_obj, :comments, :force_non_association_create => true)
+ result.to_s.should == 'add something'
+ end
+
+ end
end
context "with a block" do
@@ -146,12 +169,6 @@ describe Cocoon do
end
context "link_to_remove_association" do
- before(:each) do
- @tester = TestClass.new
- @post = Post.new
- @form_obj = stub(:object => @post, :object_name => @post.class.name)
- end
-
context "without a block" do
it "accepts a name" do
result = @tester.link_to_remove_association('remove something', @form_obj)
@@ -180,44 +197,50 @@ describe Cocoon do
result.to_s.should == "remove some long name"
end
end
+ end
- context "create_object" do
- it "should create correct association with conditions" do
- result = @tester.create_object(@form_obj, :admin_comments)
- result.author.should == "Admin"
- end
-
- it "should create correct association for belongs_to associations" do
- result = @tester.create_object(stub(:object => Comment.new), :post)
- result.should be_a Post
- end
-
- it "should raise error if cannot reflect on association" do
- expect { @tester.create_object(stub(:object => Comment.new), :not_existing) }.to raise_error /association/i
- end
-
- it "should create an association if object responds to 'build_association' as singular" do
- object = Comment.new
- object.should_receive(:build_custom_item).and_return 'custom'
- @tester.create_object(stub(:object => object), :custom_item).should == 'custom'
- end
-
- it "should create an association if object responds to 'build_association' as plural" do
- object = Comment.new
- object.should_receive(:build_custom_item).and_return 'custom'
- @tester.create_object(stub(:object => object), :custom_items).should == 'custom'
- end
+ context "create_object" do
+ it "creates correct association with conditions" do
+ @tester.should_not_receive(:create_object_with_conditions)
+ result = @tester.create_object(@form_obj, :admin_comments)
+ result.author.should == "Admin"
end
- context "get_partial_path" do
- it "generates the default partial name if no partial given" do
- result = @tester.get_partial_path(nil, :admin_comments)
- result.should == "admin_comment_fields"
- end
- it "uses the given partial name" do
- result = @tester.get_partial_path("comment_fields", :admin_comments)
- result.should == "comment_fields"
- end
+ it "creates correct association for belongs_to associations" do
+ result = @tester.create_object(stub(:object => Comment.new), :post)
+ result.should be_a Post
+ end
+
+ it "raises an error if cannot reflect on association" do
+ expect { @tester.create_object(stub(:object => Comment.new), :not_existing) }.to raise_error /association/i
+ end
+
+ it "creates an association if object responds to 'build_association' as singular" do
+ object = Comment.new
+ object.should_receive(:build_custom_item).and_return 'custom'
+ @tester.create_object(stub(:object => object), :custom_item).should == 'custom'
+ end
+
+ it "creates an association if object responds to 'build_association' as plural" do
+ object = Comment.new
+ object.should_receive(:build_custom_item).and_return 'custom'
+ @tester.create_object(stub(:object => object), :custom_items).should == 'custom'
+ end
+
+ it "can create using only conditions not the association" do
+ @tester.should_receive(:create_object_with_conditions).and_return('flappie')
+ @tester.create_object(@form_obj, :comments, true).should == 'flappie'
+ end
+ end
+
+ context "get_partial_path" do
+ it "generates the default partial name if no partial given" do
+ result = @tester.get_partial_path(nil, :admin_comments)
+ result.should == "admin_comment_fields"
+ end
+ it "uses the given partial name" do
+ result = @tester.get_partial_path("comment_fields", :admin_comments)
+ result.should == "comment_fields"
end
end