loyal_awesome_nested_set 0.0.1

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/CHANGELOG ADDED
@@ -0,0 +1,57 @@
1
+ 2.1.6
2
+ * Fixed rebuild! when there is a default_scope with order [Adrian Serafin]
3
+ * Testing with stable bundler, ruby 2.0, MySQL and PostgreSQL [Philip Arndt]
4
+ * Optimized move_to for large trees [ericsmith66]
5
+
6
+ 2.1.5
7
+ * Worked around issues where AR#association wasn't present on Rails 3.0.x. [Philip Arndt]
8
+ * Adds option 'order_column' which defaults to 'left_column_name'. [gudata]
9
+ * Added moving with order functionality. [Sytse Sijbrandij]
10
+ * Use tablename in all select queries. [Mikhail Dieterle]
11
+ * Made sure all descendants' depths are updated when moving parent, not just immediate child. [Phil Thompson]
12
+ * Add documentation of the callbacks. [Tobias Maier]
13
+
14
+ 2.1.4
15
+ * nested_set_options accept both Class & AR Relation. [Semyon Perepelitsa]
16
+ * Reduce the number of queries triggered by the canonical usage of `i.level` in the `nested_set` helpers. [thedarkone]
17
+ * Specifically require active_record [Bogdan Gusiev]
18
+ * compute_level now checks for a non nil association target. [Joel Nimety]
19
+
20
+ 2.1.3
21
+ * Update child depth when parent node is moved. [Amanda Wagener]
22
+ * Added move_to_child_with_index. [Ben Zhang]
23
+ * Optimised self_and_descendants for when there's an index on lft. [Mark Torrance]
24
+ * Added support for an unsaved record to return the right 'root'. [Philip Arndt]
25
+
26
+ 2.1.2
27
+ * Fixed regressions introduced. [Philip Arndt]
28
+
29
+ 2.1.1
30
+ * Added 'depth' which indicates how many levels deep the node is.
31
+ This only works when you have a column called 'depth' in your table,
32
+ otherwise it doesn't set itself. [Philip Arndt]
33
+ * Rails 3.2 support added. [Gabriel Sobrinho]
34
+ * Oracle compatibility added. [Pikender Sharma]
35
+ * Adding row locking to deletion, locking source of pivot values, and adding retry on collisions. [Markus J. Q. Roberts]
36
+ * Added method and helper for sorting children by column. [bluegod]
37
+ * Fixed .all_roots_valid? to work with Postgres. [Joshua Clayton]
38
+ * Made compatible with polymorphic belongs_to. [Graham Randall]
39
+ * Added in the association callbacks to the children :has_many association. [Michael Deering]
40
+ * Modified helper to allow using array of objects as argument. [Rahmat Budiharso]
41
+ * Fixed cases where we were calling attr_protected. [Jacob Swanner]
42
+ * Fixed nil cases involving lft and rgt. [Stuart Coyle] and [Patrick Morgan]
43
+
44
+ 2.0.2
45
+ * Fixed deprecation warning under Rails 3.1 [Philip Arndt]
46
+ * Converted Test::Unit matchers to RSpec. [Uģis Ozols]
47
+ * Added inverse_of to associations to improve performance rendering trees. [Sergio Cambra]
48
+ * Added row locking and fixed some race conditions. [Markus J. Q. Roberts]
49
+
50
+ 2.0.1
51
+ * Fixed a bug with move_to not using nested_set_scope [Andreas Sekine]
52
+
53
+ 2.0.0.pre
54
+ * Expect Rails 3
55
+ * Changed how callbacks work. Returning false in a before_move action does not block save operations. Use a validation or exception in the callback if you need that.
56
+ * Switched to RSpec
57
+ * Remove use of Comparable
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2007-2011 Collective Idea
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,163 @@
1
+ # AwesomeNestedSet
2
+
3
+ Awesome Nested Set is an implementation of the nested set pattern for ActiveRecord models.
4
+ It is a replacement for acts_as_nested_set and BetterNestedSet, but more awesome.
5
+
6
+ Version 2 supports Rails 3. Gem versions prior to 2.0 support Rails 2.
7
+
8
+ ## What makes this so awesome?
9
+
10
+ This is a new implementation of nested set based off of BetterNestedSet that fixes some bugs, removes tons of duplication, adds a few useful methods, and adds STI support.
11
+
12
+ [![Code Climate](https://codeclimate.com/github/collectiveidea/awesome_nested_set.png)](https://codeclimate.com/github/collectiveidea/awesome_nested_set)
13
+
14
+ ## Installation
15
+
16
+ Add to your Gemfile:
17
+
18
+ ```ruby
19
+ gem 'awesome_nested_set'
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ To make use of `awesome_nested_set`, your model needs to have 3 fields:
25
+ `lft`, `rgt`, and `parent_id`. The names of these fields are configurable.
26
+ You can also have an optional field, `depth`:
27
+
28
+ ```ruby
29
+ class CreateCategories < ActiveRecord::Migration
30
+ def self.up
31
+ create_table :categories do |t|
32
+ t.string :name
33
+ t.integer :parent_id
34
+ t.integer :lft
35
+ t.integer :rgt
36
+ t.integer :depth # this is optional.
37
+ end
38
+ end
39
+
40
+ def self.down
41
+ drop_table :categories
42
+ end
43
+ end
44
+ ```
45
+
46
+ Enable the nested set functionality by declaring `acts_as_nested_set` on your model
47
+
48
+ ```ruby
49
+ class Category < ActiveRecord::Base
50
+ acts_as_nested_set
51
+ end
52
+ ```
53
+
54
+ Run `rake rdoc` to generate the API docs and see [CollectiveIdea::Acts::NestedSet](lib/awesome_nested_set/awesome_nested_set.rb) for more information.
55
+
56
+ ## Callbacks
57
+
58
+ There are three callbacks called when moving a node:
59
+ `before_move`, `after_move` and `around_move`.
60
+
61
+ ```ruby
62
+ class Category < ActiveRecord::Base
63
+ acts_as_nested_set
64
+
65
+ after_move :rebuild_slug
66
+ around_move :da_fancy_things_around
67
+
68
+ private
69
+
70
+ def rebuild_slug
71
+ # do whatever
72
+ end
73
+
74
+ def da_fancy_things_around
75
+ # do something...
76
+ yield # actually moves
77
+ # do something else...
78
+ end
79
+ end
80
+ ```
81
+
82
+ Beside this there are also hooks to act on the newly added or removed children.
83
+
84
+ ```ruby
85
+ class Category < ActiveRecord::Base
86
+ acts_as_nested_set :before_add => :do_before_add_stuff,
87
+ :after_add => :do_after_add_stuff,
88
+ :before_remove => :do_before_remove_stuff,
89
+ :after_remove => :do_after_remove_stuff
90
+
91
+ private
92
+
93
+ def do_before_add_stuff(child_node)
94
+ # do whatever with the child
95
+ end
96
+
97
+ def do_after_add_stuff(child_node)
98
+ # do whatever with the child
99
+ end
100
+
101
+ def do_before_remove_stuff(child_node)
102
+ # do whatever with the child
103
+ end
104
+
105
+ def do_after_remove_stuff(child_node)
106
+ # do whatever with the child
107
+ end
108
+ end
109
+ ```
110
+
111
+ ## Protecting attributes from mass assignment
112
+
113
+ It's generally best to "whitelist" the attributes that can be used in mass assignment:
114
+
115
+ ```ruby
116
+ class Category < ActiveRecord::Base
117
+ acts_as_nested_set
118
+ attr_accessible :name, :parent_id
119
+ end
120
+ ```
121
+
122
+ If for some reason that is not possible, you will probably want to protect the `lft` and `rgt` attributes:
123
+
124
+ ```ruby
125
+ class Category < ActiveRecord::Base
126
+ acts_as_nested_set
127
+ attr_protected :lft, :rgt
128
+ end
129
+ ```
130
+
131
+ ## Conversion from other trees
132
+
133
+ Coming from acts_as_tree or another system where you only have a parent_id? No problem. Simply add the lft & rgt fields as above, and then run:
134
+
135
+ ```ruby
136
+ Category.rebuild!
137
+ ```
138
+
139
+ Your tree will be converted to a valid nested set. Awesome!
140
+
141
+ ## View Helper
142
+
143
+ The view helper is called #nested_set_options.
144
+
145
+ Example usage:
146
+
147
+ ```erb
148
+ <%= f.select :parent_id, nested_set_options(Category, @category) {|i| "#{'-' * i.level} #{i.name}" } %>
149
+
150
+ <%= select_tag 'parent_id', options_for_select(nested_set_options(Category) {|i| "#{'-' * i.level} #{i.name}" } ) %>
151
+ ```
152
+
153
+ See [CollectiveIdea::Acts::NestedSet::Helper](lib/awesome_nested_set/helper.rb) for more information about the helpers.
154
+
155
+ ## References
156
+
157
+ You can learn more about nested sets at: http://threebit.net/tutorials/nestedset/tutorial1.html
158
+
159
+ ## How to contribute
160
+
161
+ Please see the ['Contributing' document](CONTRIBUTING.md).
162
+
163
+ Copyright © 2008 - 2013 Collective Idea, released under the MIT license
@@ -0,0 +1,8 @@
1
+ require 'awesome_nested_set/awesome_nested_set'
2
+ require 'active_record'
3
+ ActiveRecord::Base.send :extend, CollectiveIdea::Acts::NestedSet
4
+
5
+ if defined?(ActionView)
6
+ require 'awesome_nested_set/helper'
7
+ ActionView::Base.send :include, CollectiveIdea::Acts::NestedSet::Helper
8
+ end
@@ -0,0 +1,134 @@
1
+ require 'awesome_nested_set/columns'
2
+ require 'awesome_nested_set/model'
3
+
4
+ module CollectiveIdea #:nodoc:
5
+ module Acts #:nodoc:
6
+ module NestedSet #:nodoc:
7
+
8
+ # This acts provides Nested Set functionality. Nested Set is a smart way to implement
9
+ # an _ordered_ tree, with the added feature that you can select the children and all of their
10
+ # descendants with a single query. The drawback is that insertion or move need some complex
11
+ # sql queries. But everything is done here by this module!
12
+ #
13
+ # Nested sets are appropriate each time you want either an orderd tree (menus,
14
+ # commercial categories) or an efficient way of querying big trees (threaded posts).
15
+ #
16
+ # == API
17
+ #
18
+ # Methods names are aligned with acts_as_tree as much as possible to make replacment from one
19
+ # by another easier.
20
+ #
21
+ # item.children.create(:name => "child1")
22
+ #
23
+
24
+ # Configuration options are:
25
+ #
26
+ # * +:parent_column+ - specifies the column name to use for keeping the position integer (default: parent_id)
27
+ # * +:left_column+ - column name for left boundry data, default "lft"
28
+ # * +:right_column+ - column name for right boundry data, default "rgt"
29
+ # * +:depth_column+ - column name for the depth data, default "depth"
30
+ # * +:scope+ - restricts what is to be considered a list. Given a symbol, it'll attach "_id"
31
+ # (if it hasn't been already) and use that as the foreign key restriction. You
32
+ # can also pass an array to scope by multiple attributes.
33
+ # Example: <tt>acts_as_nested_set :scope => [:notable_id, :notable_type]</tt>
34
+ # * +:dependent+ - behavior for cascading destroy. If set to :destroy, all the
35
+ # child objects are destroyed alongside this object by calling their destroy
36
+ # method. If set to :delete_all (default), all the child objects are deleted
37
+ # without calling their destroy method.
38
+ # * +:counter_cache+ adds a counter cache for the number of children.
39
+ # defaults to false.
40
+ # Example: <tt>acts_as_nested_set :counter_cache => :children_count</tt>
41
+ # * +:order_column+ on which column to do sorting, by default it is the left_column_name
42
+ # Example: <tt>acts_as_nested_set :order_column => :position</tt>
43
+ #
44
+ # See CollectiveIdea::Acts::NestedSet::Model::ClassMethods for a list of class methods and
45
+ # CollectiveIdea::Acts::NestedSet::Model for a list of instance methods added
46
+ # to acts_as_nested_set models
47
+ def acts_as_nested_set(options = {})
48
+ acts_as_nested_set_parse_options! options
49
+
50
+ include Model
51
+ include Columns
52
+ extend Columns
53
+
54
+ acts_as_nested_set_relate_parent!
55
+ acts_as_nested_set_relate_children!
56
+
57
+ attr_accessor :skip_before_destroy
58
+
59
+ acts_as_nested_set_prevent_assignment_to_reserved_columns!
60
+ acts_as_nested_set_define_callbacks!
61
+ end
62
+
63
+ private
64
+ def acts_as_nested_set_define_callbacks!
65
+ # on creation, set automatically lft and rgt to the end of the tree
66
+ before_create :set_default_left_and_right
67
+ before_save :store_new_parent
68
+ after_save :move_to_new_parent, :set_depth!
69
+ before_destroy :destroy_descendants
70
+
71
+ define_model_callbacks :move
72
+ end
73
+
74
+ def acts_as_nested_set_relate_children!
75
+ has_many_children_options = {
76
+ :class_name => self.base_class.to_s,
77
+ :foreign_key => parent_column_name,
78
+ :order => quoted_order_column_name,
79
+ :inverse_of => (:parent unless acts_as_nested_set_options[:polymorphic]),
80
+ }
81
+
82
+ # Add callbacks, if they were supplied.. otherwise, we don't want them.
83
+ [:before_add, :after_add, :before_remove, :after_remove].each do |ar_callback|
84
+ has_many_children_options.update(ar_callback => acts_as_nested_set_options[ar_callback]) if acts_as_nested_set_options[ar_callback]
85
+ end
86
+
87
+ order_condition = has_many_children_options.delete(:order)
88
+ has_many :children, -> { order(order_condition) }, has_many_children_options
89
+ end
90
+
91
+ def acts_as_nested_set_relate_parent!
92
+ belongs_to :parent, :class_name => self.base_class.to_s,
93
+ :foreign_key => parent_column_name,
94
+ :counter_cache => acts_as_nested_set_options[:counter_cache],
95
+ :inverse_of => (:children unless acts_as_nested_set_options[:polymorphic]),
96
+ :polymorphic => acts_as_nested_set_options[:polymorphic]
97
+ end
98
+
99
+ def acts_as_nested_set_default_options
100
+ {
101
+ :parent_column => 'parent_id',
102
+ :left_column => 'lft',
103
+ :right_column => 'rgt',
104
+ :depth_column => 'depth',
105
+ :dependent => :delete_all, # or :destroy
106
+ :polymorphic => false,
107
+ :counter_cache => false
108
+ }.freeze
109
+ end
110
+
111
+ def acts_as_nested_set_parse_options!(options)
112
+ options = acts_as_nested_set_default_options.merge(options)
113
+
114
+ if options[:scope].is_a?(Symbol) && options[:scope].to_s !~ /_id$/
115
+ options[:scope] = "#{options[:scope]}_id".intern
116
+ end
117
+
118
+ class_attribute :acts_as_nested_set_options
119
+ self.acts_as_nested_set_options = options
120
+ end
121
+
122
+ def acts_as_nested_set_prevent_assignment_to_reserved_columns!
123
+ # no assignment to structure fields
124
+ [left_column_name, right_column_name, depth_column_name].each do |column|
125
+ module_eval <<-"end_eval", __FILE__, __LINE__
126
+ def #{column}=(x)
127
+ raise ActiveRecord::ActiveRecordError, "Unauthorized assignment to #{column}: it's an internal field handled by acts_as_nested_set code, use move_to_* methods instead."
128
+ end
129
+ end_eval
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,72 @@
1
+ # Mixed into both classes and instances to provide easy access to the column names
2
+ module CollectiveIdea #:nodoc:
3
+ module Acts #:nodoc:
4
+ module NestedSet #:nodoc:
5
+ module Columns
6
+ def left_column_name
7
+ acts_as_nested_set_options[:left_column]
8
+ end
9
+
10
+ def right_column_name
11
+ acts_as_nested_set_options[:right_column]
12
+ end
13
+
14
+ def depth_column_name
15
+ acts_as_nested_set_options[:depth_column]
16
+ end
17
+
18
+ def parent_column_name
19
+ acts_as_nested_set_options[:parent_column]
20
+ end
21
+
22
+ def order_column
23
+ acts_as_nested_set_options[:order_column] || left_column_name
24
+ end
25
+
26
+ def scope_column_names
27
+ Array(acts_as_nested_set_options[:scope])
28
+ end
29
+
30
+ def quoted_left_column_name
31
+ ActiveRecord::Base.connection.quote_column_name(left_column_name)
32
+ end
33
+
34
+ def quoted_right_column_name
35
+ ActiveRecord::Base.connection.quote_column_name(right_column_name)
36
+ end
37
+
38
+ def quoted_depth_column_name
39
+ ActiveRecord::Base.connection.quote_column_name(depth_column_name)
40
+ end
41
+
42
+ def quoted_parent_column_name
43
+ ActiveRecord::Base.connection.quote_column_name(parent_column_name)
44
+ end
45
+
46
+ def quoted_scope_column_names
47
+ scope_column_names.collect {|column_name| connection.quote_column_name(column_name) }
48
+ end
49
+
50
+ def quoted_order_column_name
51
+ ActiveRecord::Base.connection.quote_column_name(order_column)
52
+ end
53
+
54
+ def quoted_primary_key_column_full_name
55
+ "#{quoted_table_name}.#{ActiveRecord::Base.connection.quote_column_name('id')}"
56
+ end
57
+
58
+ def quoted_left_column_full_name
59
+ "#{quoted_table_name}.#{quoted_left_column_name}"
60
+ end
61
+
62
+ def quoted_right_column_full_name
63
+ "#{quoted_table_name}.#{quoted_right_column_name}"
64
+ end
65
+
66
+ def quoted_parent_column_full_name
67
+ "#{quoted_table_name}.#{quoted_parent_column_name}"
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end