awesome_nested_fields 0.0.3 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ demos/*/**
data/Gemfile.lock ADDED
@@ -0,0 +1,78 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ awesome_nested_fields (0.0.3)
5
+ rails (>= 3.0.0)
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ abstract (1.0.0)
11
+ actionmailer (3.0.4)
12
+ actionpack (= 3.0.4)
13
+ mail (~> 2.2.15)
14
+ actionpack (3.0.4)
15
+ activemodel (= 3.0.4)
16
+ activesupport (= 3.0.4)
17
+ builder (~> 2.1.2)
18
+ erubis (~> 2.6.6)
19
+ i18n (~> 0.4)
20
+ rack (~> 1.2.1)
21
+ rack-mount (~> 0.6.13)
22
+ rack-test (~> 0.5.7)
23
+ tzinfo (~> 0.3.23)
24
+ activemodel (3.0.4)
25
+ activesupport (= 3.0.4)
26
+ builder (~> 2.1.2)
27
+ i18n (~> 0.4)
28
+ activerecord (3.0.4)
29
+ activemodel (= 3.0.4)
30
+ activesupport (= 3.0.4)
31
+ arel (~> 2.0.2)
32
+ tzinfo (~> 0.3.23)
33
+ activeresource (3.0.4)
34
+ activemodel (= 3.0.4)
35
+ activesupport (= 3.0.4)
36
+ activesupport (3.0.4)
37
+ arel (2.0.8)
38
+ builder (2.1.2)
39
+ erubis (2.6.6)
40
+ abstract (>= 1.0.0)
41
+ i18n (0.5.0)
42
+ mail (2.2.15)
43
+ activesupport (>= 2.3.6)
44
+ i18n (>= 0.4.0)
45
+ mime-types (~> 1.16)
46
+ treetop (~> 1.4.8)
47
+ mime-types (1.16)
48
+ polyglot (0.3.1)
49
+ rack (1.2.1)
50
+ rack-mount (0.6.13)
51
+ rack (>= 1.0.0)
52
+ rack-test (0.5.7)
53
+ rack (>= 1.0)
54
+ rails (3.0.4)
55
+ actionmailer (= 3.0.4)
56
+ actionpack (= 3.0.4)
57
+ activerecord (= 3.0.4)
58
+ activeresource (= 3.0.4)
59
+ activesupport (= 3.0.4)
60
+ bundler (~> 1.0)
61
+ railties (= 3.0.4)
62
+ railties (3.0.4)
63
+ actionpack (= 3.0.4)
64
+ activesupport (= 3.0.4)
65
+ rake (>= 0.8.7)
66
+ thor (~> 0.14.4)
67
+ rake (0.8.7)
68
+ thor (0.14.6)
69
+ treetop (1.4.9)
70
+ polyglot (>= 0.3.1)
71
+ tzinfo (0.3.24)
72
+
73
+ PLATFORMS
74
+ ruby
75
+
76
+ DEPENDENCIES
77
+ awesome_nested_fields!
78
+ bundler (>= 1.0.0)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Lailson Bandeira
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ Awesome Nested Fields
2
+ =====================
3
+
4
+ In Rails, you can create forms that have fields from nested models. For example, if a person has many phone numbers, you can easily create a form that receives data from the person and from a fixed number of phones. However, when you want to allow the person to insert multiple, indefinite phones, you're in trouble: it's [much harder](http://railscasts.com/episodes/196-nested-model-form-part-1) [than it](http://railscasts.com/episodes/197-nested-model-form-part-2) [should be](http://stackoverflow.com/questions/1704142/unobtrusive-dynamic-form-fields-in-rails-with-jquery). Well, not anymore.
5
+
6
+
7
+ Installation
8
+ ------------
9
+
10
+ 1. Add the gem to your Gemfile.
11
+
12
+ gem 'awesome_nested_fields'
13
+
14
+ 2. Run bundler to make sure the gem gets installed.
15
+
16
+ bundle install
17
+
18
+ 3. Include the `jquery.nested-fields.js` file in your template (or in the pages that will use nested fields).
19
+
20
+ <script src="/javascripts/jquery.nested-fields.js" type="text/javascript"></script>
21
+
22
+ Now you're ready to rock with nested models. Don't forget to include the javascript file _after_ you've included jQuery. And don't worry because this file isn't on the public folder: it comes bundled into the gem.
23
+
24
+
25
+ Basic Usage
26
+ -----------
27
+
28
+ ### Model
29
+
30
+ First, make sure the object that has the `has_many` or `has_and_belongs_to_many` relation accepts nested attributes for the collection you want. For example, if a person _has_many_ phones, we'll have a model like this:
31
+
32
+ class Person < ActiveRecord::Base
33
+ has_many :phones
34
+ accepts_nested_attributes_for :phones, allow_destroy: true
35
+ end
36
+
37
+ The `accepts_nested_attributes_for` is a method from Active Record that allows you to pass attributes of nested models directly to its parent, instead of instantiate each child object separately. In this case, `Person` gains a method called `phones_attributes=`, that accepts data for new and existing phones of a given person. The `allow_destroy` option enables us to also delete child objects. To know more about nested attributes, check out the [ActiveRecord::NestedAttribute](https://github.com/rails/rails/blob/master/activerecord/lib/active_record/nested_attributes.rb#L1) class.
38
+
39
+ ### View
40
+
41
+ The next step is set up the form view using the `nested_fields` helper method. It receives three parameters: the parent form builder, the association name and an optional hash of options (humm, a pun).
42
+ Proceeding with the person/phones example, we can have a form like this:
43
+
44
+ <%= form_for(@person) do |f| %>
45
+ <% # person fields... %>
46
+
47
+ <h2>Phones</h2>
48
+ <div class="container">
49
+ <%= nested_fields(f, :phones) %>
50
+ </div>
51
+ <a href="#" class="add">add phone</a>
52
+
53
+ <% # more person fields... %>
54
+ <% end %>
55
+
56
+ The `nested_fields` helper lists the phones this person has and also adds an empty template to the page for creating new phones. But where is the phone form? Well, awesome_nested_fields expects a partial with the association name in the singular (after all, the partial represents a single child object). In this case, it looks for the partial `phone` (we can change this name later). So, in the file `_phone.html.erb`, we can have:
57
+
58
+ <fieldset class="item">
59
+ <%= f.label :where %>
60
+ <%= f.text_field :where %><br/>
61
+
62
+ <%= f.label :number %>
63
+ <%= f.text_field :number %>
64
+
65
+ <a href="#" class="remove">remove</a>
66
+
67
+ <%= f.hidden_field :id %>
68
+ <%= f.hidden_field :_destroy %>
69
+ </fieldset>
70
+
71
+ If you're paying attention, you noticed the key elements are marked with a special class name. We need this for the javascript code, so it knows what to do with each HTML element: the one that have the children must have the class `container`; each child must be marked with the class `item`; inside an item, the link for removal must have the class `remove`; and the link to add new items must have the class `add`. We can change the names later, but these are the default choices. Finally, don't forget to add the `id` field, as it is needed by AR to identify if this is an existing or a new element, and the `_destroy` field to activate deletion when the user clicks on the remove link.
72
+
73
+ ### Javascript
74
+
75
+ This is the easiest part: just activate the nested fields actions when the page loads. We can put this in the `application.js` file (or in any other place that gets executed in the page):
76
+
77
+ $(document).ready(function(e) {
78
+ $('FORM').nestedFields();
79
+ });
80
+
81
+ Now enjoy your new nested model form!
82
+
83
+
84
+ Compatibility
85
+ -------------
86
+
87
+ awesome_nested_fields works only with Rails 3 and was tested with jQuery 1.5.0.
88
+
89
+
90
+ TODO
91
+ ----
92
+
93
+ * Write tests
94
+ * Write awesome demos
95
+ * Make sure it can degrade gracefully
96
+ * Return and API object on JS to make interaction easier
97
+ * Port JavaScript code to CoffeeScript
98
+
99
+
100
+ Copyleft
101
+ --------
102
+ Copyleft (c) 2011 Lailson Bandeira (http://lailsonbandeira.com/). See LICENSE for details.
@@ -1,4 +1,10 @@
1
1
  module AwesomeNestedFieldsHelper
2
+
3
+ def nested_fields(builder, association, options={})
4
+ nested_fields_items(builder, association, options) <<
5
+ nested_fields_template(builder, association, options)
6
+ end
7
+
2
8
  def nested_fields_items(builder, association, options={})
3
9
  options = nested_fields_process_default_options(options, builder, association)
4
10
 
@@ -8,7 +14,7 @@ module AwesomeNestedFieldsHelper
8
14
  end
9
15
 
10
16
  if options[:none_partial] and builder.object.send(association).empty?
11
- items << render(options[:none_partial], options[:builder_local] => f)
17
+ items << render(options[:none_partial])
12
18
  end
13
19
 
14
20
  items.html_safe
@@ -18,14 +24,14 @@ module AwesomeNestedFieldsHelper
18
24
  options = nested_fields_process_default_options(options, builder, association)
19
25
 
20
26
  templates = content_tag(:script, type: 'text/html', class: options[:item_template_class]) do
21
- builder.fields_for(association, options[:new_object], child_index: 'new_nested_item') do |f|
27
+ builder.fields_for(association, options[:new_object], child_index: options[:new_item_index]) do |f|
22
28
  render(options[:partial], options[:builder_local] => f)
23
29
  end
24
30
  end
25
31
 
26
32
  if options[:none_partial]
27
33
  templates << content_tag(:script, type: 'text/html', class: options[:none_template_class]) do
28
- builder.fields_for(association, options[:new_object], child_index: 'new_nested_item') do |f|
34
+ builder.fields_for(association, options[:new_object], child_index: options[:new_item_index]) do |f|
29
35
  render(options[:none_partial], options[:builder_local] => f)
30
36
  end
31
37
  end
@@ -38,9 +44,10 @@ protected
38
44
  def nested_fields_process_default_options(options, builder, association)
39
45
  options[:new_object] ||= builder.object.class.reflect_on_association(association).klass.new
40
46
  options[:partial] ||= association.to_s.singularize
41
- options[:builder_local] ||= :builder
47
+ options[:builder_local] ||= :f
42
48
  options[:item_template_class] ||= 'template item'
43
49
  options[:none_template_class] ||= 'template none'
50
+ options[:new_item_index] ||= 'new_nested_item'
44
51
  options
45
52
  end
46
53
  end
@@ -1,3 +1,3 @@
1
1
  module AwesomeNestedFields
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -10,8 +10,8 @@
10
10
  container: '.container',
11
11
  item: '.item',
12
12
  none: '.none',
13
- addHandler: '.add',
14
- removeHandler: '.remove',
13
+ add: '.add',
14
+ remove: '.remove',
15
15
  newItemIndex: 'new_nested_item'
16
16
  };
17
17
 
@@ -31,10 +31,10 @@
31
31
  options.itemTemplate = $(options.itemTemplate, $this);
32
32
  options.noneTemplate = $(options.noneTemplate, $this);
33
33
  options.container = $(options.container, $this);
34
- options.addHandler = $(options.addHandler, $this);
34
+ options.add = $(options.add, $this);
35
35
  $this.data('nested-fields.options', options);
36
36
 
37
- options.addHandler.bind('click.nested-fields', function(e) {
37
+ options.add.bind('click.nested-fields', function(e) {
38
38
  e.preventDefault();
39
39
  var newItem = prepareTemplate(options);
40
40
  insertItemWithCallbacks(newItem, null, options);
@@ -165,17 +165,20 @@
165
165
  }
166
166
 
167
167
  function bindRemoveEvent(item, options) {
168
- var removeHandler = $(item).find(options.removeHandler);
168
+ var removeHandler = $(item).find(options.remove);
169
169
  var needsConfirmation = removeHandler.attr('data-confirm');
170
170
 
171
- var event = needsConfirmation ? 'confirmed' : 'click';
172
- removeHandler.bind(event + '.nested-fields', function(e) {
173
- removeItem(item, options);
171
+ var event = needsConfirmation ? 'confirm:complete' : 'click';
172
+ removeHandler.bind(event + '.nested-fields', function(e, confirmed) {
173
+ e.preventDefault();
174
+ if(confirmed === undefined || confirmed === true) {
175
+ removeItem(item, options);
176
+ }
174
177
  });
175
178
  }
176
179
 
177
180
  function insertNone(options) {
178
- if(findItems(options).length == 0) {
181
+ if(findItems(options).length === 0) {
179
182
  options.container.append(options.noneTemplate.html());
180
183
  }
181
184
  }
metadata CHANGED
@@ -1,13 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: awesome_nested_fields
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 0
9
- - 3
10
- version: 0.0.3
4
+ prerelease:
5
+ version: 0.1.0
11
6
  platform: ruby
12
7
  authors:
13
8
  - Lailson Bandeira
@@ -15,7 +10,7 @@ autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
12
 
18
- date: 2011-02-12 00:00:00 -03:00
13
+ date: 2011-06-06 00:00:00 -03:00
19
14
  default_executable:
20
15
  dependencies:
21
16
  - !ruby/object:Gem::Dependency
@@ -26,11 +21,6 @@ dependencies:
26
21
  requirements:
27
22
  - - ">="
28
23
  - !ruby/object:Gem::Version
29
- hash: 23
30
- segments:
31
- - 1
32
- - 0
33
- - 0
34
24
  version: 1.0.0
35
25
  type: :development
36
26
  version_requirements: *id001
@@ -42,11 +32,6 @@ dependencies:
42
32
  requirements:
43
33
  - - ">="
44
34
  - !ruby/object:Gem::Version
45
- hash: 7
46
- segments:
47
- - 3
48
- - 0
49
- - 0
50
35
  version: 3.0.0
51
36
  type: :runtime
52
37
  version_requirements: *id002
@@ -61,6 +46,9 @@ extra_rdoc_files: []
61
46
  files:
62
47
  - .gitignore
63
48
  - Gemfile
49
+ - Gemfile.lock
50
+ - LICENSE
51
+ - README.md
64
52
  - Rakefile
65
53
  - app/helpers/awesome_nested_fields_helper.rb
66
54
  - awesome_nested_fields.gemspec
@@ -81,25 +69,17 @@ required_ruby_version: !ruby/object:Gem::Requirement
81
69
  requirements:
82
70
  - - ">="
83
71
  - !ruby/object:Gem::Version
84
- hash: 3
85
- segments:
86
- - 0
87
72
  version: "0"
88
73
  required_rubygems_version: !ruby/object:Gem::Requirement
89
74
  none: false
90
75
  requirements:
91
76
  - - ">="
92
77
  - !ruby/object:Gem::Version
93
- hash: 23
94
- segments:
95
- - 1
96
- - 3
97
- - 6
98
78
  version: 1.3.6
99
79
  requirements: []
100
80
 
101
81
  rubyforge_project: awesome_nested_fields
102
- rubygems_version: 1.3.7
82
+ rubygems_version: 1.6.2
103
83
  signing_key:
104
84
  specification_version: 3
105
85
  summary: Awesome nested fields for Rails