mongoblazer 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +1 -0
- data/Rakefile +4 -0
- data/lib/mongoblazer.rb +7 -1
- data/lib/mongoblazer/active_record.rb +431 -0
- data/lib/mongoblazer/active_record/carrierwave.rb +47 -0
- data/lib/mongoblazer/document.rb +34 -0
- data/lib/mongoblazer/railtie.rb +27 -0
- data/lib/mongoblazer/version.rb +1 -1
- data/mongoblazer.gemspec +4 -0
- data/spec/mongoblazer/active_record_spec.rb +92 -0
- data/spec/spec_helper.rb +14 -0
- data/spec/support/ar.rb +121 -0
- data/spec/support/database_cleaner.rb +20 -0
- data/spec/support/mongoid.rb +1 -0
- data/spec/support/mongoid.yml +6 -0
- metadata +83 -3
data/.gitignore
CHANGED
data/Rakefile
CHANGED
data/lib/mongoblazer.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
|
+
require "rails"
|
2
|
+
require "mongoid"
|
3
|
+
require "active_record"
|
1
4
|
require "mongoblazer/version"
|
5
|
+
require "mongoblazer/active_record/carrierwave"
|
6
|
+
require "mongoblazer/active_record"
|
7
|
+
require "mongoblazer/document"
|
8
|
+
require "mongoblazer/railtie"
|
2
9
|
|
3
10
|
module Mongoblazer
|
4
|
-
# Your code goes here...
|
5
11
|
end
|
@@ -0,0 +1,431 @@
|
|
1
|
+
module Mongoblazer
|
2
|
+
##
|
3
|
+
# Mongoblazer's ActiveRecord extension.
|
4
|
+
#
|
5
|
+
module ActiveRecord
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
include Carrierwave
|
8
|
+
|
9
|
+
included do
|
10
|
+
def mongoblazed
|
11
|
+
@mongoblazed ||= begin
|
12
|
+
self.class.recreate_mongoblazer_class!
|
13
|
+
self.class.mongoblazer_class.where(id: self.mongoblazer_id).last
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def mongoblazed_add_attribute(name, data={})
|
18
|
+
self.class.recreate_mongoblazer_class!
|
19
|
+
instance = self.class.mongoblazer_class.where(id: self.mongoblazer_id).last
|
20
|
+
instance[name] = data
|
21
|
+
instance.save!
|
22
|
+
@mongoblazed = instance
|
23
|
+
end
|
24
|
+
|
25
|
+
##
|
26
|
+
# Add a relation that is not in the includes options
|
27
|
+
#
|
28
|
+
# Example:
|
29
|
+
# post.mongoblazed.add_include(:comments, post.comments.map(&:attributes))
|
30
|
+
#
|
31
|
+
# Returns the mongoblazed instance with the new include.
|
32
|
+
def mongoblazed_add_include(name, data={})
|
33
|
+
self.class.recreate_mongoblazer_class!
|
34
|
+
relations = {name => data}
|
35
|
+
mongoblaze_relations(mongoblazed, relations)
|
36
|
+
mongoblazed.save!
|
37
|
+
mongoblazed
|
38
|
+
end
|
39
|
+
|
40
|
+
def mongoblaze!(caller=self.class)
|
41
|
+
if @mongoblazer_already_blazing
|
42
|
+
@mongoblazer_already_blazing = false
|
43
|
+
return true
|
44
|
+
end
|
45
|
+
|
46
|
+
self.class.recreate_mongoblazer_class!
|
47
|
+
|
48
|
+
data = mongoblazer_attributes
|
49
|
+
relations = {}
|
50
|
+
|
51
|
+
self.class.mongoblazer_options[:embeds_one].each do |em, class_name|
|
52
|
+
if related = data.delete(em)
|
53
|
+
klass = class_name ? class_name.constantize : "#{em.to_s.camelize}".constantize
|
54
|
+
if klass != caller
|
55
|
+
related_id = related['id'] || data["#{em}_id"]
|
56
|
+
if klass.mongoblazable? && related_id
|
57
|
+
klass.recreate_mongoblazer_class!
|
58
|
+
relations[em] = klass.find(related_id).mongoblazer_attributes(self.class)
|
59
|
+
else
|
60
|
+
data[em] = related.attributes
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
self.class.mongoblazer_options[:embeds_many].each do |em, class_name|
|
67
|
+
if related = data.delete(em)
|
68
|
+
klass = class_name ? class_name.constantize : "#{em.to_s.singularize.camelize}".constantize
|
69
|
+
if klass != caller
|
70
|
+
if klass.mongoblazable?
|
71
|
+
klass.recreate_mongoblazer_class!
|
72
|
+
relations[em] = related.map do |r|
|
73
|
+
related_id = r['id'] || data["#{em.to_s.singularize}_id"]
|
74
|
+
if related_id
|
75
|
+
klass.find(related_id).mongoblazer_attributes(self.class)
|
76
|
+
else
|
77
|
+
r.attributes
|
78
|
+
end
|
79
|
+
end
|
80
|
+
else
|
81
|
+
data[em] = related.map(&:attributes)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
self.class.recreate_mongoblazer_class!
|
88
|
+
|
89
|
+
blazed_record = if self.mongoblazer_id.present?
|
90
|
+
self.class.mongoblazer_class
|
91
|
+
.where(id: self.mongoblazer_id).first
|
92
|
+
else
|
93
|
+
nil
|
94
|
+
end
|
95
|
+
|
96
|
+
if blazed_record.present?
|
97
|
+
blazed_record.save!(data)
|
98
|
+
else
|
99
|
+
blazed_record = self.class.mongoblazer_class.create(data)
|
100
|
+
@mongoblazer_already_blazing = true
|
101
|
+
update_attribute :mongoblazer_id, blazed_record.id.to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
mongoblaze_relations(blazed_record, relations)
|
105
|
+
|
106
|
+
blazed_record.save!
|
107
|
+
|
108
|
+
blazed_record
|
109
|
+
end
|
110
|
+
|
111
|
+
def mongoblaze_relations(blazed_record, relations)
|
112
|
+
if relations.present?
|
113
|
+
self.class.recreate_mongoblazer_class!
|
114
|
+
|
115
|
+
relations.each do |name, related|
|
116
|
+
next if self.class.mongoblazer_options[:uploaders].include? name
|
117
|
+
|
118
|
+
if related.is_a? Array
|
119
|
+
blazed_record.send(name).destroy_all
|
120
|
+
|
121
|
+
related.each do |r|
|
122
|
+
blazed_record.send(name).build(r)
|
123
|
+
end
|
124
|
+
|
125
|
+
else
|
126
|
+
blazed_record.send("build_#{name}", related)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def mongoblazer_attributes(caller=self.class)
|
133
|
+
if self.class.mongoblazable?
|
134
|
+
self.class.recreate_mongoblazer_class!
|
135
|
+
|
136
|
+
includes = self.class.mongoblazer_options[:includes]
|
137
|
+
|
138
|
+
instance = self.class.includes(includes).find(id)
|
139
|
+
data = if includes
|
140
|
+
instance.serializable_hash(:include => includes)
|
141
|
+
else
|
142
|
+
instance.attributes
|
143
|
+
end
|
144
|
+
|
145
|
+
if additional = self.class.mongoblazer_options[:additional_attributes]
|
146
|
+
additional.each do |attribute|
|
147
|
+
next if self.class.mongoblazer_options[:uploaders].include? attribute
|
148
|
+
|
149
|
+
data[attribute] = instance.send(attribute)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
if uploaders = self.class.mongoblazer_options[:uploaders]
|
154
|
+
uploaders.each do |uploader|
|
155
|
+
data.delete(uploader)
|
156
|
+
data.delete(uploader.to_s)
|
157
|
+
if instance.send(uploader).present?
|
158
|
+
versions = {}
|
159
|
+
instance.send(uploader).versions.each do |v,u|
|
160
|
+
versions[v] = u.to_s
|
161
|
+
end
|
162
|
+
versions.merge({default: instance.send(uploader).to_s})
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
data[:ar_id] = data.delete('id')
|
168
|
+
|
169
|
+
data.delete(caller.name.underscore.to_sym)
|
170
|
+
data.delete(caller.name.pluralize.underscore.to_sym)
|
171
|
+
|
172
|
+
self.class.recreate_mongoblazer_class!
|
173
|
+
|
174
|
+
data
|
175
|
+
else
|
176
|
+
throw "#{self.class.name} is not Mongoblazable!"
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
private
|
181
|
+
|
182
|
+
# Add associations specified via the <tt>:include</tt> option.
|
183
|
+
#
|
184
|
+
# Expects a block that takes as arguments:
|
185
|
+
# +association+ - name of the association
|
186
|
+
# +records+ - the association record(s) to be serialized
|
187
|
+
# +opts+ - options for the association records
|
188
|
+
def serializable_add_includes(options = {}) #:nodoc:
|
189
|
+
return unless include = options[:include]
|
190
|
+
|
191
|
+
unless include.is_a?(Hash)
|
192
|
+
include = Hash[Array.wrap(include).map { |n| n.is_a?(Hash) ? n.to_a.first : [n, {}] }]
|
193
|
+
end
|
194
|
+
|
195
|
+
include.each do |association, opts|
|
196
|
+
# TODO: This is broken in Rails 3.2.13 it seems, hence this fix.
|
197
|
+
opts = {:include => opts} if opts.is_a? Array
|
198
|
+
|
199
|
+
if records = send(association)
|
200
|
+
yield association, records, opts
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
module ClassMethods
|
207
|
+
def find_blazed(id)
|
208
|
+
ar_instance = select("#{self.table_name}.mongoblazer_id").find(id)
|
209
|
+
|
210
|
+
recreate_mongoblazer_class!
|
211
|
+
|
212
|
+
mongoblazer_class.find(ar_instance.mongoblazer_id)
|
213
|
+
end
|
214
|
+
|
215
|
+
##
|
216
|
+
# Is this model Mongoblazable?
|
217
|
+
#
|
218
|
+
def mongoblazable?
|
219
|
+
mongoblazer_options.present?
|
220
|
+
end
|
221
|
+
|
222
|
+
def belongs_to(name, options={})
|
223
|
+
mongoblazer_init embeds_one: {name => options[:class_name]}
|
224
|
+
super
|
225
|
+
end
|
226
|
+
|
227
|
+
def has_one(name, options={})
|
228
|
+
mongoblazer_init embeds_one: {name => options[:class_name]}
|
229
|
+
super
|
230
|
+
end
|
231
|
+
|
232
|
+
def has_many(name, options={})
|
233
|
+
mongoblazer_init embeds_many: {name => options[:class_name]}
|
234
|
+
super
|
235
|
+
end
|
236
|
+
|
237
|
+
def has_and_belongs_to_many(name, options={})
|
238
|
+
mongoblazer_init embeds_many: {name => options[:class_name]}
|
239
|
+
super
|
240
|
+
end
|
241
|
+
|
242
|
+
##
|
243
|
+
# Defines relation includes to be merged
|
244
|
+
# in the mongodb document.
|
245
|
+
#
|
246
|
+
# Syntax same as eager loading syntax in AR:
|
247
|
+
# http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations
|
248
|
+
#
|
249
|
+
def mongoblazer_includes(options={})
|
250
|
+
mongoblazer_init includes: options
|
251
|
+
end
|
252
|
+
|
253
|
+
##
|
254
|
+
# Defines default scope to find the matching mongodb
|
255
|
+
# document.
|
256
|
+
#
|
257
|
+
# Syntax same as where() in AR
|
258
|
+
#
|
259
|
+
def mongoblazer_default_scope(options={})
|
260
|
+
mongoblazer_init default_scope: options
|
261
|
+
end
|
262
|
+
|
263
|
+
##
|
264
|
+
# Defines indexes on the blazer model.
|
265
|
+
#
|
266
|
+
def mongoblazer_index_fields(options={})
|
267
|
+
mongoblazer_init indexes: options
|
268
|
+
end
|
269
|
+
|
270
|
+
##
|
271
|
+
# Defines additional attributes (e.g. not in db) to be merged
|
272
|
+
# in the mongodb document.
|
273
|
+
#
|
274
|
+
def mongoblazer_additional_attributes(options={})
|
275
|
+
mongoblazer_init additional_attributes: options
|
276
|
+
end
|
277
|
+
|
278
|
+
##
|
279
|
+
# Initialize Mongoblazer wit some options:
|
280
|
+
# includes: relations to include
|
281
|
+
# default_scope: the default scope for the blazed model
|
282
|
+
# indexes: fields to index in the blazed model
|
283
|
+
# embeds_one: model to embed one of
|
284
|
+
# embeds_many: model to embed many of
|
285
|
+
#
|
286
|
+
def mongoblazer_init(options)
|
287
|
+
unless @mongoblazer_options
|
288
|
+
@mongoblazer_options = {}
|
289
|
+
|
290
|
+
@mongoblazer_options[:indexes] =
|
291
|
+
::ActiveRecord::Base.connection.indexes(self.table_name).map do |ind|
|
292
|
+
{ind => 1}
|
293
|
+
end
|
294
|
+
|
295
|
+
@mongoblazer_options[:uploaders] = []
|
296
|
+
|
297
|
+
@mongoblazer_options[:embeds_one] = {}
|
298
|
+
@mongoblazer_options[:embeds_many] = {}
|
299
|
+
end
|
300
|
+
|
301
|
+
if one = options.delete(:embeds_one)
|
302
|
+
@mongoblazer_options[:embeds_one][one.keys.first] = one.values.first
|
303
|
+
end
|
304
|
+
|
305
|
+
if many = options.delete(:embeds_many)
|
306
|
+
@mongoblazer_options[:embeds_many][many.keys.first] = many.values.first
|
307
|
+
end
|
308
|
+
|
309
|
+
if uploader = options.delete(:uploaders)
|
310
|
+
@mongoblazer_options[:uploaders] << uploader
|
311
|
+
end
|
312
|
+
|
313
|
+
@mongoblazer_options.merge! options
|
314
|
+
|
315
|
+
create_mongoblazer_class!
|
316
|
+
end
|
317
|
+
|
318
|
+
def mongoblazer_options
|
319
|
+
if defined?(@mongoblazer_options)
|
320
|
+
@mongoblazer_options
|
321
|
+
elsif superclass.respond_to?(:mongoblazer_options)
|
322
|
+
superclass.mongoblazer_options || { }
|
323
|
+
else
|
324
|
+
{ }
|
325
|
+
end
|
326
|
+
end
|
327
|
+
|
328
|
+
def mongoblazer_class
|
329
|
+
mongoblazer_class_name.constantize
|
330
|
+
end
|
331
|
+
|
332
|
+
def mongoblazer_class_name
|
333
|
+
"#{self.name}Blazer"
|
334
|
+
end
|
335
|
+
|
336
|
+
def recreate_mongoblazer_class!(called_from_parent=false)
|
337
|
+
create_mongoblazer_class!
|
338
|
+
|
339
|
+
unless called_from_parent
|
340
|
+
begin
|
341
|
+
configuration[:embeds_one].each do |rel|
|
342
|
+
"#{rel.to_s.camelize}".constantize.recreate_mongoblazer_class!(true)
|
343
|
+
end
|
344
|
+
rescue NameError
|
345
|
+
end
|
346
|
+
begin
|
347
|
+
configuration[:embeds_many].each do |rel|
|
348
|
+
"#{rel.to_s.singularize.camelize}".constantize.recreate_mongoblazer_class!(true)
|
349
|
+
end
|
350
|
+
rescue NameError
|
351
|
+
end
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
private # ----------------------------------------------------------------
|
356
|
+
|
357
|
+
def create_mongoblazer_class!
|
358
|
+
configuration = mongoblazer_options
|
359
|
+
|
360
|
+
relations = configure_mongoblazer_relations! configuration[:embeds_one], :embeds_one
|
361
|
+
relations += configure_mongoblazer_relations! configuration[:embeds_many], :embeds_many
|
362
|
+
|
363
|
+
uploaders = configure_mongoblazer_uploaders!
|
364
|
+
|
365
|
+
klass = begin
|
366
|
+
mongoblazer_class
|
367
|
+
rescue NameError
|
368
|
+
collection = mongoblazer_class_name.pluralize.underscore
|
369
|
+
|
370
|
+
klass = Class.new do
|
371
|
+
include ::Mongoblazer::Document
|
372
|
+
|
373
|
+
# Use one collection to avoid class initialization trouble
|
374
|
+
# when guessing the collection to use.
|
375
|
+
store_in collection: collection
|
376
|
+
|
377
|
+
index ar_id: 1
|
378
|
+
index _type: 1
|
379
|
+
|
380
|
+
default_scope configuration[:default_scope] if configuration[:default_scope].present?
|
381
|
+
|
382
|
+
configuration[:indexes].each { |ind| index ind }
|
383
|
+
end
|
384
|
+
|
385
|
+
Object.const_set mongoblazer_class_name, klass
|
386
|
+
|
387
|
+
klass
|
388
|
+
end
|
389
|
+
|
390
|
+
klass.module_eval relations.join("\n")
|
391
|
+
klass.module_eval uploaders.join("\n")
|
392
|
+
end
|
393
|
+
|
394
|
+
def configure_mongoblazer_relations!(relations, embed_type=:embeds_one)
|
395
|
+
relations.map do |em, klass_name|
|
396
|
+
class_name = if klass_name
|
397
|
+
"#{klass_name}Blazer"
|
398
|
+
elsif embed_type == :embeds_one
|
399
|
+
"#{em.to_s.camelize}Blazer"
|
400
|
+
else
|
401
|
+
"#{em.to_s.singularize.camelize}Blazer"
|
402
|
+
end
|
403
|
+
|
404
|
+
if const_defined?(class_name)
|
405
|
+
<<-CODE
|
406
|
+
#{embed_type} :#{em}, class_name: '#{class_name}', inverse_of: '#{mongoblazer_class_name}'
|
407
|
+
accepts_nested_attributes_for :#{em}
|
408
|
+
CODE
|
409
|
+
else
|
410
|
+
<<-CODE
|
411
|
+
def #{em}=(data)
|
412
|
+
write_attribute(:#{em}, data)
|
413
|
+
end
|
414
|
+
|
415
|
+
def #{em}
|
416
|
+
data = attributes['#{em}']
|
417
|
+
if data.is_a? Array
|
418
|
+
data.map{|d| OpenStruct.new(d)}
|
419
|
+
elsif data.is_a? Hash
|
420
|
+
OpenStruct.new(data)
|
421
|
+
else
|
422
|
+
data
|
423
|
+
end
|
424
|
+
end
|
425
|
+
CODE
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# module CarrierWave
|
2
|
+
# class Uploader::Base
|
3
|
+
# def __bson_dump__(io, key)
|
4
|
+
# data = versions.merge({default: self.to_s})
|
5
|
+
|
6
|
+
# io << Types::OBJECT_ID
|
7
|
+
# io << key
|
8
|
+
# io << NULL_BYTE
|
9
|
+
# io << data
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
# end
|
13
|
+
|
14
|
+
module Mongoblazer
|
15
|
+
module ActiveRecord
|
16
|
+
module Carrierwave
|
17
|
+
extend ActiveSupport::Concern
|
18
|
+
|
19
|
+
module ClassMethods
|
20
|
+
def mount_uploader(name, klass, options={})
|
21
|
+
mongoblazer_init uploaders: name
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def configure_mongoblazer_uploaders!
|
28
|
+
mongoblazer_options[:uploaders].map do |uploader|
|
29
|
+
<<-CODE
|
30
|
+
def #{uploader}
|
31
|
+
@#{uploader} ||= begin
|
32
|
+
klass = Class.new OpenStruct do
|
33
|
+
def to_s
|
34
|
+
default
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
klass.new(attributes['#{uploader}'])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
CODE
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Mongoblazer
|
2
|
+
module Document
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
include Mongoid::Document
|
5
|
+
|
6
|
+
included do
|
7
|
+
field :ar_id, type: String
|
8
|
+
|
9
|
+
index ar_id: 1
|
10
|
+
|
11
|
+
def is_mongoblazed?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
|
15
|
+
def ar_object
|
16
|
+
@ar_object ||= self.class.name.sub(/Blazer$/, '').constantize.find(ar_id)
|
17
|
+
end
|
18
|
+
|
19
|
+
def method_missing(method_sym, *arguments, &block)
|
20
|
+
begin
|
21
|
+
super
|
22
|
+
rescue NoMethodError
|
23
|
+
Rails.logger.debug "MONGOBLAZER DEBUG: #{self.class.name} access to unblazed method:
|
24
|
+
#{method_sym} with args:
|
25
|
+
#{arguments.inspect}
|
26
|
+
for record with id: #{id}"
|
27
|
+
if ar_object.respond_to? method_sym
|
28
|
+
ar_object.send method_sym
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Mongoblazer
|
2
|
+
if defined? Rails::Railtie
|
3
|
+
require 'rails'
|
4
|
+
|
5
|
+
class Railtie < Rails::Railtie
|
6
|
+
initializer 'mongoblazer.insert_into_active_record' do
|
7
|
+
ActiveSupport.on_load :active_record do
|
8
|
+
Mongoblazer::Railtie.insert
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# rake_tasks do
|
13
|
+
# load "tasks/mongoblazer.rake"
|
14
|
+
# end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Railtie
|
19
|
+
def self.insert
|
20
|
+
if defined?(::ActiveRecord)
|
21
|
+
::ActiveRecord::Base.class_eval do
|
22
|
+
include Mongoblazer::ActiveRecord
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/mongoblazer/version.rb
CHANGED
data/mongoblazer.gemspec
CHANGED
@@ -20,6 +20,10 @@ Gem::Specification.new do |spec|
|
|
20
20
|
|
21
21
|
spec.add_development_dependency "bundler", "~> 1.3"
|
22
22
|
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "database_cleaner"
|
25
|
+
spec.add_development_dependency "debugger"
|
26
|
+
spec.add_development_dependency "sqlite3"
|
23
27
|
|
24
28
|
spec.add_runtime_dependency "rails"
|
25
29
|
spec.add_runtime_dependency "mongoid"
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mongoblazer::ActiveRecord do
|
4
|
+
|
5
|
+
describe ".mongoblazable" do
|
6
|
+
context "not enabled" do
|
7
|
+
subject { NotEnabled }
|
8
|
+
it { should_not be_mongoblazable }
|
9
|
+
end
|
10
|
+
|
11
|
+
context "enabled" do
|
12
|
+
subject { Enabled }
|
13
|
+
it { should be_mongoblazable }
|
14
|
+
end
|
15
|
+
|
16
|
+
context "enabled in parent" do
|
17
|
+
subject { EnabledInParent }
|
18
|
+
it { should be_mongoblazable }
|
19
|
+
end
|
20
|
+
|
21
|
+
context "options" do
|
22
|
+
subject { EnabledInParent.mongoblazer_options }
|
23
|
+
it { should eq({:indexes=>[], :uploaders=>[], :embeds_one=>{}, :embeds_many=>{:posts=>nil}, :includes=>{:posts=>[{:comments=>:user}, :tags]}, :additional_attributes=>[:additional]}) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe ".create_mongoblazer_class!" do
|
28
|
+
subject { Enabled }
|
29
|
+
|
30
|
+
it "should have defined the EnabledBlazer class" do
|
31
|
+
defined?(EnabledBlazer).should eq "constant"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".mongoblaze!" do
|
36
|
+
let(:post) { Post.create(title: "Foo", body: "Bar baz burp", status: 'published')}
|
37
|
+
let(:enabled) { Enabled.create(name: "Enabled", posts: [post]) }
|
38
|
+
|
39
|
+
context "after_create" do
|
40
|
+
before { Enabled.any_instance.should_receive :mongoblaze! }
|
41
|
+
|
42
|
+
it { enabled }
|
43
|
+
end
|
44
|
+
|
45
|
+
context "with relations" do
|
46
|
+
subject { enabled.mongoblazed }
|
47
|
+
|
48
|
+
it "should contain a post" do
|
49
|
+
subject.posts.size.should be 1
|
50
|
+
end
|
51
|
+
|
52
|
+
context "related data" do
|
53
|
+
subject { enabled.mongoblazed.posts.first }
|
54
|
+
|
55
|
+
its(:title) { should eq "Foo" }
|
56
|
+
its(:body) { should eq "Bar baz burp" }
|
57
|
+
its(:status) { should eq "published" }
|
58
|
+
end
|
59
|
+
|
60
|
+
context "with additional_attributes" do
|
61
|
+
its(:additional) { should eq "additional attribute to include" }
|
62
|
+
end
|
63
|
+
|
64
|
+
context "with attributes not in blazed fallback" do
|
65
|
+
its(:not_in_blazed) { should eq "this is not in the blazed instance" }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context "with enabled relations" do
|
70
|
+
let(:enabled) { WithEnabledRelation.create(name: "FooBar", related_enableds: [related_enabled]) }
|
71
|
+
let(:related_enabled) { RelatedEnabled.create(name: "Related To FooBar") }
|
72
|
+
subject { enabled.mongoblazed }
|
73
|
+
|
74
|
+
its(:name) { should eq "FooBar" }
|
75
|
+
|
76
|
+
it "should have embedded related_enableds" do
|
77
|
+
subject.related_enableds.size.should be 1
|
78
|
+
end
|
79
|
+
|
80
|
+
context "options" do
|
81
|
+
subject { WithEnabledRelation.mongoblazer_options }
|
82
|
+
it { should eq({:indexes=>[], :uploaders=>[], :embeds_one=>{}, :embeds_many=>{:related_enableds=>nil}, :includes=>:related_enableds}) }
|
83
|
+
end
|
84
|
+
|
85
|
+
context "relations" do
|
86
|
+
subject { enabled.mongoblazed.related_enableds.first }
|
87
|
+
|
88
|
+
its(:name) { should eq "Related To FooBar" }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
ENV["RACK_ENV"] ||= 'test'
|
2
|
+
ENV['RAILS_ENV'] ||= 'test'
|
3
|
+
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.require
|
6
|
+
|
7
|
+
Dir[File.expand_path("../../lib/**/*.rb", __FILE__)].each {|f| require f}
|
8
|
+
Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.color_enabled = true
|
12
|
+
config.tty = true
|
13
|
+
config.formatter = :progress
|
14
|
+
end
|
data/spec/support/ar.rb
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
::ActiveRecord::Base.class_eval do
|
2
|
+
include Mongoblazer::ActiveRecord
|
3
|
+
end
|
4
|
+
|
5
|
+
ActiveRecord::Base.establish_connection(
|
6
|
+
:adapter => 'sqlite3',
|
7
|
+
:database => ':memory:'
|
8
|
+
)
|
9
|
+
|
10
|
+
ActiveRecord::Schema.define(:version => 0) do
|
11
|
+
create_table "not_enableds" do |t|
|
12
|
+
t.string "name"
|
13
|
+
end
|
14
|
+
|
15
|
+
create_table "enableds" do |t|
|
16
|
+
t.string "name"
|
17
|
+
t.string "mongoblazer_id"
|
18
|
+
end
|
19
|
+
|
20
|
+
create_table "with_enabled_relations" do |t|
|
21
|
+
t.string "name"
|
22
|
+
t.string "mongoblazer_id"
|
23
|
+
end
|
24
|
+
|
25
|
+
create_table "related_enableds" do |t|
|
26
|
+
t.string "name"
|
27
|
+
t.integer "with_enabled_relation_id"
|
28
|
+
end
|
29
|
+
|
30
|
+
create_table "posts" do |t|
|
31
|
+
t.integer "enabled_id"
|
32
|
+
t.integer "user_id"
|
33
|
+
t.string "title"
|
34
|
+
t.text "body"
|
35
|
+
t.string "status"
|
36
|
+
end
|
37
|
+
|
38
|
+
add_index "posts", "status", name: "index_posts_on_status"
|
39
|
+
|
40
|
+
create_table "comments" do |t|
|
41
|
+
t.integer "post_id"
|
42
|
+
t.integer "user_id"
|
43
|
+
t.string "text"
|
44
|
+
end
|
45
|
+
|
46
|
+
create_table "users" do |t|
|
47
|
+
t.string "name"
|
48
|
+
end
|
49
|
+
|
50
|
+
create_table "tags" do |t|
|
51
|
+
t.string "name"
|
52
|
+
end
|
53
|
+
|
54
|
+
create_table "posts_tags", id: false do |t|
|
55
|
+
t.integer "post_id"
|
56
|
+
t.integer "tag_id"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
class NotEnabled < ActiveRecord::Base
|
61
|
+
end
|
62
|
+
|
63
|
+
class Enabled < ActiveRecord::Base
|
64
|
+
has_many :posts
|
65
|
+
|
66
|
+
mongoblazer_includes posts: [{comments: :user}, :tags]
|
67
|
+
mongoblazer_additional_attributes [:additional]
|
68
|
+
|
69
|
+
after_save :mongoblaze!
|
70
|
+
|
71
|
+
def additional
|
72
|
+
"additional attribute to include"
|
73
|
+
end
|
74
|
+
|
75
|
+
def not_in_blazed
|
76
|
+
"this is not in the blazed instance"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
class EnabledInParent < Enabled
|
81
|
+
end
|
82
|
+
|
83
|
+
class WithEnabledRelation < ActiveRecord::Base
|
84
|
+
has_many :related_enableds
|
85
|
+
|
86
|
+
mongoblazer_includes :related_enableds
|
87
|
+
|
88
|
+
after_save :mongoblaze!
|
89
|
+
end
|
90
|
+
|
91
|
+
class RelatedEnabled < ActiveRecord::Base
|
92
|
+
belongs_to :with_enabled_relation
|
93
|
+
|
94
|
+
mongoblazer_includes :with_enabled_relation
|
95
|
+
end
|
96
|
+
|
97
|
+
class DefaultScoped < Enabled
|
98
|
+
default_scope where(foo: "bar")
|
99
|
+
end
|
100
|
+
|
101
|
+
class Post < ActiveRecord::Base
|
102
|
+
belongs_to :user
|
103
|
+
has_many :comments
|
104
|
+
has_and_belongs_to_many :tags
|
105
|
+
|
106
|
+
default_scope where(status: 'published')
|
107
|
+
end
|
108
|
+
|
109
|
+
class Comment < ActiveRecord::Base
|
110
|
+
belongs_to :post
|
111
|
+
belongs_to :user
|
112
|
+
end
|
113
|
+
|
114
|
+
class User < ActiveRecord::Base
|
115
|
+
has_many :posts
|
116
|
+
has_many :comments
|
117
|
+
end
|
118
|
+
|
119
|
+
class Tag < ActiveRecord::Base
|
120
|
+
has_and_belongs_to_many :posts
|
121
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'database_cleaner'
|
2
|
+
|
3
|
+
RSpec.configure do |config|
|
4
|
+
|
5
|
+
config.before :suite do
|
6
|
+
DatabaseCleaner.orm = :mongoid
|
7
|
+
DatabaseCleaner.strategy = :truncation
|
8
|
+
DatabaseCleaner.clean_with :truncation
|
9
|
+
end
|
10
|
+
|
11
|
+
config.before :each do
|
12
|
+
DatabaseCleaner.clean
|
13
|
+
DatabaseCleaner.start
|
14
|
+
end
|
15
|
+
|
16
|
+
config.after :each do
|
17
|
+
DatabaseCleaner.clean
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
Mongoid.load!(File.expand_path("../mongoid.yml", __FILE__))
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongoblazer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-04-
|
12
|
+
date: 2013-04-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -43,6 +43,70 @@ dependencies:
|
|
43
43
|
- - ! '>='
|
44
44
|
- !ruby/object:Gem::Version
|
45
45
|
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: database_cleaner
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: debugger
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ! '>='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: '0'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: sqlite3
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
46
110
|
- !ruby/object:Gem::Dependency
|
47
111
|
name: rails
|
48
112
|
requirement: !ruby/object:Gem::Requirement
|
@@ -89,8 +153,18 @@ files:
|
|
89
153
|
- README.md
|
90
154
|
- Rakefile
|
91
155
|
- lib/mongoblazer.rb
|
156
|
+
- lib/mongoblazer/active_record.rb
|
157
|
+
- lib/mongoblazer/active_record/carrierwave.rb
|
158
|
+
- lib/mongoblazer/document.rb
|
159
|
+
- lib/mongoblazer/railtie.rb
|
92
160
|
- lib/mongoblazer/version.rb
|
93
161
|
- mongoblazer.gemspec
|
162
|
+
- spec/mongoblazer/active_record_spec.rb
|
163
|
+
- spec/spec_helper.rb
|
164
|
+
- spec/support/ar.rb
|
165
|
+
- spec/support/database_cleaner.rb
|
166
|
+
- spec/support/mongoid.rb
|
167
|
+
- spec/support/mongoid.yml
|
94
168
|
homepage: http://springest.github.com/mongoblazer
|
95
169
|
licenses:
|
96
170
|
- MIT
|
@@ -116,4 +190,10 @@ rubygems_version: 1.8.23
|
|
116
190
|
signing_key:
|
117
191
|
specification_version: 3
|
118
192
|
summary: MongoBlazer to flatten ActiveRecord Models into Mongodb Documents
|
119
|
-
test_files:
|
193
|
+
test_files:
|
194
|
+
- spec/mongoblazer/active_record_spec.rb
|
195
|
+
- spec/spec_helper.rb
|
196
|
+
- spec/support/ar.rb
|
197
|
+
- spec/support/database_cleaner.rb
|
198
|
+
- spec/support/mongoid.rb
|
199
|
+
- spec/support/mongoid.yml
|