cocoon 1.0.22 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.md CHANGED
@@ -1,6 +1,27 @@
1
1
  # Change History / Release Notes
2
2
 
3
3
 
4
+ ## Version 1.1.0
5
+
6
+ * BREAKING: the triggered javascript events `removal-callback`, `after-removal-callback`, and `insertion-callback` are renamed to the more correct and symmetric
7
+ `cocoon:after-insert, cocoon:before-insert, cocoon:after-remove, cocoon:before-remove`. Also the events are namespaced to prevent collisions with other libraries.
8
+ * allow created objects to be decorated with a callable. This is especially useful if you are using Draper or some decorator instead of the plain model in your views.
9
+ * it is now possible to specify a relative node, and use standard jquery traversal methods on insertion
10
+ * trigger insertion event on correct `insertionNode`
11
+ * thanks to #90 cocoon now supports non-AR associations and array-fields, you just have to supply your own `build_<association>` methods
12
+
13
+ I would really really like to thank all contributors, check them out https://github.com/nathanvda/cocoon/graphs/contributors
14
+ They made cocoon way more awesome than I could have done in my lonesome.
15
+
16
+ ## Version 1.0.22
17
+
18
+ * Fix that it still works for mongoid
19
+
20
+ ## Version 1.0.21
21
+
22
+ * Use association build methods instead of assoc.klass.new. This avoids mass-assignment errors and other misbehaviors around attribute accessibility.
23
+
24
+
4
25
  ## Version 1.0.20
5
26
 
6
27
  * improved handing of the `:partial`: remove the extra options-hash, and just make it use the single hash, so now we can just write
data/README.markdown CHANGED
@@ -9,6 +9,8 @@ For example a project with its tasks, an invoice with its ordered items.
9
9
 
10
10
  It is formbuilder-agnostic, so it works with standard Rails, or Formtastic or simple_form.
11
11
 
12
+ This project is not related to [Apache Cocoon](http://cocoon.apache.org/)
13
+
12
14
  ## Prerequisites
13
15
 
14
16
  This gem uses jQuery, it is most useful to use this gem in a rails3
@@ -26,7 +28,7 @@ Inside your `Gemfile` add the following:
26
28
  gem "cocoon"
27
29
  ````
28
30
 
29
- ### Rails 3.1
31
+ ### Rails 3.1+
30
32
 
31
33
  Add the following to `application.js` so it compiles to the
32
34
  asset_pipeline
@@ -35,7 +37,7 @@ asset_pipeline
35
37
  //= require cocoon
36
38
  ````
37
39
 
38
- ### Rails 3.x
40
+ ### Rails 3.0.x
39
41
 
40
42
  If you are using Rails 3.0.x, you need to run the installation task (since rails 3.1 this is no longer needed):
41
43
 
@@ -96,7 +98,7 @@ We will show the sample usage with the different possible form-builders.
96
98
  Inside our `projects/_form` partial we then write:
97
99
 
98
100
  ````haml
99
- - f.inputs do
101
+ = f.inputs do
100
102
  = f.input :name
101
103
  = f.input :description
102
104
  %h3 Tasks
@@ -105,7 +107,7 @@ Inside our `projects/_form` partial we then write:
105
107
  = render 'task_fields', :f => task
106
108
  .links
107
109
  = link_to_add_association 'add task', f, :tasks
108
- -f.actions do
110
+ = f.actions do
109
111
  = f.action :submit
110
112
  ````
111
113
 
@@ -125,14 +127,70 @@ There is an example project on github implementing it called [cocoon_formtastic_
125
127
 
126
128
  ### Using simple_form
127
129
 
128
- This is almost identical to formtastic, instead of writing `semantic_fields_for` you write `simple_fields_for`.
130
+ Inside our `projects/_form` partial we then write:
129
131
 
130
- There is an example project on github implementing it called [cocoon_simple_form_demo](https://github.com/nathanvda/cocoon_simple_form_demo).
132
+ ````haml
133
+ = simple_form_for @project do |f|
134
+ = f.input :name
135
+ = f.input :description
136
+ %h3 Tasks
137
+ #tasks
138
+ = f.simple_fields_for :tasks do |task|
139
+ = render 'task_fields', :f => task
140
+ .links
141
+ = link_to_add_association 'add task', f, :tasks
142
+ = f.submit
143
+ ````
144
+
145
+ and inside the `_task_fields` partial we write:
131
146
 
147
+ ````haml
148
+ .nested-fields
149
+ = f.input :description
150
+ = f.input :done, :as => :boolean
151
+ = link_to_remove_association "remove task", f
152
+ ````
153
+
154
+ There is an example project on github implementing it called [cocoon_simple_form_demo](https://github.com/nathanvda/cocoon_simple_form_demo).
132
155
 
133
156
  ### Using standard rails forms
134
157
 
135
- I will provide a full example (and a sample project) later.
158
+ Inside our `projects/_form` partial we then write:
159
+
160
+ ````haml
161
+ - form_for @project do |f|
162
+ .field
163
+ = f.label :name
164
+ %br
165
+ = f.text_field :name
166
+ .field
167
+ = f.label :description
168
+ %br
169
+ = f.text_field :description
170
+ %h3 Tasks
171
+ #tasks
172
+ = f.fields_for :tasks do |task|
173
+ = render 'task_fields', :f => task
174
+ .links
175
+ = link_to_add_association 'add task', f, :tasks
176
+ = f.submit
177
+ ````
178
+
179
+ and inside the `_task_fields` partial we write:
180
+
181
+ ````haml
182
+ .nested-fields
183
+ .field
184
+ = f.label :description
185
+ %br
186
+ = f.text_field :description
187
+ .field
188
+ = f.check_box :done
189
+ = f.label :done
190
+ = link_to_remove_association "remove task", f
191
+ ````
192
+
193
+ I will provide a sample project later.
136
194
 
137
195
  ## How it works
138
196
 
@@ -150,6 +208,7 @@ It takes four parameters:
150
208
  - association: the name of the association (plural) of which a new instance needs to be added (symbol or string).
151
209
  - html_options: extra html-options (see `link_to`)
152
210
  There are some special options, the first three allow to control the placement of the new link-data:
211
+ - `data-association-insertion-traversal` : the jquery traversal method to allow node selection relative to the link. `closest`, `next`, `children`, etc. Default: absolute selection
153
212
  - `data-association-insertion-node` : the jquery selector of the node
154
213
  - `data-association-insertion-method` : jquery method that inserts the new data. `before`, `after`, `append`, `prepend`, etc. Default: `before`
155
214
  - `data-association-insertion-position` : old method specifying where to insert new data.
@@ -165,6 +224,8 @@ Inside the `html_options` you can add an option `:render_options`, and the conta
165
224
  form. E.g. especially when using `twitter-bootstrap` and `simple_form` together, the `simple_fields_for` needs the option `:wrapper => 'inline'` which can
166
225
  be handed down as follows:
167
226
 
227
+ (Note: In certain newer versions of simple_form, the option to use is ':wrapper => 'bootstrap')
228
+
168
229
  ````haml
169
230
  = link_to_add_association 'add something', f, :something, :render_options => {:wrapper => 'inline' }
170
231
  ````
@@ -201,7 +262,14 @@ Optionally you could also leave out the name and supply a block that is captured
201
262
 
202
263
  ### Callbacks (upon insert and remove of items)
203
264
 
204
- There is an option to add a callback on insertion or removal. If in your view you have the following snippet to select an `owner`
265
+ On insertion or removal the following events are triggered:
266
+
267
+ * `cocoon:before-insert`: called before inserting a new nested child
268
+ * `cocoon:after-insert`: called after inserting
269
+ * `cocoon:before-remove`: called before removing the nested child
270
+ * `cocoon:after-remove`: called after removal
271
+
272
+ If in your view you have the following snippet to select an `owner`
205
273
  (we use slim for demonstration purposes)
206
274
 
207
275
  ````haml
@@ -218,17 +286,21 @@ The callbacks can be added as follows:
218
286
 
219
287
  ````javascript
220
288
  $(document).ready(function() {
221
- $('#owner').bind('insertion-callback',
289
+ $('#owner').bind('cocoon:before-insert',
222
290
  function() {
223
291
  $("#owner_from_list").hide();
224
292
  $("#owner a.add_fields").hide();
225
293
  });
226
- $('#owner').bind("removal-callback",
294
+ $('#owner').bind('cocoon:after-insert',
295
+ function() {
296
+ /* ... do something ... */
297
+ });
298
+ $('#owner').bind("cocoon:before-remove",
227
299
  function() {
228
300
  $("#owner_from_list").show();
229
301
  $("#owner a.add_fields").show();
230
302
  });
231
- $('#owner').bind("after-removal-callback",
303
+ $('#owner').bind("cocoon:after-remove",
232
304
  function() {
233
305
  /* e.g. recalculate order of child items */
234
306
  });
@@ -236,7 +308,7 @@ $(document).ready(function() {
236
308
  ````
237
309
 
238
310
  Do note that for the callbacks to work there has to be a surrounding container (div), where you can bind the callbacks to.
239
- Note that the default `removal-callback` is called _before_ removing the nested item.
311
+
240
312
 
241
313
  ### Control the Insertion behaviour
242
314
 
@@ -256,6 +328,18 @@ The `association-insertion-node` will determine where to add it. You can choose
256
328
 
257
329
  The `association-insertion-method` will determine where to add it in relation with the node. Any jQuery DOM Manipulation method can be set but we recommend sticking to any of the following: `before`, `after`, `append`, `prepend`. It is unknown at this time what others would do.
258
330
 
331
+ The `association-insertion-traversal` will allow node selection to be relative to the link.
332
+
333
+ For example:
334
+
335
+ ````javascript
336
+ $(document).ready(function() {
337
+ $("#owner a.add_fields").
338
+ data("association-insertion-method", 'append').
339
+ data("association-insertion-traversal", 'closest').
340
+ data("association-insertion-node", '#parent_table');
341
+ });
342
+ ````
259
343
 
260
344
  ### Partial
261
345
 
@@ -280,6 +364,12 @@ There is no limit to the amount of nesting, though.
280
364
  * Send me a pull request. Bonus points for topic branches.
281
365
 
282
366
 
367
+ ## Contributors
368
+
369
+ The list of contributors just keeps on growing. [Check it out](https://github.com/nathanvda/cocoon/graphs/contributors) !!
370
+ I would really really like to thank all of them,
371
+ they make cocoon more awesome every day. Thanks.
372
+
283
373
  ## Todo
284
374
 
285
375
  * add more sample relations: `has_many :through`, `belongs_to`, ...
@@ -288,3 +378,9 @@ There is no limit to the amount of nesting, though.
288
378
  ## Copyright
289
379
 
290
380
  Copyright (c) 2010 Nathan Van der Auwera. See LICENSE for details.
381
+
382
+ ## Not Related To Apache Cocoon
383
+
384
+ Please note that this project is not related to the Apache Cocoon web framework project.
385
+
386
+ [Apache Cocoon](http://cocoon.apache.org/), Cocoon, and Apache are either registered trademarks or trademarks of the [Apache Software Foundation](http://www.apache.org/) in the United States and/or other countries.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.22
1
+ 1.1.0
@@ -5,12 +5,12 @@
5
5
  content.replace(reg_exp, with_str);
6
6
  }
7
7
 
8
- function trigger_removal_callback(node) {
9
- node.trigger('removal-callback');
8
+ function trigger_before_removal_callback(node) {
9
+ node.trigger('cocoon:before-remove');
10
10
  }
11
11
 
12
12
  function trigger_after_removal_callback(node) {
13
- node.trigger('after-removal-callback');
13
+ node.trigger('cocoon:after-remove');
14
14
  }
15
15
 
16
16
  $('.add_fields').live('click', function(e) {
@@ -18,9 +18,10 @@
18
18
  var $this = $(this),
19
19
  assoc = $this.data('association'),
20
20
  assocs = $this.data('associations'),
21
- content = $this.data('template'),
21
+ content = $this.data('association-insertion-template'),
22
22
  insertionMethod = $this.data('association-insertion-method') || $this.data('association-insertion-position') || 'before';
23
23
  insertionNode = $this.data('association-insertion-node'),
24
+ insertionTraversal = $this.data('association-insertion-traversal'),
24
25
  regexp_braced = new RegExp('\\[new_' + assoc + '\\]', 'g'),
25
26
  regexp_underscord = new RegExp('_new_' + assoc + '_', 'g'),
26
27
  new_id = new Date().getTime(),
@@ -37,25 +38,31 @@
37
38
  new_content = new_content.replace(regexp_underscord, newcontent_underscord);
38
39
 
39
40
  if (insertionNode){
40
- insertionNode = insertionNode == "this" ? $this : $(insertionNode);
41
+ if (insertionTraversal){
42
+ insertionNode = $this[insertionTraversal](insertionNode)
43
+ } else {
44
+ insertionNode = insertionNode == "this" ? $this : $(insertionNode);
45
+ }
41
46
  } else {
42
47
  insertionNode = $this.parent();
43
48
  }
44
49
 
45
50
  var contentNode = $(new_content);
46
51
 
52
+ insertionNode.trigger('cocoon:before-insert');
53
+
47
54
  // allow any of the jquery dom manipulation methods (after, before, append, prepend, etc)
48
55
  // to be called on the node. allows the insertion node to be the parent of the inserted
49
56
  // code and doesn't force it to be a sibling like after/before does. default: 'before'
50
57
  insertionNode[insertionMethod](contentNode);
51
58
 
52
- $this.parent().trigger('insertion-callback');
59
+ insertionNode.trigger('cocoon:after-insert');
53
60
  });
54
61
 
55
62
  $('.remove_fields.dynamic').live('click', function(e) {
56
63
  var $this = $(this);
57
64
  var trigger_node = $this.closest(".nested-fields").parent();
58
- trigger_removal_callback(trigger_node);
65
+ trigger_before_removal_callback(trigger_node);
59
66
  e.preventDefault();
60
67
  $this.closest(".nested-fields").remove();
61
68
  trigger_after_removal_callback(trigger_node);
@@ -64,11 +71,11 @@
64
71
  $('.remove_fields.existing').live('click', function(e) {
65
72
  var $this = $(this);
66
73
  var trigger_node = $this.closest(".nested-fields").parent().parent();
67
- trigger_removal_callback(trigger_node);
74
+ trigger_before_removal_callback(trigger_node);
68
75
  e.preventDefault();
69
76
  $this.prev("input[type=hidden]").val("1");
70
77
  $this.closest(".nested-fields").hide();
71
78
  trigger_after_removal_callback(trigger_node);
72
79
  });
73
80
 
74
- })(jQuery);
81
+ })(jQuery);
data/cocoon.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "cocoon"
8
- s.version = "1.0.22"
8
+ s.version = "1.1.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Nathan Van der Auwera"]
12
- s.date = "2012-05-20"
12
+ s.date = "2012-10-08"
13
13
  s.description = "Unobtrusive nested forms handling, using jQuery. Use this and discover cocoon-heaven."
14
14
  s.email = "nathan@dixis.com"
15
15
  s.extra_rdoc_files = [
@@ -31,6 +31,7 @@ Gem::Specification.new do |s|
31
31
  "spec/cocoon_spec.rb",
32
32
  "spec/dummy/Rakefile",
33
33
  "spec/dummy/app/controllers/application_controller.rb",
34
+ "spec/dummy/app/decorators/comment_decorator.rb",
34
35
  "spec/dummy/app/helpers/application_helper.rb",
35
36
  "spec/dummy/app/models/comment.rb",
36
37
  "spec/dummy/app/models/person.rb",
@@ -73,7 +74,7 @@ Gem::Specification.new do |s|
73
74
  ]
74
75
  s.homepage = "http://github.com/nathanvda/cocoon"
75
76
  s.require_paths = ["lib"]
76
- s.rubygems_version = "1.8.15"
77
+ s.rubygems_version = "1.8.24"
77
78
  s.summary = "gem that enables easier nested forms with standard forms, formtastic and simple-form"
78
79
 
79
80
  if s.respond_to? :specification_version then
@@ -67,13 +67,19 @@ module Cocoon
67
67
  render_options = html_options.delete(:render_options)
68
68
  render_options ||= {}
69
69
  override_partial = html_options.delete(:partial)
70
+ wrap_object = html_options.delete(:wrap_object)
70
71
 
71
72
  html_options[:class] = [html_options[:class], "add_fields"].compact.join(' ')
72
73
  html_options[:'data-association'] = association.to_s.singularize
73
74
  html_options[:'data-associations'] = association.to_s.pluralize
74
75
 
75
- new_object = create_object(f, association)
76
- html_options[:'data-template'] = CGI.escapeHTML(render_association(association, f, new_object, render_options, override_partial)).html_safe
76
+ if wrap_object.respond_to?(:call)
77
+ new_object = wrap_object.call(create_object(f, association))
78
+ else
79
+ new_object = create_object(f, association)
80
+ end
81
+
82
+ html_options[:'data-association-insertion-template'] = CGI.escapeHTML(render_association(association, f, new_object, render_options, override_partial)).html_safe
77
83
 
78
84
  link_to(name, '#', html_options )
79
85
  end
@@ -86,12 +92,28 @@ module Cocoon
86
92
  def create_object(f, association)
87
93
  assoc = f.object.class.reflect_on_association(association)
88
94
 
89
- if assoc.class.name == "Mongoid::Relations::Metadata"
90
- conditions = assoc.respond_to?(:conditions) ? assoc.conditions.flatten : []
91
- assoc.klass.new(*conditions)
95
+ assoc ? create_object_on_association(f, association, assoc) : create_object_on_non_association(f, association)
96
+ end
97
+
98
+ def get_partial_path(partial, association)
99
+ partial ? partial : association.to_s.singularize + "_fields"
100
+ end
101
+
102
+ private
103
+
104
+ def create_object_on_non_association(f, association)
105
+ builder_method = %W{build_#{association} build_#{association.to_s.singularize}}.select { |m| f.object.respond_to?(m) }.first
106
+ return f.object.send(builder_method) if builder_method
107
+ raise "Association #{association} doesn't exist on #{f.object.class}"
108
+ end
109
+
110
+ def create_object_on_association(f, association, instance)
111
+ if instance.class.name == "Mongoid::Relations::Metadata"
112
+ conditions = instance.respond_to?(:conditions) ? instance.conditions.flatten : []
113
+ instance.klass.new(*conditions)
92
114
  else
93
115
  # assume ActiveRecord or compatible
94
- if assoc.collection?
116
+ if instance.collection?
95
117
  f.object.send(association).build
96
118
  else
97
119
  f.object.send("build_#{association}")
@@ -99,9 +121,5 @@ module Cocoon
99
121
  end
100
122
  end
101
123
 
102
- def get_partial_path(partial, association)
103
- partial ? partial : association.to_s.singularize + "_fields"
104
- end
105
-
106
124
  end
107
125
  end
data/spec/cocoon_spec.rb CHANGED
@@ -21,19 +21,25 @@ describe Cocoon do
21
21
  context "without a block" do
22
22
  it "accepts a name" do
23
23
  result = @tester.link_to_add_association('add something', @form_obj, :comments)
24
- result.to_s.should == '<a href="#" class="add_fields" data-association="comment" data-associations="comments" data-template="form&lt;tag&gt;">add something</a>'
24
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="form&lt;tag&gt;" data-association="comment" data-associations="comments">add something</a>'
25
25
  end
26
26
 
27
27
  it "accepts html options and pass them to link_to" do
28
28
  result = @tester.link_to_add_association('add something', @form_obj, :comments, {:class => 'something silly'})
29
- result.to_s.should == '<a href="#" class="something silly add_fields" data-association="comment" data-associations="comments" data-template="form&lt;tag&gt;">add something</a>'
29
+ result.to_s.should == '<a href="#" class="something silly add_fields" data-association-insertion-template="form&lt;tag&gt;" data-association="comment" data-associations="comments">add something</a>'
30
30
  end
31
31
 
32
32
  it "allows to explicitly hand the wanted partial" do
33
33
  @tester.unstub(:render_association)
34
34
  @tester.should_receive(:render_association).with(anything(), anything(), anything(), anything(), "shared/partial").and_return('partiallll')
35
35
  result = @tester.link_to_add_association('add something', @form_obj, :comments, :partial => "shared/partial")
36
- result.to_s.should == '<a href="#" class="add_fields" data-association="comment" data-associations="comments" data-template="partiallll">add something</a>'
36
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="partiallll" data-association="comment" data-associations="comments">add something</a>'
37
+ end
38
+
39
+ it "gives an opportunity to wrap/decorate created objects" do
40
+ @tester.unstub(:render_association)
41
+ @tester.should_receive(:render_association).with(anything(), anything(), kind_of(CommentDecorator), anything(), anything()).and_return('partiallll')
42
+ @tester.link_to_add_association('add something', @form_obj, :comments, :wrap_object => Proc.new {|comment| CommentDecorator.new(comment) })
37
43
  end
38
44
  end
39
45
 
@@ -42,14 +48,14 @@ describe Cocoon do
42
48
  result = @tester.link_to_add_association(@form_obj, :comments) do
43
49
  "some long name"
44
50
  end
45
- result.to_s.should == '<a href="#" class="add_fields" data-association="comment" data-associations="comments" data-template="form&lt;tag&gt;">some long name</a>'
51
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="form&lt;tag&gt;" data-association="comment" data-associations="comments">some long name</a>'
46
52
  end
47
53
 
48
54
  it "accepts html options and pass them to link_to" do
49
55
  result = @tester.link_to_add_association(@form_obj, :comments, {:class => 'floppy disk'}) do
50
56
  "some long name"
51
57
  end
52
- result.to_s.should == '<a href="#" class="floppy disk add_fields" data-association="comment" data-associations="comments" data-template="form&lt;tag&gt;">some long name</a>'
58
+ result.to_s.should == '<a href="#" class="floppy disk add_fields" data-association-insertion-template="form&lt;tag&gt;" data-association="comment" data-associations="comments">some long name</a>'
53
59
  end
54
60
 
55
61
  it "allows to explicitly hand the wanted partial" do
@@ -58,21 +64,21 @@ describe Cocoon do
58
64
  result = @tester.link_to_add_association( @form_obj, :comments, :class => 'floppy disk', :partial => "shared/partial") do
59
65
  "some long name"
60
66
  end
61
- result.to_s.should == '<a href="#" class="floppy disk add_fields" data-association="comment" data-associations="comments" data-template="partiallll">some long name</a>'
67
+ result.to_s.should == '<a href="#" class="floppy disk add_fields" data-association-insertion-template="partiallll" data-association="comment" data-associations="comments">some long name</a>'
62
68
  end
63
69
  end
64
70
 
65
71
  context "with an irregular plural" do
66
72
  it "uses the correct plural" do
67
73
  result = @tester.link_to_add_association('add something', @form_obj, :people)
68
- result.to_s.should == '<a href="#" class="add_fields" data-association="person" data-associations="people" data-template="form&lt;tag&gt;">add something</a>'
74
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="form&lt;tag&gt;" data-association="person" data-associations="people">add something</a>'
69
75
  end
70
76
  end
71
77
 
72
78
  context "when using aliased association and class-name" do
73
79
  it "uses the correct name" do
74
80
  result = @tester.link_to_add_association('add something', @form_obj, :admin_comments)
75
- result.to_s.should == '<a href="#" class="add_fields" data-association="admin_comment" data-associations="admin_comments" data-template="form&lt;tag&gt;">add something</a>'
81
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="form&lt;tag&gt;" data-association="admin_comment" data-associations="admin_comments">add something</a>'
76
82
  end
77
83
  end
78
84
 
@@ -84,7 +90,7 @@ describe Cocoon do
84
90
  it "uses the correct plural" do
85
91
  @tester.should_receive(:render_association).with(:people, @form_obj, anything, {:wrapper => 'inline'}, nil)
86
92
  result = @tester.link_to_add_association('add something', @form_obj, :people, :render_options => {:wrapper => 'inline'})
87
- result.to_s.should == '<a href="#" class="add_fields" data-association="person" data-associations="people" data-template="form&lt;tag&gt;">add something</a>'
93
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="form&lt;tag&gt;" data-association="person" data-associations="people">add something</a>'
88
94
  end
89
95
  end
90
96
 
@@ -94,14 +100,14 @@ describe Cocoon do
94
100
  @form_obj.should_receive(:fields_for) { | association, new_object, options_hash, &block| block.call }
95
101
  @tester.should_receive(:render).with("person_fields", {:f=>nil, :dynamic=>true, :alfred=>"Judoka"}).and_return ("partiallll")
96
102
  result = @tester.link_to_add_association('add something', @form_obj, :people, :render_options => {:wrapper => 'inline', :locals => {:alfred => 'Judoka'}})
97
- result.to_s.should == '<a href="#" class="add_fields" data-association="person" data-associations="people" data-template="partiallll">add something</a>'
103
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="partiallll" data-association="person" data-associations="people">add something</a>'
98
104
  end
99
105
  it "if no locals are given it still works" do
100
106
  @tester.unstub(:render_association)
101
107
  @form_obj.should_receive(:fields_for) { | association, new_object, options_hash, &block| block.call }
102
108
  @tester.should_receive(:render).with("person_fields", {:f=>nil, :dynamic=>true}).and_return ("partiallll")
103
109
  result = @tester.link_to_add_association('add something', @form_obj, :people, :render_options => {:wrapper => 'inline'})
104
- result.to_s.should == '<a href="#" class="add_fields" data-association="person" data-associations="people" data-template="partiallll">add something</a>'
110
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="partiallll" data-association="person" data-associations="people">add something</a>'
105
111
  end
106
112
  end
107
113
 
@@ -116,7 +122,7 @@ describe Cocoon do
116
122
  @form_obj.should_receive(:semantic_fields_for)
117
123
  @form_obj.should_receive(:fields_for).never
118
124
  result = @tester.link_to_add_association('add something', @form_obj, :people)
119
- result.to_s.should == '<a href="#" class="add_fields" data-association="person" data-associations="people" data-template="form&lt;tagzzz&gt;">add something</a>'
125
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="form&lt;tagzzz&gt;" data-association="person" data-associations="people">add something</a>'
120
126
 
121
127
  end
122
128
  end
@@ -132,7 +138,7 @@ describe Cocoon do
132
138
  @form_obj.should_receive(:simple_fields_for)
133
139
  @form_obj.should_receive(:fields_for).never
134
140
  result = @tester.link_to_add_association('add something', @form_obj, :people)
135
- result.to_s.should == '<a href="#" class="add_fields" data-association="person" data-associations="people" data-template="form&lt;tagxxx&gt;">add something</a>'
141
+ result.to_s.should == '<a href="#" class="add_fields" data-association-insertion-template="form&lt;tagxxx&gt;" data-association="person" data-associations="people">add something</a>'
136
142
 
137
143
  end
138
144
  end
@@ -185,6 +191,22 @@ describe Cocoon do
185
191
  result = @tester.create_object(stub(:object => Comment.new), :post)
186
192
  result.should be_a Post
187
193
  end
194
+
195
+ it "should raise error if cannot reflect on association" do
196
+ expect { @tester.create_object(stub(:object => Comment.new), :not_existing) }.to raise_error /association/i
197
+ end
198
+
199
+ it "should create an association if object responds to 'build_association' as singular" do
200
+ object = Comment.new
201
+ object.should_receive(:build_custom_item).and_return 'custom'
202
+ @tester.create_object(stub(:object => object), :custom_item).should == 'custom'
203
+ end
204
+
205
+ it "should create an association if object responds to 'build_association' as plural" do
206
+ object = Comment.new
207
+ object.should_receive(:build_custom_item).and_return 'custom'
208
+ @tester.create_object(stub(:object => object), :custom_items).should == 'custom'
209
+ end
188
210
  end
189
211
 
190
212
  context "get_partial_path" do
@@ -0,0 +1,17 @@
1
+ class CommentDecorator
2
+ def initialize(comment)
3
+ @comment = comment
4
+ end
5
+
6
+ def formatted_created_at
7
+ @comment.created_at.to_formatted_s(:short)
8
+ end
9
+
10
+ def method_missing(method_sym, *args)
11
+ if @comment.respond_to?(method_sym)
12
+ @comment.send(method_sym, *args)
13
+ else
14
+ super
15
+ end
16
+ end
17
+ end
metadata CHANGED
@@ -1,181 +1,184 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: cocoon
3
- version: !ruby/object:Gem::Version
4
- hash: 59
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
5
  prerelease:
6
- segments:
7
- - 1
8
- - 0
9
- - 22
10
- version: 1.0.22
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Nathan Van der Auwera
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2012-05-20 00:00:00 Z
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
21
- requirement: &id001 !ruby/object:Gem::Requirement
12
+ date: 2012-10-08 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rails
16
+ requirement: !ruby/object:Gem::Requirement
22
17
  none: false
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- hash: 7
27
- segments:
28
- - 3
29
- - 0
30
- - 0
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
31
21
  version: 3.0.0
32
- version_requirements: *id001
33
- name: rails
34
- prerelease: false
35
22
  type: :development
36
- - !ruby/object:Gem::Dependency
37
- requirement: &id002 !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
38
25
  none: false
39
- requirements:
40
- - - ">="
41
- - !ruby/object:Gem::Version
42
- hash: 3
43
- segments:
44
- - 0
45
- version: "0"
46
- version_requirements: *id002
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 3.0.0
30
+ - !ruby/object:Gem::Dependency
47
31
  name: sqlite3-ruby
48
- prerelease: false
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
49
38
  type: :development
50
- - !ruby/object:Gem::Dependency
51
- requirement: &id003 !ruby/object:Gem::Requirement
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
52
41
  none: false
53
- requirements:
54
- - - ">="
55
- - !ruby/object:Gem::Version
56
- hash: 3
57
- segments:
58
- - 0
59
- version: "0"
60
- version_requirements: *id003
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
61
47
  name: json_pure
62
- prerelease: false
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
63
54
  type: :development
64
- - !ruby/object:Gem::Dependency
65
- requirement: &id004 !ruby/object:Gem::Requirement
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
66
57
  none: false
67
- requirements:
68
- - - ">="
69
- - !ruby/object:Gem::Version
70
- hash: 3
71
- segments:
72
- - 0
73
- version: "0"
74
- version_requirements: *id004
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
75
63
  name: jeweler
76
- prerelease: false
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
77
70
  type: :development
78
- - !ruby/object:Gem::Dependency
79
- requirement: &id005 !ruby/object:Gem::Requirement
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
80
73
  none: false
81
- requirements:
82
- - - ">="
83
- - !ruby/object:Gem::Version
84
- hash: 23
85
- segments:
86
- - 2
87
- - 6
88
- - 0
89
- version: 2.6.0
90
- version_requirements: *id005
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ - !ruby/object:Gem::Dependency
91
79
  name: rspec-rails
92
- prerelease: false
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: 2.6.0
93
86
  type: :development
94
- - !ruby/object:Gem::Dependency
95
- requirement: &id006 !ruby/object:Gem::Requirement
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
96
89
  none: false
97
- requirements:
98
- - - ">="
99
- - !ruby/object:Gem::Version
100
- hash: 23
101
- segments:
102
- - 2
103
- - 6
104
- - 0
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
105
93
  version: 2.6.0
106
- version_requirements: *id006
94
+ - !ruby/object:Gem::Dependency
107
95
  name: rspec
108
- prerelease: false
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: 2.6.0
109
102
  type: :development
110
- - !ruby/object:Gem::Dependency
111
- requirement: &id007 !ruby/object:Gem::Requirement
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
112
105
  none: false
113
- requirements:
114
- - - ">="
115
- - !ruby/object:Gem::Version
116
- hash: 7
117
- segments:
118
- - 3
119
- - 0
120
- - 0
121
- version: 3.0.0
122
- version_requirements: *id007
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: 2.6.0
110
+ - !ruby/object:Gem::Dependency
123
111
  name: actionpack
124
- prerelease: false
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: 3.0.0
125
118
  type: :development
126
- - !ruby/object:Gem::Dependency
127
- requirement: &id008 !ruby/object:Gem::Requirement
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
128
121
  none: false
129
- requirements:
130
- - - ">="
131
- - !ruby/object:Gem::Version
132
- hash: 3
133
- segments:
134
- - 0
135
- version: "0"
136
- version_requirements: *id008
122
+ requirements:
123
+ - - ! '>='
124
+ - !ruby/object:Gem::Version
125
+ version: 3.0.0
126
+ - !ruby/object:Gem::Dependency
137
127
  name: simplecov
138
- prerelease: false
128
+ requirement: !ruby/object:Gem::Requirement
129
+ none: false
130
+ requirements:
131
+ - - ! '>='
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
139
134
  type: :development
140
- - !ruby/object:Gem::Dependency
141
- requirement: &id009 !ruby/object:Gem::Requirement
135
+ prerelease: false
136
+ version_requirements: !ruby/object:Gem::Requirement
142
137
  none: false
143
- requirements:
144
- - - ">="
145
- - !ruby/object:Gem::Version
146
- hash: 3
147
- segments:
148
- - 0
149
- version: "0"
150
- version_requirements: *id009
138
+ requirements:
139
+ - - ! '>='
140
+ - !ruby/object:Gem::Version
141
+ version: '0'
142
+ - !ruby/object:Gem::Dependency
151
143
  name: generator_spec
152
- prerelease: false
144
+ requirement: !ruby/object:Gem::Requirement
145
+ none: false
146
+ requirements:
147
+ - - ! '>='
148
+ - !ruby/object:Gem::Version
149
+ version: '0'
153
150
  type: :development
154
- - !ruby/object:Gem::Dependency
155
- requirement: &id010 !ruby/object:Gem::Requirement
151
+ prerelease: false
152
+ version_requirements: !ruby/object:Gem::Requirement
156
153
  none: false
157
- requirements:
158
- - - ">="
159
- - !ruby/object:Gem::Version
160
- hash: 15
161
- segments:
162
- - 2
163
- - 0
164
- - 0
165
- version: 2.0.0
166
- version_requirements: *id010
154
+ requirements:
155
+ - - ! '>='
156
+ - !ruby/object:Gem::Version
157
+ version: '0'
158
+ - !ruby/object:Gem::Dependency
167
159
  name: rspec
168
- prerelease: false
160
+ requirement: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: 2.0.0
169
166
  type: :development
170
- description: Unobtrusive nested forms handling, using jQuery. Use this and discover cocoon-heaven.
167
+ prerelease: false
168
+ version_requirements: !ruby/object:Gem::Requirement
169
+ none: false
170
+ requirements:
171
+ - - ! '>='
172
+ - !ruby/object:Gem::Version
173
+ version: 2.0.0
174
+ description: Unobtrusive nested forms handling, using jQuery. Use this and discover
175
+ cocoon-heaven.
171
176
  email: nathan@dixis.com
172
177
  executables: []
173
-
174
178
  extensions: []
175
-
176
- extra_rdoc_files:
179
+ extra_rdoc_files:
177
180
  - README.markdown
178
- files:
181
+ files:
179
182
  - .travis.yml
180
183
  - Gemfile
181
184
  - History.md
@@ -191,6 +194,7 @@ files:
191
194
  - spec/cocoon_spec.rb
192
195
  - spec/dummy/Rakefile
193
196
  - spec/dummy/app/controllers/application_controller.rb
197
+ - spec/dummy/app/decorators/comment_decorator.rb
194
198
  - spec/dummy/app/helpers/application_helper.rb
195
199
  - spec/dummy/app/models/comment.rb
196
200
  - spec/dummy/app/models/person.rb
@@ -232,36 +236,30 @@ files:
232
236
  - spec/spec_helper.rb
233
237
  homepage: http://github.com/nathanvda/cocoon
234
238
  licenses: []
235
-
236
239
  post_install_message:
237
240
  rdoc_options: []
238
-
239
- require_paths:
241
+ require_paths:
240
242
  - lib
241
- required_ruby_version: !ruby/object:Gem::Requirement
243
+ required_ruby_version: !ruby/object:Gem::Requirement
242
244
  none: false
243
- requirements:
244
- - - ">="
245
- - !ruby/object:Gem::Version
246
- hash: 3
247
- segments:
245
+ requirements:
246
+ - - ! '>='
247
+ - !ruby/object:Gem::Version
248
+ version: '0'
249
+ segments:
248
250
  - 0
249
- version: "0"
250
- required_rubygems_version: !ruby/object:Gem::Requirement
251
+ hash: -4012454906623253900
252
+ required_rubygems_version: !ruby/object:Gem::Requirement
251
253
  none: false
252
- requirements:
253
- - - ">="
254
- - !ruby/object:Gem::Version
255
- hash: 3
256
- segments:
257
- - 0
258
- version: "0"
254
+ requirements:
255
+ - - ! '>='
256
+ - !ruby/object:Gem::Version
257
+ version: '0'
259
258
  requirements: []
260
-
261
259
  rubyforge_project:
262
- rubygems_version: 1.8.15
260
+ rubygems_version: 1.8.24
263
261
  signing_key:
264
262
  specification_version: 3
265
- summary: gem that enables easier nested forms with standard forms, formtastic and simple-form
263
+ summary: gem that enables easier nested forms with standard forms, formtastic and
264
+ simple-form
266
265
  test_files: []
267
-