mongoid_denormalize 0.4.2 → 1.0.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.
- checksums.yaml +7 -0
- data/LICENSE +19 -19
- data/README.md +168 -161
- data/lib/mongoid_denormalize.rb +121 -120
- data/lib/mongoid_denormalize/version.rb +5 -5
- data/lib/railties/denormalize.rake +38 -38
- data/lib/railties/railtie.rb +8 -8
- data/spec/mongoid_denormalize_spec.rb +145 -149
- metadata +15 -26
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6081ab30b9501363e07033bda0c9d8905e9fa4ba
|
4
|
+
data.tar.gz: 92668ecc79b16a74fb51c9d279c99e48a37a3825
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fcbc69ea331a4d5a13e21730742fd72c907f31958cf7a663278df3d67da3dbfd0902f1f0bca7b0281b63c831d7be8407a3a586d00c6eb2759aebb91479b1f522
|
7
|
+
data.tar.gz: 3b489b8eb8727cf5cd8b64783e003b509f45c03e871946d2eb7b14146f32503b730d5df246c593d4f2321511cd982e6ef698c7e4534f3c2938fe960d48d7fc39
|
data/LICENSE
CHANGED
@@ -1,20 +1,20 @@
|
|
1
|
-
Copyright (c) 2010 Logan Raarup
|
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
|
1
|
+
Copyright (c) 2010 Logan Raarup
|
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
20
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
@@ -1,161 +1,168 @@
|
|
1
|
-
Mongoid::Denormalize
|
2
|
-
====================
|
3
|
-
|
4
|
-
*Note: I am no longer actively maintaining this module, and I do not know whether it is compatible with newer versions of mongoid. If you would like to take ownership of this repository, please let me know.*
|
5
|
-
|
6
|
-
|
7
|
-
Helper module for denormalizing association attributes in Mongoid models. Why denormalize? Read *[A Note on Denormalization](http://www.mongodb.org/display/DOCS/MongoDB+Data+Modeling+and+Rails#MongoDBDataModelingandRails-ANoteonDenormalization)*.
|
8
|
-
|
9
|
-
Extracted from [coookin'](http://coookin.com), where it is used in production.
|
10
|
-
|
11
|
-
|
12
|
-
Installation
|
13
|
-
------------
|
14
|
-
|
15
|
-
Add the gem to your Bundler `Gemfile`:
|
16
|
-
|
17
|
-
gem 'mongoid_denormalize'
|
18
|
-
|
19
|
-
Or install with RubyGems:
|
20
|
-
|
21
|
-
$ gem install mongoid_denormalize
|
22
|
-
|
23
|
-
|
24
|
-
Usage
|
25
|
-
-----
|
26
|
-
|
27
|
-
In your model:
|
28
|
-
|
29
|
-
# Include the helper method
|
30
|
-
include Mongoid::Denormalize
|
31
|
-
|
32
|
-
# Define your denormalized fields
|
33
|
-
denormalize :name, :email, :from => :user
|
34
|
-
|
35
|
-
|
36
|
-
Example
|
37
|
-
-------
|
38
|
-
|
39
|
-
class User
|
40
|
-
include Mongoid::Document
|
41
|
-
include Mongoid::Denormalize
|
42
|
-
|
43
|
-
has_many :comments
|
44
|
-
has_many :moderated_comments, :class_name => "Comment", :inverse_of => :moderator
|
45
|
-
|
46
|
-
field :name
|
47
|
-
field :email
|
48
|
-
|
49
|
-
denormalize :name, :email, :to => :comments
|
50
|
-
end
|
51
|
-
|
52
|
-
class Comment
|
53
|
-
include Mongoid::Document
|
54
|
-
include Mongoid::Denormalize
|
55
|
-
|
56
|
-
belongs_to :user
|
57
|
-
belongs_to :moderator, :class_name => "User", :inverse_of => :moderated_comments
|
58
|
-
|
59
|
-
field :body
|
60
|
-
|
61
|
-
denormalize :name, :email, :from => :user
|
62
|
-
end
|
63
|
-
|
64
|
-
>> user = User.create(:name => "John Doe", :email => "john@doe.com")
|
65
|
-
>> comment = Comment.create(:body => "Lorem ipsum...", :user => user)
|
66
|
-
>> user.comments << comment
|
67
|
-
>> comment.user_name
|
68
|
-
"John Doe"
|
69
|
-
>> comment.user_email
|
70
|
-
"john@doe.com"
|
71
|
-
>> user.update_attributes(:name => "Bill")
|
72
|
-
>> comment.user_name
|
73
|
-
"Bill"
|
74
|
-
|
75
|
-
|
76
|
-
Options
|
77
|
-
-------
|
78
|
-
|
79
|
-
Denormalization can happen in either or both directions. When using the `:from` option, the associated objects will fetch the values from
|
80
|
-
the parent. When using the `:to` option, the parent will push the values to its children.
|
81
|
-
|
82
|
-
# Basic denormalization. Will set the user_name attribute of "self.comments" to the value of "self.name".
|
83
|
-
denormalize :name, :to => :comments
|
84
|
-
|
85
|
-
# Multiple children. Will set the user_name attribute of "self.posts" and "self.comments" with "self.name".
|
86
|
-
denormalize :name, :to => [:posts, :comments]
|
87
|
-
|
88
|
-
# Basic denormalization, obeying :inverse_of. Will set the moderator_name attribute of "self.moderated_comments"
|
89
|
-
denormalize :name, :email, :to => :moderated_comments
|
90
|
-
|
91
|
-
# With custom field name prefix. Will set the commenter_name attribute of "self.comments" (takes precedence over
|
92
|
-
# inverse_of).
|
93
|
-
denormalize :name, :to => :comments, :as => :commenter
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
1
|
+
Mongoid::Denormalize
|
2
|
+
====================
|
3
|
+
|
4
|
+
*Note: I am no longer actively maintaining this module, and I do not know whether it is compatible with newer versions of mongoid. If you would like to take ownership of this repository, please let me know.*
|
5
|
+
|
6
|
+
|
7
|
+
Helper module for denormalizing association attributes in Mongoid models. Why denormalize? Read *[A Note on Denormalization](http://www.mongodb.org/display/DOCS/MongoDB+Data+Modeling+and+Rails#MongoDBDataModelingandRails-ANoteonDenormalization)*.
|
8
|
+
|
9
|
+
Extracted from [coookin'](http://coookin.com), where it is used in production.
|
10
|
+
|
11
|
+
|
12
|
+
Installation
|
13
|
+
------------
|
14
|
+
|
15
|
+
Add the gem to your Bundler `Gemfile`:
|
16
|
+
|
17
|
+
gem 'mongoid_denormalize'
|
18
|
+
|
19
|
+
Or install with RubyGems:
|
20
|
+
|
21
|
+
$ gem install mongoid_denormalize
|
22
|
+
|
23
|
+
|
24
|
+
Usage
|
25
|
+
-----
|
26
|
+
|
27
|
+
In your model:
|
28
|
+
|
29
|
+
# Include the helper method
|
30
|
+
include Mongoid::Denormalize
|
31
|
+
|
32
|
+
# Define your denormalized fields
|
33
|
+
denormalize :name, :email, :from => :user
|
34
|
+
|
35
|
+
|
36
|
+
Example
|
37
|
+
-------
|
38
|
+
|
39
|
+
class User
|
40
|
+
include Mongoid::Document
|
41
|
+
include Mongoid::Denormalize
|
42
|
+
|
43
|
+
has_many :comments
|
44
|
+
has_many :moderated_comments, :class_name => "Comment", :inverse_of => :moderator
|
45
|
+
|
46
|
+
field :name
|
47
|
+
field :email
|
48
|
+
|
49
|
+
denormalize :name, :email, :to => :comments
|
50
|
+
end
|
51
|
+
|
52
|
+
class Comment
|
53
|
+
include Mongoid::Document
|
54
|
+
include Mongoid::Denormalize
|
55
|
+
|
56
|
+
belongs_to :user
|
57
|
+
belongs_to :moderator, :class_name => "User", :inverse_of => :moderated_comments
|
58
|
+
|
59
|
+
field :body
|
60
|
+
|
61
|
+
denormalize :name, :email, :from => :user
|
62
|
+
end
|
63
|
+
|
64
|
+
>> user = User.create(:name => "John Doe", :email => "john@doe.com")
|
65
|
+
>> comment = Comment.create(:body => "Lorem ipsum...", :user => user)
|
66
|
+
>> user.comments << comment
|
67
|
+
>> comment.user_name
|
68
|
+
"John Doe"
|
69
|
+
>> comment.user_email
|
70
|
+
"john@doe.com"
|
71
|
+
>> user.update_attributes(:name => "Bill")
|
72
|
+
>> comment.user_name
|
73
|
+
"Bill"
|
74
|
+
|
75
|
+
|
76
|
+
Options
|
77
|
+
-------
|
78
|
+
|
79
|
+
Denormalization can happen in either or both directions. When using the `:from` option, the associated objects will fetch the values from
|
80
|
+
the parent. When using the `:to` option, the parent will push the values to its children.
|
81
|
+
|
82
|
+
# Basic denormalization. Will set the user_name attribute of "self.comments" to the value of "self.name".
|
83
|
+
denormalize :name, :to => :comments
|
84
|
+
|
85
|
+
# Multiple children. Will set the user_name attribute of "self.posts" and "self.comments" with "self.name".
|
86
|
+
denormalize :name, :to => [:posts, :comments]
|
87
|
+
|
88
|
+
# Basic denormalization, obeying :inverse_of. Will set the moderator_name attribute of "self.moderated_comments"
|
89
|
+
denormalize :name, :email, :to => :moderated_comments
|
90
|
+
|
91
|
+
# With custom field name prefix. Will set the commenter_name attribute of "self.comments" (takes precedence over
|
92
|
+
# inverse_of).
|
93
|
+
denormalize :name, :to => :comments, :as => :commenter
|
94
|
+
denormalize :name, :from => :comments, :as => :commenter
|
95
|
+
|
96
|
+
# Basic denormalization. Will set the user_name attribute with the associated user's name.
|
97
|
+
denormalize :name, :from => :user
|
98
|
+
|
99
|
+
# Multiple fields. Will set the user_name and user_email attributes with the associated user's name and email.
|
100
|
+
denormalize :name, :email, :from => :user
|
101
|
+
|
102
|
+
# Basic denormalization. Will set the moderator_name attribute with the associated author user's name.
|
103
|
+
denormalize :name, :from => :moderator
|
104
|
+
|
105
|
+
When using `:from`, if the type of the denormalized field is anything but `String` (the default),
|
106
|
+
you must specify the type with the `:type` option.
|
107
|
+
|
108
|
+
# in User
|
109
|
+
field :location, :type => Array
|
110
|
+
denormalize :location, :to => :posts
|
111
|
+
|
112
|
+
# in Post
|
113
|
+
denormalize :location, :type => Array, :from => :user
|
114
|
+
|
115
|
+
A few notes on behavior:
|
116
|
+
|
117
|
+
`:from` denormalizations are processed as `before_save` callbacks.
|
118
|
+
|
119
|
+
`:to` denormalizations are processed as `after_save` callbacks.
|
120
|
+
|
121
|
+
With `:to`, validations are not run on the object(s) containing the denormalized field(s) when they are saved.
|
122
|
+
|
123
|
+
Rake tasks
|
124
|
+
----------
|
125
|
+
|
126
|
+
A rake task is included for verifying and repairing inconsistent denormalizations. This might be useful your records may be modified
|
127
|
+
without Mongoid, or if you are using relational associations in combination with embedded records (see *Known issues*).
|
128
|
+
|
129
|
+
rake db:denormalize
|
130
|
+
|
131
|
+
This task will only update records that have outdated denormalized fields.
|
132
|
+
|
133
|
+
|
134
|
+
Known issues
|
135
|
+
------------
|
136
|
+
|
137
|
+
**Relational associations in combination with embedded records**
|
138
|
+
|
139
|
+
It is not recommended nor supported to use mongoid_denormalize to perform denormalization to embedded records through a relational association because
|
140
|
+
MongoDB/Mongoid do not support direct access to embedded fields via a relational association.
|
141
|
+
|
142
|
+
So, if User has_many :posts and User has_many :comments, but Comments are embedded_in :post, a user can't directly access a comment.
|
143
|
+
|
144
|
+
Contributing
|
145
|
+
-------
|
146
|
+
|
147
|
+
Clone the repository and run Bundler with `bundle install`. Use `rake -T` to view available rake tasks.
|
148
|
+
|
149
|
+
You can also use `bundle exec guard` for test driven development, if desired.
|
150
|
+
|
151
|
+
A MongoDB server is required to run the specs. Docker is an easy option:
|
152
|
+
|
153
|
+
docker run --name mongo3 -d -p 27017:27017 mongo
|
154
|
+
|
155
|
+
Contributors
|
156
|
+
-------
|
157
|
+
* hubsmoke (https://github.com/hubsmoke)
|
158
|
+
* Leo Lou (https://github.com/l4u)
|
159
|
+
* Austin Bales (https://github.com/arbales)
|
160
|
+
* Isaac Cambron (https://github.com/icambron)
|
161
|
+
* Shannon Carey (https://github.com/rehevkor5)
|
162
|
+
* Sebastien Azimi (https://github.com/suruja)
|
163
|
+
* HuffMoody (https://github.com/HuffMoody)
|
164
|
+
|
165
|
+
Credits
|
166
|
+
-------
|
167
|
+
|
168
|
+
Copyright (c) 2010 Logan Raarup, released under the MIT license.
|
data/lib/mongoid_denormalize.rb
CHANGED
@@ -1,120 +1,121 @@
|
|
1
|
-
require 'mongoid_denormalize/version'
|
2
|
-
require File.dirname(__FILE__) + '/railties/railtie' if defined?(Rails::Railtie)
|
3
|
-
|
4
|
-
# = Mongoid::Denormalize
|
5
|
-
#
|
6
|
-
# Helper module for denormalizing association attributes in Mongoid models.
|
7
|
-
module Mongoid::Denormalize
|
8
|
-
extend ActiveSupport::Concern
|
9
|
-
|
10
|
-
included do
|
11
|
-
cattr_accessor :denormalize_definitions
|
12
|
-
|
13
|
-
before_save :denormalize_from
|
14
|
-
after_save :denormalize_to
|
15
|
-
end
|
16
|
-
|
17
|
-
module ClassMethods
|
18
|
-
# Set a field or a number of fields to denormalize. Specify the associated object using the :from or :to options.
|
19
|
-
#
|
20
|
-
# def Post
|
21
|
-
# include Mongoid::Document
|
22
|
-
# include Mongoid::Denormalize
|
23
|
-
#
|
24
|
-
# referenced_in :user
|
25
|
-
# references_many :comments
|
26
|
-
#
|
27
|
-
# denormalize :name, :avatar, :from => :user
|
28
|
-
# denormalize :created_at, :to => :comments
|
29
|
-
# end
|
30
|
-
def denormalize(*args)
|
31
|
-
*fields, options = args
|
32
|
-
|
33
|
-
(self.denormalize_definitions ||= []) << { :fields => fields, :options => options }
|
34
|
-
|
35
|
-
# Define schema
|
36
|
-
unless options[:to]
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
associated.
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
end
|
1
|
+
require 'mongoid_denormalize/version'
|
2
|
+
require File.dirname(__FILE__) + '/railties/railtie' if defined?(Rails::Railtie)
|
3
|
+
|
4
|
+
# = Mongoid::Denormalize
|
5
|
+
#
|
6
|
+
# Helper module for denormalizing association attributes in Mongoid models.
|
7
|
+
module Mongoid::Denormalize
|
8
|
+
extend ActiveSupport::Concern
|
9
|
+
|
10
|
+
included do
|
11
|
+
cattr_accessor :denormalize_definitions
|
12
|
+
|
13
|
+
before_save :denormalize_from
|
14
|
+
after_save :denormalize_to
|
15
|
+
end
|
16
|
+
|
17
|
+
module ClassMethods
|
18
|
+
# Set a field or a number of fields to denormalize. Specify the associated object using the :from or :to options.
|
19
|
+
#
|
20
|
+
# def Post
|
21
|
+
# include Mongoid::Document
|
22
|
+
# include Mongoid::Denormalize
|
23
|
+
#
|
24
|
+
# referenced_in :user
|
25
|
+
# references_many :comments
|
26
|
+
#
|
27
|
+
# denormalize :name, :avatar, :from => :user
|
28
|
+
# denormalize :created_at, :to => :comments
|
29
|
+
# end
|
30
|
+
def denormalize(*args)
|
31
|
+
*fields, options = args
|
32
|
+
|
33
|
+
(self.denormalize_definitions ||= []) << { :fields => fields, :options => options }
|
34
|
+
|
35
|
+
# Define schema
|
36
|
+
unless options[:to]
|
37
|
+
prefix = options[:as] || options[:from]
|
38
|
+
fields.each do |name|
|
39
|
+
field "#{prefix}_#{name}", :type => options[:type] || String
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def is_denormalized?
|
45
|
+
true
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def denormalized_valid?
|
50
|
+
denormalize_from
|
51
|
+
!self.changed?
|
52
|
+
end
|
53
|
+
|
54
|
+
def repair_denormalized!
|
55
|
+
self.save! unless denormalized_valid?
|
56
|
+
end
|
57
|
+
|
58
|
+
private
|
59
|
+
def denormalize_from
|
60
|
+
Array(self.denormalize_definitions).reject do |definition|
|
61
|
+
definition[:options][:to]
|
62
|
+
end.each do |definition|
|
63
|
+
definition[:fields].each do |field|
|
64
|
+
association = definition[:options][:from]
|
65
|
+
prefix = definition[:options][:as] || definition[:options][:from]
|
66
|
+
# force reload if :from method is an association ; call it normally otherwise
|
67
|
+
associated = self.class.reflect_on_association(association) ? self.send(association, true) : self.send(association)
|
68
|
+
self.send("#{prefix}_#{field}=", associated.try(field))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def denormalize_to
|
74
|
+
Array(self.denormalize_definitions).find_all do |definition|
|
75
|
+
definition[:options][:to]
|
76
|
+
end.each do |definition|
|
77
|
+
as = definition[:options][:as]
|
78
|
+
|
79
|
+
assignments = definition[:fields].collect do |source_field|
|
80
|
+
{
|
81
|
+
:source_field => source_field.to_s,
|
82
|
+
:value => self.send(source_field)
|
83
|
+
}
|
84
|
+
end
|
85
|
+
|
86
|
+
Array(definition[:options][:to]).each do |association|
|
87
|
+
relation = []
|
88
|
+
reflect = self.class.reflect_on_association(association)
|
89
|
+
relation = reflect.relation.macro unless reflect.nil? || reflect.relation.nil?
|
90
|
+
|
91
|
+
reflect.klass.skip_callback(:save, :before, :denormalize_from) if reflect.klass.try(:is_denormalized?)
|
92
|
+
|
93
|
+
associated = self.send(association)
|
94
|
+
prefix = (as || reflect.inverse_of || reflect.inverse_class_name).to_s.underscore
|
95
|
+
|
96
|
+
if [:embedded_in, :embeds_one, :referenced_in, :references_one, :has_one, :belongs_to].include? relation
|
97
|
+
unless associated.blank?
|
98
|
+
assign_and_save(associated, assignments, prefix)
|
99
|
+
end
|
100
|
+
else
|
101
|
+
associated.to_a.each { |c| assign_and_save(c, assignments, prefix) }
|
102
|
+
end
|
103
|
+
|
104
|
+
reflect.klass.set_callback(:save, :before, :denormalize_from) if reflect.klass.try(:is_denormalized?)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def assign_and_save(obj, assignments, prefix)
|
110
|
+
attributes_hash = Hash[assignments.collect { |assignment|
|
111
|
+
if self.changed_attributes.has_key?(assignment[:source_field].to_s) ||
|
112
|
+
self.changed_attributes.has_key?(assignment[:source_field].to_sym)
|
113
|
+
["#{prefix}_#{assignment[:source_field]}", assignment[:value]]
|
114
|
+
end
|
115
|
+
}.compact]
|
116
|
+
|
117
|
+
unless attributes_hash.empty?
|
118
|
+
obj.update_attributes(attributes_hash)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
module Mongoid
|
2
|
-
module Denormalize
|
3
|
-
VERSION = '0.
|
4
|
-
end
|
5
|
-
end
|
1
|
+
module Mongoid
|
2
|
+
module Denormalize
|
3
|
+
VERSION = '1.0.0'
|
4
|
+
end
|
5
|
+
end
|
@@ -1,39 +1,39 @@
|
|
1
|
-
namespace :db do
|
2
|
-
desc "Verify all denormalizations and repair any inconsistencies"
|
3
|
-
task :denormalize => :environment do
|
4
|
-
get_denormalizable_models.each do |klass|
|
5
|
-
if klass.embedded?
|
6
|
-
reflection = klass.reflect_on_all_associations(:embedded_in).first
|
7
|
-
parent = reflection.class_name.to_s.classify.constantize
|
8
|
-
|
9
|
-
unless parent.embedded?
|
10
|
-
parent.all.each do |parent_instance|
|
11
|
-
parent_instance.send(reflection.inverse).each(&:repair_denormalized!)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
else
|
15
|
-
klass.all.each do |instance|
|
16
|
-
instance.repair_denormalized!
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def get_denormalizable_models
|
23
|
-
documents = []
|
24
|
-
Dir.glob("app/models/**/*.rb").sort.each do |file|
|
25
|
-
model_path = file[0..-4].split('/')[2..-1]
|
26
|
-
begin
|
27
|
-
klass = model_path.map(&:classify).join('::').constantize
|
28
|
-
|
29
|
-
if klass.ancestors.include?(Mongoid::Document) && klass.ancestors.include?(Mongoid::Denormalize)
|
30
|
-
documents << klass
|
31
|
-
end
|
32
|
-
rescue => e
|
33
|
-
# Just for non-mongoid objects that dont have the embedded
|
34
|
-
# attribute at the class level.
|
35
|
-
end
|
36
|
-
end
|
37
|
-
documents
|
38
|
-
end
|
1
|
+
namespace :db do
|
2
|
+
desc "Verify all denormalizations and repair any inconsistencies"
|
3
|
+
task :denormalize => :environment do
|
4
|
+
get_denormalizable_models.each do |klass|
|
5
|
+
if klass.embedded?
|
6
|
+
reflection = klass.reflect_on_all_associations(:embedded_in).first
|
7
|
+
parent = reflection.class_name.to_s.classify.constantize
|
8
|
+
|
9
|
+
unless parent.embedded?
|
10
|
+
parent.all.each do |parent_instance|
|
11
|
+
parent_instance.send(reflection.inverse).each(&:repair_denormalized!)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
else
|
15
|
+
klass.all.each do |instance|
|
16
|
+
instance.repair_denormalized!
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_denormalizable_models
|
23
|
+
documents = []
|
24
|
+
Dir.glob("app/models/**/*.rb").sort.each do |file|
|
25
|
+
model_path = file[0..-4].split('/')[2..-1]
|
26
|
+
begin
|
27
|
+
klass = model_path.map(&:classify).join('::').constantize
|
28
|
+
|
29
|
+
if klass.ancestors.include?(Mongoid::Document) && klass.ancestors.include?(Mongoid::Denormalize)
|
30
|
+
documents << klass
|
31
|
+
end
|
32
|
+
rescue => e
|
33
|
+
# Just for non-mongoid objects that dont have the embedded
|
34
|
+
# attribute at the class level.
|
35
|
+
end
|
36
|
+
end
|
37
|
+
documents
|
38
|
+
end
|
39
39
|
end
|
data/lib/railties/railtie.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
-
require 'rails'
|
2
|
-
|
3
|
-
module Mongoid::Denormalize
|
4
|
-
class Railtie < Rails::Railtie
|
5
|
-
rake_tasks do
|
6
|
-
load 'railties/denormalize.rake'
|
7
|
-
end
|
8
|
-
end
|
1
|
+
require 'rails'
|
2
|
+
|
3
|
+
module Mongoid::Denormalize
|
4
|
+
class Railtie < Rails::Railtie
|
5
|
+
rake_tasks do
|
6
|
+
load 'railties/denormalize.rake'
|
7
|
+
end
|
8
|
+
end
|
9
9
|
end
|
@@ -1,150 +1,146 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
describe Mongoid::Denormalize do
|
4
|
-
before(:each) do
|
5
|
-
@post = Post.create!(:title => "Blog post", :body => "Lorem ipsum...", :created_at => Time.parse("Jan 1 2010 12:00"))
|
6
|
-
@user = User.create!(:name => "John Doe", :email => "john@doe.com", :post => @post, :location => [1, 1], :nickname => "jdoe")
|
7
|
-
@comment = @post.comments.create(:body => "This is the comment", :user => @user)
|
8
|
-
@post.reload #neccessary for older versions of Mongoid
|
9
|
-
@moderated_comment = @post.comments.create(:body => "This is a moderated comment", :moderator => @user)
|
10
|
-
@article = @user.articles.create!(:title => "Article about Lorem", :body => "Lorem ipsum...", :created_at => Time.parse("Jan 1 2010 12:00"))
|
11
|
-
|
12
|
-
@user.comments << @comment
|
13
|
-
@user.moderated_comments << @moderated_comment
|
14
|
-
@user.save
|
15
|
-
@user.reload
|
16
|
-
@other_user = User.create!(:name => "Bill")
|
17
|
-
end
|
18
|
-
|
19
|
-
context "denormalize from" do
|
20
|
-
it "should define multiple fields for association" do
|
21
|
-
@post.fields.should have_key "user_name"
|
22
|
-
@post.fields.should have_key "user_email"
|
23
|
-
@post.fields.should have_key "user_location"
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should default to string field type for associated fields" do
|
27
|
-
@post.fields["user_name"].type.should eql String
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should allow setting the field type for associated fields" do
|
31
|
-
@comment.fields["post_created_at"].type.should eql Time
|
32
|
-
end
|
33
|
-
|
34
|
-
it "should allow multiple declarations for the same association" do
|
35
|
-
@comment.fields.should have_key "user_name"
|
36
|
-
@comment.fields.should have_key "user_email"
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should denormalize fields without specified type" do
|
40
|
-
@comment.user_name.should eql @user.name
|
41
|
-
@comment.user_email.should eql @user.email
|
42
|
-
@post.user_name.should eql @user.name
|
43
|
-
@post.user_email.should eql @user.email
|
44
|
-
end
|
45
|
-
|
46
|
-
it "should denormalize fields with specified type" do
|
47
|
-
@comment.post_created_at.should eql @post.created_at
|
48
|
-
|
49
|
-
@post.user_location.should eql @user.location
|
50
|
-
end
|
51
|
-
|
52
|
-
it "should use fresh values from database where possible" do
|
53
|
-
@other_post = Post.create!(:title => "My first blog post")
|
54
|
-
@other_post.update_attribute(:user_id, @user.id)
|
55
|
-
@other_post.user_name.should eql @user.name
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should update denormalized values if attribute is changed" do
|
59
|
-
@user.update_attributes(:name => "Bob Doe", :location => [4, 4])
|
60
|
-
|
61
|
-
@post.reload #needed for old versions of Mongoid
|
62
|
-
@post.user_location.should eql @user.location
|
63
|
-
|
64
|
-
@comment.reload #needed for old versions of Mongoid
|
65
|
-
@comment.user_name.should eql @user.name
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should update denormalized values if object is changed" do
|
69
|
-
@other_user = User.create!(:name => "Bill", :email => "bill@doe.com")
|
70
|
-
|
71
|
-
@comment.user = @other_user
|
72
|
-
@comment.save!
|
73
|
-
|
74
|
-
@comment.user_name.should eql @other_user.name
|
75
|
-
@comment.user_email.should eql @other_user.email
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
context "denormalize to" do
|
80
|
-
it "should push denormalized fields to one-to-one association" do
|
81
|
-
@user.name = "Elvis"
|
82
|
-
@user.save!
|
83
|
-
|
84
|
-
@post.reload #needed for old versions of Mongoid
|
85
|
-
@post.user_name.should eql "Elvis"
|
86
|
-
end
|
87
|
-
|
88
|
-
it "should push denormalized fields to one-to-many association" do
|
89
|
-
@post.created_at = Time.parse("Jan 1 2011 12:00")
|
90
|
-
@post.save!
|
91
|
-
|
92
|
-
@comment.reload #needed for old versions of Mongoid
|
93
|
-
@comment.post_created_at.should eql Time.parse("Jan 1 2011 12:00")
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should push denormalized fields to association using inverse_of class name" do
|
97
|
-
@user.update_attributes(:name => "Bob Doe", :email => "bob@doe.com")
|
98
|
-
@user.save!
|
99
|
-
|
100
|
-
@article.reload #needed for old versions of Mongoid
|
101
|
-
@article.author_name.should eql "Bob Doe"
|
102
|
-
@article.author_email.should eql "bob@doe.com"
|
103
|
-
end
|
104
|
-
|
105
|
-
it "should push to overriden field names" do
|
106
|
-
@user.nickname = "jonsey"
|
107
|
-
@user.save!
|
108
|
-
|
109
|
-
@moderated_comment.reload
|
110
|
-
@moderated_comment.mod_nickname.should eql "jonsey"
|
111
|
-
end
|
112
|
-
|
113
|
-
it "shouldn't make superfluous saves" do
|
114
|
-
@comment.should_not_receive(:save)
|
115
|
-
@post.save!
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
context "rake task" do
|
120
|
-
it "should correct inconsistent denormalizations on regular documents" do
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
@
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
@post.reload
|
147
|
-
@post.comments.last.user_name.should eql @rake_user.name
|
148
|
-
end
|
149
|
-
end
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Mongoid::Denormalize do
|
4
|
+
before(:each) do
|
5
|
+
@post = Post.create!(:title => "Blog post", :body => "Lorem ipsum...", :created_at => Time.parse("Jan 1 2010 12:00"))
|
6
|
+
@user = User.create!(:name => "John Doe", :email => "john@doe.com", :post => @post, :location => [1, 1], :nickname => "jdoe")
|
7
|
+
@comment = @post.comments.create(:body => "This is the comment", :user => @user)
|
8
|
+
@post.reload #neccessary for older versions of Mongoid
|
9
|
+
@moderated_comment = @post.comments.create(:body => "This is a moderated comment", :moderator => @user)
|
10
|
+
@article = @user.articles.create!(:title => "Article about Lorem", :body => "Lorem ipsum...", :created_at => Time.parse("Jan 1 2010 12:00"))
|
11
|
+
|
12
|
+
@user.comments << @comment
|
13
|
+
@user.moderated_comments << @moderated_comment
|
14
|
+
@user.save
|
15
|
+
@user.reload
|
16
|
+
@other_user = User.create!(:name => "Bill")
|
17
|
+
end
|
18
|
+
|
19
|
+
context "denormalize from" do
|
20
|
+
it "should define multiple fields for association" do
|
21
|
+
@post.fields.should have_key "user_name"
|
22
|
+
@post.fields.should have_key "user_email"
|
23
|
+
@post.fields.should have_key "user_location"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should default to string field type for associated fields" do
|
27
|
+
@post.fields["user_name"].type.should eql String
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should allow setting the field type for associated fields" do
|
31
|
+
@comment.fields["post_created_at"].type.should eql Time
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should allow multiple declarations for the same association" do
|
35
|
+
@comment.fields.should have_key "user_name"
|
36
|
+
@comment.fields.should have_key "user_email"
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should denormalize fields without specified type" do
|
40
|
+
@comment.user_name.should eql @user.name
|
41
|
+
@comment.user_email.should eql @user.email
|
42
|
+
@post.user_name.should eql @user.name
|
43
|
+
@post.user_email.should eql @user.email
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should denormalize fields with specified type" do
|
47
|
+
@comment.post_created_at.should eql @post.created_at
|
48
|
+
|
49
|
+
@post.user_location.should eql @user.location
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should use fresh values from database where possible" do
|
53
|
+
@other_post = Post.create!(:title => "My first blog post")
|
54
|
+
@other_post.update_attribute(:user_id, @user.id)
|
55
|
+
@other_post.user_name.should eql @user.name
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should update denormalized values if attribute is changed" do
|
59
|
+
@user.update_attributes(:name => "Bob Doe", :location => [4, 4])
|
60
|
+
|
61
|
+
@post.reload #needed for old versions of Mongoid
|
62
|
+
@post.user_location.should eql @user.location
|
63
|
+
|
64
|
+
@comment.reload #needed for old versions of Mongoid
|
65
|
+
@comment.user_name.should eql @user.name
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should update denormalized values if object is changed" do
|
69
|
+
@other_user = User.create!(:name => "Bill", :email => "bill@doe.com")
|
70
|
+
|
71
|
+
@comment.user = @other_user
|
72
|
+
@comment.save!
|
73
|
+
|
74
|
+
@comment.user_name.should eql @other_user.name
|
75
|
+
@comment.user_email.should eql @other_user.email
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context "denormalize to" do
|
80
|
+
it "should push denormalized fields to one-to-one association" do
|
81
|
+
@user.name = "Elvis"
|
82
|
+
@user.save!
|
83
|
+
|
84
|
+
@post.reload #needed for old versions of Mongoid
|
85
|
+
@post.user_name.should eql "Elvis"
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should push denormalized fields to one-to-many association" do
|
89
|
+
@post.created_at = Time.parse("Jan 1 2011 12:00")
|
90
|
+
@post.save!
|
91
|
+
|
92
|
+
@comment.reload #needed for old versions of Mongoid
|
93
|
+
@comment.post_created_at.should eql Time.parse("Jan 1 2011 12:00")
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should push denormalized fields to association using inverse_of class name" do
|
97
|
+
@user.update_attributes(:name => "Bob Doe", :email => "bob@doe.com")
|
98
|
+
@user.save!
|
99
|
+
|
100
|
+
@article.reload #needed for old versions of Mongoid
|
101
|
+
@article.author_name.should eql "Bob Doe"
|
102
|
+
@article.author_email.should eql "bob@doe.com"
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should push to overriden field names" do
|
106
|
+
@user.nickname = "jonsey"
|
107
|
+
@user.save!
|
108
|
+
|
109
|
+
@moderated_comment.reload
|
110
|
+
@moderated_comment.mod_nickname.should eql "jonsey"
|
111
|
+
end
|
112
|
+
|
113
|
+
it "shouldn't make superfluous saves" do
|
114
|
+
@comment.should_not_receive(:save)
|
115
|
+
@post.save!
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
context "rake task" do
|
120
|
+
it "should correct inconsistent denormalizations on regular documents" do
|
121
|
+
@post.set(:user_name => 'Clint Eastwood')
|
122
|
+
|
123
|
+
@post.reload #needed for old versions of Mongoid
|
124
|
+
@post.user_name.should eq 'Clint Eastwood'
|
125
|
+
|
126
|
+
Rake::Task["db:denormalize"].invoke
|
127
|
+
Rake::Task["db:denormalize"].reenable
|
128
|
+
|
129
|
+
@post.reload
|
130
|
+
@post.user_name.should eql @user.name
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should correct inconsistent denormalizations on referenced embedded documents" do
|
134
|
+
@rake_user = User.create!(:name => "Johnny Depp", :email => "johnny@depp.com")
|
135
|
+
@rake_comment = @post.comments.create!(:body => "Depp's comment", :user => @rake_user)
|
136
|
+
|
137
|
+
@rake_user.update_attributes!(:name => "J. Depp")
|
138
|
+
|
139
|
+
Rake::Task["db:denormalize"].invoke
|
140
|
+
Rake::Task["db:denormalize"].reenable
|
141
|
+
|
142
|
+
@post.reload
|
143
|
+
@post.comments.last.user_name.should eql @rake_user.name
|
144
|
+
end
|
145
|
+
end
|
150
146
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoid_denormalize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 1.0.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Logan Raarup
|
@@ -14,51 +13,45 @@ dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: rake
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - ">="
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '0'
|
22
20
|
type: :development
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: guard-rspec
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - ">="
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: '0'
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - ">="
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: '0'
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: mongoid
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
|
-
- -
|
45
|
+
- - ">="
|
52
46
|
- !ruby/object:Gem::Version
|
53
|
-
version:
|
47
|
+
version: 4.0.0
|
54
48
|
type: :runtime
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
|
-
- -
|
52
|
+
- - ">="
|
60
53
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
54
|
+
version: 4.0.0
|
62
55
|
description: Helper module for denormalizing association attributes in Mongoid models.
|
63
56
|
email: logan@logan.dk
|
64
57
|
executables: []
|
@@ -67,37 +60,33 @@ extra_rdoc_files:
|
|
67
60
|
- LICENSE
|
68
61
|
- README.md
|
69
62
|
files:
|
63
|
+
- LICENSE
|
64
|
+
- README.md
|
70
65
|
- lib/mongoid_denormalize.rb
|
71
66
|
- lib/mongoid_denormalize/version.rb
|
72
67
|
- lib/railties/denormalize.rake
|
73
68
|
- lib/railties/railtie.rb
|
74
|
-
- LICENSE
|
75
|
-
- README.md
|
76
69
|
- spec/mongoid_denormalize_spec.rb
|
77
70
|
homepage: http://github.com/logandk/mongoid_denormalize
|
78
71
|
licenses: []
|
72
|
+
metadata: {}
|
79
73
|
post_install_message:
|
80
74
|
rdoc_options: []
|
81
75
|
require_paths:
|
82
76
|
- lib
|
83
77
|
required_ruby_version: !ruby/object:Gem::Requirement
|
84
|
-
none: false
|
85
78
|
requirements:
|
86
|
-
- -
|
79
|
+
- - ">="
|
87
80
|
- !ruby/object:Gem::Version
|
88
81
|
version: '0'
|
89
|
-
segments:
|
90
|
-
- 0
|
91
|
-
hash: -889189390443941496
|
92
82
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
-
none: false
|
94
83
|
requirements:
|
95
|
-
- -
|
84
|
+
- - ">="
|
96
85
|
- !ruby/object:Gem::Version
|
97
86
|
version: '0'
|
98
87
|
requirements: []
|
99
88
|
rubyforge_project:
|
100
|
-
rubygems_version:
|
89
|
+
rubygems_version: 2.4.5
|
101
90
|
signing_key:
|
102
91
|
specification_version: 3
|
103
92
|
summary: Mongoid denormalization helper.
|