mongoid_listable 0.1.0 → 0.1.3
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.
- checksums.yaml +8 -8
- data/.rspec +2 -0
- data/README.md +43 -14
- data/lib/mongoid/listable.rb +6 -50
- data/lib/mongoid/listable/accessors.rb +5 -5
- data/lib/mongoid/listable/callbacks.rb +110 -54
- data/lib/mongoid/listable/macros.rb +13 -11
- data/lib/mongoid/listable/version.rb +1 -1
- data/spec/mongoid_listable_spec.rb +126 -90
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OGY4YzBjMjJiMzExZjI2M2M2YTFmNTBkMjM5MmY0ZTMyMjNjNzYwZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YmVlYmFjMDk1YmE2NjE4ZjkxZDgwZTYwMzhmOWU1ZTI2ZTcyMGZjMw==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OTliYmRiODE5MTlmYzA3OTM0MjE2MWMyYzg1OWZiMGIzYmY1ZTIyYzdlZmVh
|
10
|
+
MDBhMTcyMjdjMDIxZjdhOTc0OTU0YWNhMGM2YjAwNDlkNjdiOTNkM2M0OTIw
|
11
|
+
YTBmOTRmNzRiOWQwNTE4MDYwNTI4ZmUzNzlhOTQxMjVhOWU2N2Q=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YWVhZGRiNGFhZGQ3ZjA4MmE0NWQ3ZDdiNjIxYmI5NDk5OTk3OWFiYzdhNTNl
|
14
|
+
MGY1NDg0ODhkYzNkNTU5MTg4ZTYxNjBjMDc2MWNkNGNlNTc2ZGJmMzdhYzAx
|
15
|
+
OWQzYTRlYWY1MDhiYWEwMmI2YTRiNTZhOGU2NmJhZWRiYWU5OGI=
|
data/.rspec
ADDED
data/README.md
CHANGED
@@ -4,11 +4,28 @@
|
|
4
4
|
[](https://coveralls.io/r/richardcalahan/mongoid_listable?branch=master)
|
5
5
|
[](http://badge.fury.io/rb/mongoid_listable)
|
6
6
|
|
7
|
-
Mongoid Listable
|
8
|
-
|
9
|
-
|
7
|
+
Mongoid Listable manages lists for isolated collections or for more complex `has_many` / `belongs_to` relationships.
|
8
|
+
There are two main macros:
|
9
|
+
|
10
|
+
`listed` for isolated lists not belonging to any parent object.
|
11
|
+
`lists` for `has_many` / `belongs_to` relationships
|
12
|
+
|
13
|
+
|
14
|
+
## Basic Usage - Isolated
|
15
|
+
|
16
|
+
class Photo
|
17
|
+
include Mongoid::Document
|
18
|
+
include Mongoid::Listable
|
19
|
+
|
20
|
+
listed
|
21
|
+
end
|
22
|
+
|
23
|
+
The `listed` macro will assign a `position` field and a `list` scope to the Photo class. All Photo instances
|
24
|
+
added or removed, (or whose position fields are updated) will trigger automatic reording of all sibling instances.
|
25
|
+
|
26
|
+
|
27
|
+
## Basic Usage - Has Many
|
10
28
|
|
11
|
-
## Basic Usage
|
12
29
|
|
13
30
|
class User
|
14
31
|
include Mongoid::Document
|
@@ -26,16 +43,31 @@ defined `has_many` / `belongs_to` relation.
|
|
26
43
|
...
|
27
44
|
end
|
28
45
|
|
29
|
-
In this example photos that are
|
30
|
-
|
46
|
+
In this example photos that are added to or removed from a user, or have their position attribute updated
|
47
|
+
will maintain logical order based on the method used:
|
48
|
+
|
49
|
+
# setter
|
50
|
+
User.first.photos = [ photo_a, photo_c, photo_b ]
|
51
|
+
User.first.photos.last == photo_b #=> true
|
52
|
+
|
53
|
+
# ids setter
|
54
|
+
User.first.photo_ids = [ '527fe97c67df6f07e1000003', '527fe97c67df6f07e1000004', '527fe97c67df6f07e1000003' ]
|
55
|
+
User.first.photos[1].id == '527fe97c67df6f07e1000004' #=> true
|
56
|
+
|
57
|
+
# push
|
58
|
+
photo = Photo.create
|
59
|
+
User.first.photos << photo
|
60
|
+
User.first.photos.last == photo #=> true
|
61
|
+
|
62
|
+
|
31
63
|
|
32
|
-
Each photo that belongs to the user will automatically obtain a field called `user_position`. The
|
33
|
-
is derived from the foreign key of the relation, replacing "\_id" with "_position".
|
64
|
+
Each photo that belongs to the user will automatically obtain a field called `user_position`. The field
|
65
|
+
is derived from the foreign key of the relation, replacing "\_id" with "_position".
|
34
66
|
|
35
|
-
The
|
67
|
+
The `has_many` relation of a user to their photos will automatically be ordered by `user_position` unless otherwise specified
|
36
68
|
via the standard `order` option to the `has_many` macro.
|
37
69
|
|
38
|
-
##
|
70
|
+
## Advanced Usage - Has Many
|
39
71
|
|
40
72
|
# Handles multiple has_many relations on same model!
|
41
73
|
|
@@ -77,13 +109,10 @@ via the standard `order` option to the `has_many` macro.
|
|
77
109
|
In this example, there are two `has_many` relations defined between a user and photos. Each photo belonging to a user will
|
78
110
|
obtain two position fields: `featured_by_user_position` and `kodaked_by_user_position`.
|
79
111
|
|
80
|
-
You can optionally override the name of the position column:
|
81
|
-
|
82
|
-
lists :photos, column: :users_photos_order
|
83
112
|
|
84
113
|
## Todo
|
85
114
|
|
86
|
-
|
115
|
+
Need to test embedded documents.
|
87
116
|
|
88
117
|
## Installation
|
89
118
|
|
data/lib/mongoid/listable.rb
CHANGED
@@ -49,24 +49,17 @@ module Mongoid
|
|
49
49
|
send(name).uniq(&:id).count
|
50
50
|
end
|
51
51
|
|
52
|
-
|
53
|
-
|
54
|
-
# Applies a position change on column. Which objects are repositioned
|
55
|
-
# depends on the direction of the change.
|
52
|
+
# Retrieves an object's list siblings
|
56
53
|
#
|
57
|
-
# @
|
54
|
+
# @return [ Array ]
|
58
55
|
#
|
59
56
|
# @since 0.1.0
|
60
|
-
def
|
61
|
-
|
62
|
-
if to > from
|
63
|
-
reposition siblings.between(column => from..to), column, from
|
64
|
-
elsif to < from
|
65
|
-
reposition siblings.between(column => to..from), column, to + 1
|
66
|
-
end
|
67
|
-
set column, to
|
57
|
+
def siblings field=:position
|
58
|
+
self.class.exists(field => true).ne id: id
|
68
59
|
end
|
69
60
|
|
61
|
+
private
|
62
|
+
|
70
63
|
# Resets column on objects starting at 'start'
|
71
64
|
#
|
72
65
|
# @param [ Array ] objects The objects to interate
|
@@ -80,42 +73,5 @@ module Mongoid
|
|
80
73
|
end
|
81
74
|
end
|
82
75
|
|
83
|
-
# Returns the old and new values for column
|
84
|
-
#
|
85
|
-
# @param [ Symbol ] column The column to retrieve the change
|
86
|
-
# @return [Array] [from, to]
|
87
|
-
#
|
88
|
-
# @since 0.1.0
|
89
|
-
def change_on column
|
90
|
-
from, to = send "#{column}_change"
|
91
|
-
to = safe_to to
|
92
|
-
[from, to]
|
93
|
-
end
|
94
|
-
|
95
|
-
# Ensures the 'to' value is within acceptable bounds
|
96
|
-
#
|
97
|
-
# @param [ Integer ] to The supplied position value
|
98
|
-
# @return [ Integer ] The acceptable position value
|
99
|
-
#
|
100
|
-
# @since 0.1.0
|
101
|
-
def safe_to to
|
102
|
-
if to > self.class.count
|
103
|
-
self.class.count
|
104
|
-
elsif to < 1
|
105
|
-
1
|
106
|
-
else
|
107
|
-
to
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
# Retrieves an object's list siblings
|
112
|
-
#
|
113
|
-
# @return [ Array ]
|
114
|
-
#
|
115
|
-
# @since 0.1.0
|
116
|
-
def siblings
|
117
|
-
self.class.list.ne id: id
|
118
|
-
end
|
119
|
-
|
120
76
|
end
|
121
77
|
end
|
@@ -16,11 +16,12 @@ module Mongoid
|
|
16
16
|
# @return [ Object ] self
|
17
17
|
#
|
18
18
|
# @since 0.0.6
|
19
|
-
def
|
19
|
+
def ids_set name, meta
|
20
20
|
ids_method = "#{name.to_s.singularize}_ids="
|
21
21
|
redefine_method ids_method do |ids|
|
22
22
|
send meta.setter, meta.klass.find(ids).sort_by_attr(:id, ids)
|
23
23
|
end
|
24
|
+
|
24
25
|
self
|
25
26
|
end
|
26
27
|
|
@@ -33,17 +34,16 @@ module Mongoid
|
|
33
34
|
# @return [ Object ] self
|
34
35
|
#
|
35
36
|
# @since 0.0.6
|
36
|
-
def
|
37
|
+
def set name, meta
|
37
38
|
before_method "#{name}=" do |objects|
|
38
39
|
objects ||= []
|
39
|
-
objects
|
40
|
-
object.set field_name(meta), index + 1
|
41
|
-
end
|
40
|
+
reposition objects, field_name(meta), 1
|
42
41
|
|
43
42
|
(send(name).to_a - objects).each do |object|
|
44
43
|
object.unset field_name(meta)
|
45
44
|
end
|
46
45
|
end
|
46
|
+
|
47
47
|
self
|
48
48
|
end
|
49
49
|
|
@@ -6,104 +6,160 @@ module Mongoid
|
|
6
6
|
|
7
7
|
module ClassMethods
|
8
8
|
|
9
|
-
# Defines a mongoid
|
10
|
-
# Sets the position
|
9
|
+
# Defines a mongoid before_create callback.
|
10
|
+
# Sets the position field to current object count + 1
|
11
11
|
#
|
12
|
-
# @param [
|
13
|
-
# @param [ MetaData ] meta The MetaData class
|
12
|
+
# @param [ Hash ] The configuration hash
|
14
13
|
#
|
15
14
|
# @return [ Object ] self
|
16
15
|
#
|
17
|
-
# @since 0.0
|
18
|
-
def
|
19
|
-
callback = "#{name
|
20
|
-
define_method callback do
|
21
|
-
|
22
|
-
|
16
|
+
# @since 0.1.0
|
17
|
+
def created name
|
18
|
+
callback = "#{name}_#{__method__}"
|
19
|
+
define_method callback do
|
20
|
+
position = send name
|
21
|
+
if position.present?
|
22
|
+
siblings = siblings(name).gte name => position
|
23
|
+
reposition siblings, name, position + 1
|
24
|
+
else
|
25
|
+
set name, siblings(name).count + 1
|
23
26
|
end
|
24
27
|
end
|
25
|
-
|
28
|
+
|
29
|
+
before_create callback
|
26
30
|
self
|
27
31
|
end
|
28
32
|
|
29
|
-
# Defines a mongoid
|
30
|
-
#
|
33
|
+
# Defines a mongoid before_update callback.
|
34
|
+
# If the position column has changed, apply the change.
|
35
|
+
# Hoe the change is applied varies depending on the redrection
|
36
|
+
# of the update.
|
31
37
|
#
|
32
|
-
# @param [
|
33
|
-
# @param [ MetaData ] meta The MetaData class
|
38
|
+
# @param [ Hash ] The configuration hash
|
34
39
|
#
|
35
40
|
# @return [ Object ] self
|
36
41
|
#
|
37
|
-
# @since 0.0
|
38
|
-
def
|
39
|
-
|
40
|
-
callback
|
41
|
-
|
42
|
-
define_method callback do |object|
|
43
|
-
position = object.send field_name
|
44
|
-
send(name).where(field_name.gt => position)
|
45
|
-
.each_with_index do |object, index|
|
46
|
-
object.set field_name, position + index
|
47
|
-
end
|
48
|
-
object.unset field_name
|
42
|
+
# @since 0.1.0
|
43
|
+
def updated name
|
44
|
+
callback = "#{name}_#{__method__}"
|
45
|
+
define_method callback do
|
46
|
+
apply_change_on name if send("#{name}_changed?")
|
49
47
|
end
|
50
48
|
|
51
|
-
|
49
|
+
before_update callback
|
52
50
|
self
|
53
51
|
end
|
54
52
|
|
55
|
-
# Defines a mongoid
|
56
|
-
#
|
53
|
+
# Defines a mongoid before_destroy callback.
|
54
|
+
# Resets all sibling object's higher in the list
|
57
55
|
#
|
58
56
|
# @param [ Hash ] The configuration hash
|
59
57
|
#
|
60
58
|
# @return [ Object ] self
|
61
59
|
#
|
62
60
|
# @since 0.1.0
|
63
|
-
def
|
64
|
-
|
65
|
-
|
61
|
+
def destroyed name
|
62
|
+
callback = "#{name}_#{__method__}"
|
63
|
+
define_method callback do
|
64
|
+
position = send name
|
65
|
+
siblings = siblings(name).gt(name => position)
|
66
|
+
reposition siblings, name, position
|
66
67
|
end
|
67
|
-
|
68
|
+
|
69
|
+
before_destroy callback
|
68
70
|
self
|
69
71
|
end
|
70
72
|
|
71
|
-
# Defines a mongoid
|
72
|
-
#
|
73
|
-
# Hoe the change is applied varies depending on the redrection
|
74
|
-
# of the update.
|
73
|
+
# Defines a mongoid has_many relation after_add callback.
|
74
|
+
# Sets the position attribute to current relations length + 1
|
75
75
|
#
|
76
|
-
# @param [
|
76
|
+
# @param [ Symbol ] name The name of the has_many relation
|
77
|
+
# @param [ MetaData ] meta The MetaData class
|
77
78
|
#
|
78
79
|
# @return [ Object ] self
|
79
80
|
#
|
80
|
-
# @since 0.
|
81
|
-
def
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
# @since 0.0.6
|
82
|
+
def added name, meta
|
83
|
+
callback = "#{name.to_s.singularize}_added"
|
84
|
+
define_method callback do |object|
|
85
|
+
if object[field_name(meta)].nil?
|
86
|
+
object.set field_name(meta), has_many_count(name) + 1
|
87
|
+
end
|
85
88
|
end
|
86
|
-
|
89
|
+
meta[:before_add] = callback
|
87
90
|
self
|
88
91
|
end
|
89
92
|
|
90
|
-
# Defines a mongoid
|
91
|
-
# Resets
|
93
|
+
# Defines a mongoid has_many relation before_remove callback.
|
94
|
+
# Resets the position index on all objects that came after
|
92
95
|
#
|
93
|
-
# @param [
|
96
|
+
# @param [ Symbol ] name The name of the has_many relation
|
97
|
+
# @param [ MetaData ] meta The MetaData class
|
94
98
|
#
|
95
99
|
# @return [ Object ] self
|
96
100
|
#
|
97
|
-
# @since 0.
|
98
|
-
def
|
99
|
-
|
100
|
-
|
101
|
-
|
101
|
+
# @since 0.0.6
|
102
|
+
def removed name, meta
|
103
|
+
field_name = field_name meta
|
104
|
+
callback = "#{name.to_s.singularize}_removed"
|
105
|
+
define_method callback do |object|
|
106
|
+
position = object.send field_name
|
107
|
+
reposition object.siblings(field_name).gt(field_name => position),
|
108
|
+
field_name, position
|
109
|
+
object.unset field_name
|
102
110
|
end
|
103
|
-
|
111
|
+
|
112
|
+
meta[:before_remove] = callback
|
104
113
|
self
|
105
114
|
end
|
106
115
|
|
116
|
+
end # ClassMethods
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
# Applies a position change on column. Which objects are repositioned
|
121
|
+
# depends on the direction of the change.
|
122
|
+
#
|
123
|
+
# @param [ Symbol ] name The name of position column
|
124
|
+
#
|
125
|
+
# @since 0.1.0
|
126
|
+
def apply_change_on name
|
127
|
+
from, to = change_on name
|
128
|
+
siblings = siblings name
|
129
|
+
if to > from
|
130
|
+
reposition siblings.between(name => from..to), name, from
|
131
|
+
elsif to < from
|
132
|
+
reposition siblings.between(name => to..from), name, to + 1
|
133
|
+
end
|
134
|
+
set name, to
|
135
|
+
end
|
136
|
+
|
137
|
+
# Returns the old and new values for column
|
138
|
+
#
|
139
|
+
# @param [ Symbol ] column The column to retrieve the change
|
140
|
+
# @return [Array] [from, to]
|
141
|
+
#
|
142
|
+
# @since 0.1.0
|
143
|
+
def change_on column
|
144
|
+
from, to = send "#{column}_change"
|
145
|
+
to = safe_to to
|
146
|
+
[from, to]
|
147
|
+
end
|
148
|
+
|
149
|
+
# Ensures the 'to' value is within acceptable bounds
|
150
|
+
#
|
151
|
+
# @param [ Integer ] to The supplied position value
|
152
|
+
# @return [ Integer ] The acceptable position value
|
153
|
+
#
|
154
|
+
# @since 0.1.0
|
155
|
+
def safe_to to
|
156
|
+
if to > self.class.count
|
157
|
+
self.class.count
|
158
|
+
elsif to < 1
|
159
|
+
1
|
160
|
+
else
|
161
|
+
to
|
162
|
+
end
|
107
163
|
end
|
108
164
|
|
109
165
|
end
|
@@ -16,16 +16,16 @@ module Mongoid
|
|
16
16
|
#
|
17
17
|
# @since 0.1.0
|
18
18
|
def listed options={}
|
19
|
-
configuration = {
|
19
|
+
configuration = { field_name: :position }
|
20
20
|
configuration.merge! options if options.is_a?(Hash)
|
21
21
|
|
22
|
-
|
22
|
+
field_name = configuration[:field_name]
|
23
23
|
|
24
|
-
|
25
|
-
.updated(configuration)
|
26
|
-
.destroyed(configuration)
|
24
|
+
field field_name, type: Integer
|
27
25
|
|
28
|
-
|
26
|
+
created(field_name).updated(field_name).destroyed(field_name)
|
27
|
+
|
28
|
+
scope :list, order_by(field_name => :asc)
|
29
29
|
self
|
30
30
|
end
|
31
31
|
|
@@ -39,11 +39,13 @@ module Mongoid
|
|
39
39
|
# @since 0.0.1
|
40
40
|
def lists name, options={}
|
41
41
|
meta = reflect_on_association name
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
.added(name, meta)
|
46
|
-
|
42
|
+
field_name = field_name(meta)
|
43
|
+
meta.klass.send :field, field_name, type: Integer
|
44
|
+
ids_set(name, meta).set(name, meta)
|
45
|
+
.added(name, meta).removed(name, meta)
|
46
|
+
|
47
|
+
meta.klass.updated(field_name).destroyed(field_name)
|
48
|
+
|
47
49
|
meta[:order] ||= "#{field_name(meta)} asc"
|
48
50
|
end
|
49
51
|
|
@@ -1,126 +1,162 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Mongoid::Listable do
|
3
|
+
describe Mongoid::Listable do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
it 'created a user' do
|
11
|
-
expect(User.first).to be_true
|
5
|
+
def ensure_order objects, field
|
6
|
+
objects.each_with_index do |object, index|
|
7
|
+
expect(object[field]).to eq(index + 1)
|
8
|
+
end
|
12
9
|
end
|
13
10
|
|
14
|
-
|
15
|
-
expect(Photo.count).to eq(10)
|
16
|
-
end
|
11
|
+
describe 'listed' do
|
17
12
|
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
before :all do
|
14
|
+
Photo.destroy_all
|
15
|
+
10.times { Photo.create }
|
16
|
+
end
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
expect(photo.position).to eq(index + 1)
|
18
|
+
after :each do
|
19
|
+
ensure_order Photo.list, :position
|
25
20
|
end
|
26
|
-
end
|
27
21
|
|
28
|
-
|
29
|
-
|
30
|
-
|
22
|
+
it 'adds an object to the beginning of a list on create' do
|
23
|
+
photo = Photo.create position: 1
|
24
|
+
expect(Photo.list.first.position).to eq(1)
|
25
|
+
expect(photo.id).to eq(Photo.list.first.id)
|
26
|
+
end
|
31
27
|
|
32
|
-
|
33
|
-
|
28
|
+
it 'adds an object to the middle of a list on create' do
|
29
|
+
photo = Photo.create position: 5
|
30
|
+
expect(Photo.list[4].position).to eq(5)
|
31
|
+
expect(photo.id).to eq(Photo.list[4].id)
|
32
|
+
end
|
34
33
|
|
35
|
-
|
34
|
+
it 'adds an object to the end of a list on create' do
|
35
|
+
photo = Photo.create
|
36
|
+
expect(Photo.list.last.position).to eq(13)
|
37
|
+
expect(photo.id).to eq(Photo.list.last.id)
|
38
|
+
end
|
36
39
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
it 'updates the position of an object higher' do
|
41
|
+
photo_id = Photo.list[1].id
|
42
|
+
Photo.list[1].update_attribute :position, 4
|
43
|
+
expect(photo_id).to eq(Photo.list[3].id)
|
44
|
+
expect(Photo.list[3].position).to eq(4)
|
45
|
+
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
47
|
+
it 'updates the position of an object lower' do
|
48
|
+
photo_id = Photo.list[9].id
|
49
|
+
Photo.list[9].update_attribute :position, 2
|
50
|
+
expect(photo_id).to eq(Photo.list[1].id)
|
51
|
+
expect(Photo.list[1].position).to eq(2)
|
52
|
+
end
|
44
53
|
|
45
|
-
|
46
|
-
|
54
|
+
it 'updates the position of an object the same' do
|
55
|
+
photo_id = Photo.list[4].id
|
56
|
+
Photo.list[4].update_attribute :position, 5
|
57
|
+
expect(photo_id).to eq(Photo.list[4].id)
|
58
|
+
expect(Photo.list[4].position).to eq(5)
|
59
|
+
end
|
47
60
|
|
48
|
-
|
61
|
+
it 'removes an object from the beginning of a list on destroy' do
|
62
|
+
Photo.list.first.destroy
|
63
|
+
expect(Photo.list.first.position).to eq(1)
|
64
|
+
end
|
49
65
|
|
50
|
-
|
51
|
-
|
52
|
-
|
66
|
+
it 'removes an object from the middle of a list on destroy' do
|
67
|
+
Photo.list[6].destroy
|
68
|
+
expect(Photo.list.first.position).to eq(1)
|
69
|
+
expect(Photo.list[6].position).to eq(7)
|
70
|
+
expect(Photo.list.last.position).to eq(11)
|
71
|
+
end
|
53
72
|
|
54
|
-
|
55
|
-
|
56
|
-
|
73
|
+
it 'removes an object from the end of a list on destroy' do
|
74
|
+
Photo.list.last.destroy
|
75
|
+
expect(Photo.list.last.position).to eq(10)
|
76
|
+
end
|
77
|
+
end
|
57
78
|
|
58
|
-
|
79
|
+
describe 'lists' do
|
59
80
|
|
60
|
-
|
81
|
+
before :all do
|
82
|
+
User.destroy_all
|
83
|
+
Photo.destroy_all
|
61
84
|
|
62
|
-
|
63
|
-
|
85
|
+
User.create
|
86
|
+
10.times { Photo.create }
|
87
|
+
end
|
64
88
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
expect(Photo.last.position).to eq(10)
|
69
|
-
end
|
89
|
+
after :each do
|
90
|
+
ensure_order User.first.photos, :user_position
|
91
|
+
end
|
70
92
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
93
|
+
it 'sets object list of an owner with the default setter' do
|
94
|
+
photos = Photo.all
|
95
|
+
User.first.photos = photos
|
96
|
+
photos.each_with_index do |photo, index|
|
97
|
+
expect(photo.id).to eq(User.first.photos[index].id)
|
98
|
+
end
|
99
|
+
expect(User.first.photos.count).to eq(Photo.count)
|
100
|
+
end
|
75
101
|
|
76
|
-
|
77
|
-
|
78
|
-
|
102
|
+
it 'sets object list of an owner with the default ids setter' do
|
103
|
+
ids = Photo.all[2..7].collect(&:id)
|
104
|
+
User.first.photo_ids = ids
|
105
|
+
ids.each_with_index do |id, index|
|
106
|
+
expect(id).to eq(User.first.photos[index].id)
|
107
|
+
end
|
108
|
+
expect(User.first.photos.count).to eq(6)
|
79
109
|
end
|
80
|
-
end
|
81
110
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
111
|
+
it 'pushes objects to the list of an owner' do
|
112
|
+
User.first.photos << Photo.all
|
113
|
+
expect(User.first.photos.count).to eq(10)
|
114
|
+
end
|
86
115
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
116
|
+
it 'updates the position of an object higher' do
|
117
|
+
photo_id = User.first.photos[4].id
|
118
|
+
Photo.find(photo_id).update_attribute :user_position, 6
|
119
|
+
expect(photo_id).to eq(User.first.photos[5].id)
|
120
|
+
expect(User.first.photos[5].user_position).to eq(6)
|
121
|
+
end
|
91
122
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
123
|
+
it 'updates the position of an object lower' do
|
124
|
+
photo_id = User.first.photos[4].id
|
125
|
+
Photo.find(photo_id).update_attribute :user_position, 1
|
126
|
+
expect(photo_id).to eq(User.first.photos[0].id)
|
127
|
+
expect(User.first.photos[0].user_position).to eq(1)
|
128
|
+
end
|
96
129
|
|
97
|
-
|
98
|
-
|
99
|
-
|
130
|
+
it 'updates the position of an object the same' do
|
131
|
+
photo_id = User.first.photos[4].id
|
132
|
+
Photo.find(photo_id).update_attribute :user_position, 5
|
133
|
+
expect(photo_id).to eq(User.first.photos[4].id)
|
134
|
+
expect(User.first.photos[4].user_position).to eq(5)
|
100
135
|
end
|
101
|
-
end
|
102
136
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
137
|
+
it 'updates the position of an object out of bounds high' do
|
138
|
+
photo_id = User.first.photos[4].id
|
139
|
+
Photo.find(photo_id).update_attribute :user_position, 1000
|
140
|
+
expect(photo_id).to eq(User.first.photos.last.id)
|
141
|
+
expect(User.first.photos.last.user_position).to eq(User.first.photos.count)
|
142
|
+
end
|
108
143
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
144
|
+
it 'updates the position of an object out of bounds low' do
|
145
|
+
photo_id = User.first.photos[4].id
|
146
|
+
Photo.find(photo_id).update_attribute :user_position, -2
|
147
|
+
expect(photo_id).to eq(User.first.photos.first.id)
|
148
|
+
expect(User.first.photos.first.user_position).to eq(1)
|
149
|
+
end
|
114
150
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
end
|
151
|
+
it 'removes objects from the list of an owner with the default unsetter' do
|
152
|
+
User.first.photos.delete(Photo.first)
|
153
|
+
expect(User.first.photos.count).to eq(9)
|
154
|
+
end
|
120
155
|
|
121
|
-
|
122
|
-
|
123
|
-
expect(
|
156
|
+
it 'removes objects from the list of an owner by destroy' do
|
157
|
+
Photo.all[3].destroy
|
158
|
+
expect(User.first.photos.count).to eq(8)
|
159
|
+
Photo.first.destroy
|
124
160
|
end
|
125
161
|
end
|
126
162
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_listable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- richardcalahan
|
@@ -61,6 +61,7 @@ extra_rdoc_files: []
|
|
61
61
|
files:
|
62
62
|
- .coveralls.yml
|
63
63
|
- .gitignore
|
64
|
+
- .rspec
|
64
65
|
- .travis.yml
|
65
66
|
- Gemfile
|
66
67
|
- LICENSE.txt
|