mongoid_listable 0.1.0 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Coverage Status](https://coveralls.io/repos/richardcalahan/mongoid_listable/badge.png?branch=master)](https://coveralls.io/r/richardcalahan/mongoid_listable?branch=master)
|
5
5
|
[![Gem Version](https://badge.fury.io/rb/mongoid_listable.png)](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
|