populate-me 0.0.33 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/LICENSE +1 -1
- data/README.md +399 -4
- data/Rakefile +14 -0
- data/example/config.ru +67 -0
- data/lib/populate_me.rb +2 -0
- data/lib/populate_me/admin.rb +143 -0
- data/lib/populate_me/admin/__assets__/css/main.css +174 -0
- data/lib/populate_me/admin/__assets__/js/columnav.js +82 -0
- data/lib/populate_me/admin/__assets__/js/main.js +251 -0
- data/lib/populate_me/admin/__assets__/js/mustache.js +578 -0
- data/lib/populate_me/admin/__assets__/js/sortable.js +2 -0
- data/lib/populate_me/admin/views/page.erb +163 -0
- data/lib/populate_me/api.rb +124 -0
- data/lib/populate_me/attachment.rb +182 -0
- data/lib/populate_me/document.rb +178 -0
- data/lib/populate_me/document_mixins/admin_adapter.rb +131 -0
- data/lib/populate_me/document_mixins/callbacks.rb +104 -0
- data/lib/populate_me/document_mixins/outcasting.rb +49 -0
- data/lib/populate_me/document_mixins/persistence.rb +92 -0
- data/lib/populate_me/document_mixins/schema.rb +99 -0
- data/lib/populate_me/document_mixins/typecasting.rb +60 -0
- data/lib/populate_me/document_mixins/validation.rb +44 -0
- data/lib/populate_me/file_system_attachment.rb +40 -0
- data/lib/populate_me/grid_fs_attachment.rb +127 -0
- data/lib/populate_me/mongo.rb +98 -3
- data/lib/populate_me/variation.rb +34 -0
- data/lib/populate_me/version.rb +4 -0
- data/populate-me.gemspec +20 -12
- data/test/helper.rb +37 -0
- data/test/test_admin.rb +161 -0
- data/test/test_api.rb +246 -0
- data/test/test_attachment.rb +155 -0
- data/test/test_document.rb +120 -0
- data/test/test_document_admin_adapter.rb +43 -0
- data/test/test_document_callbacks.rb +107 -0
- data/test/test_document_persistence.rb +56 -0
- data/test/test_document_typecasting.rb +121 -0
- data/test/test_mongo.rb +217 -0
- data/test/test_variation.rb +91 -0
- data/test/test_version.rb +11 -0
- metadata +115 -66
- data/lib/populate_me/control.rb +0 -196
- data/lib/populate_me/control/_public/css/main.css +0 -207
- data/lib/populate_me/control/_public/css/plugin.asmselect.css +0 -63
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_flat_30_cccccc_40x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_flat_50_5c5c5c_40x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_20_555555_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_40_0078a3_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_glass_40_ffc73d_1x400.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_gloss-wave_25_333333_500x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_highlight-soft_80_eeeeee_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_inset-soft_25_000000_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-bg_inset-soft_30_f58400_1x100.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_222222_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_4b8e0b_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_a83300_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_cccccc_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/images/ui-icons_ffffff_256x240.png +0 -0
- data/lib/populate_me/control/_public/css/ui-darkness/jquery-ui-1.8.17.custom.css +0 -430
- data/lib/populate_me/control/_public/img/grip.png +0 -0
- data/lib/populate_me/control/_public/img/icons-cms-solarized.png +0 -0
- data/lib/populate_me/control/_public/img/icons-cms.png +0 -0
- data/lib/populate_me/control/_public/img/placeholder.png +0 -0
- data/lib/populate_me/control/_public/img/placeholder.stash_thumb.gif +0 -0
- data/lib/populate_me/control/_public/img/placeholder.stash_thumb.png +0 -0
- data/lib/populate_me/control/_public/img/small-loader.gif +0 -0
- data/lib/populate_me/control/_public/js/addon.timepicker.js +0 -20
- data/lib/populate_me/control/_public/js/jquery-ui.js +0 -114
- data/lib/populate_me/control/_public/js/jquery.js +0 -167
- data/lib/populate_me/control/_public/js/jquery.mustache.js +0 -559
- data/lib/populate_me/control/_public/js/main.js +0 -144
- data/lib/populate_me/control/_public/js/plugin.asmselect.js +0 -407
- data/lib/populate_me/control/_public/js/plugin.form.js +0 -11
- data/lib/populate_me/control/_public/js/plugin.quicksearch.js +0 -1
- data/lib/populate_me/control/_public/js/plugin.underwood.js +0 -4
- data/lib/populate_me/control/views/populate_me_layout.erb +0 -75
- data/lib/populate_me/ext.rb +0 -16
- data/lib/populate_me/mongo/backend_api_plug.rb +0 -78
- data/lib/populate_me/mongo/crushyform.rb +0 -243
- data/lib/populate_me/mongo/mutation.rb +0 -324
- data/lib/populate_me/mongo/plug.rb +0 -134
- data/lib/populate_me/mongo/stash.rb +0 -171
- data/test/spec_ext.rb +0 -29
- data/test/spec_mongo_mutation.rb +0 -279
@@ -0,0 +1,92 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module DocumentMixins
|
3
|
+
module Persistence
|
4
|
+
|
5
|
+
def persistent_instance_variables
|
6
|
+
instance_variables.select do |k|
|
7
|
+
if self.class.fields.empty?
|
8
|
+
k !~ /^@_/
|
9
|
+
else
|
10
|
+
self.class.fields.key? k[1..-1].to_sym
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def attachment f
|
16
|
+
attacher = Utils.resolve_class_name self.class.fields[f][:class_name]
|
17
|
+
attacher.new self, f
|
18
|
+
end
|
19
|
+
|
20
|
+
# Saving
|
21
|
+
def save
|
22
|
+
return unless valid?
|
23
|
+
exec_callback :before_save
|
24
|
+
if new?
|
25
|
+
exec_callback :before_create
|
26
|
+
id = perform_create
|
27
|
+
exec_callback :after_create
|
28
|
+
else
|
29
|
+
exec_callback :before_update
|
30
|
+
id = perform_update
|
31
|
+
exec_callback :after_update
|
32
|
+
end
|
33
|
+
exec_callback :after_save
|
34
|
+
id
|
35
|
+
end
|
36
|
+
def perform_create
|
37
|
+
self.class.documents << self.to_h
|
38
|
+
self.id
|
39
|
+
end
|
40
|
+
def perform_update
|
41
|
+
index = self.class.documents.index{|d| d['id']==self.id }
|
42
|
+
raise MissingDocumentError, "No document can be found with this ID: #{self.id}" if self.id.nil?||index.nil?
|
43
|
+
self.class.documents[index] = self.to_h
|
44
|
+
end
|
45
|
+
|
46
|
+
# Deletion
|
47
|
+
def delete o={}
|
48
|
+
exec_callback :before_delete
|
49
|
+
perform_delete
|
50
|
+
exec_callback :after_delete
|
51
|
+
end
|
52
|
+
def perform_delete
|
53
|
+
index = self.class.documents.index{|d| d['id']==self.id }
|
54
|
+
raise MissingDocumentError, "No document can be found with this ID: #{self.id}" if self.id.nil?||index.nil?
|
55
|
+
self.class.documents.delete_at(index)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.included(base)
|
59
|
+
base.extend(ClassMethods)
|
60
|
+
end
|
61
|
+
|
62
|
+
module ClassMethods
|
63
|
+
|
64
|
+
attr_writer :documents
|
65
|
+
|
66
|
+
def documents; @documents ||= []; end
|
67
|
+
|
68
|
+
def id_string_key
|
69
|
+
(self.fields.keys[0]||'id').to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
def set_indexes f, ids=[]
|
73
|
+
ids.each_with_index do |id,i|
|
74
|
+
self.documents.each do |d|
|
75
|
+
d[f.to_s] = i if d[self.id_string_key]==id
|
76
|
+
end
|
77
|
+
end
|
78
|
+
self
|
79
|
+
end
|
80
|
+
|
81
|
+
def is_unique unique_id='unique'
|
82
|
+
if self.admin_get(unique_id).nil?
|
83
|
+
self.new.set_from_hash({id:unique_id}).save
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module DocumentMixins
|
3
|
+
module Schema
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
attr_writer :fields
|
12
|
+
attr_accessor :label_field
|
13
|
+
|
14
|
+
def fields; @fields ||= {}; end
|
15
|
+
|
16
|
+
def field name, o={}
|
17
|
+
set_id_field if self.fields.empty?&&o[:type]!=:id
|
18
|
+
complete_field_options name, o
|
19
|
+
if o[:type]==:list
|
20
|
+
define_method(name) do
|
21
|
+
var = "@#{name}"
|
22
|
+
instance_variable_set(var, instance_variable_get(var)||[])
|
23
|
+
end
|
24
|
+
else
|
25
|
+
attr_accessor name
|
26
|
+
end
|
27
|
+
self.fields[name] = o
|
28
|
+
end
|
29
|
+
|
30
|
+
def complete_field_options name, o={}
|
31
|
+
o[:field_name] = name
|
32
|
+
WebUtils.ensure_key! o, :type, :string
|
33
|
+
WebUtils.ensure_key! o, :form_field, ![:id,:position].include?(o[:type])
|
34
|
+
o[:wrap] = false unless o[:form_field]
|
35
|
+
WebUtils.ensure_key! o, :wrap, ![:hidden,:list].include?(o[:type])
|
36
|
+
WebUtils.ensure_key! o, :label, WebUtils.label_for_field(name)
|
37
|
+
if o[:type]==:attachment
|
38
|
+
WebUtils.ensure_key! o, :class_name, settings.default_attachment_class
|
39
|
+
raise MissingAttachmentClassError, "No attachment class was provided for the #{self.name} field: #{name}" if o[:class_name].nil?
|
40
|
+
o[:class_name] = o[:class_name].name unless o[:class_name].is_a?(String)
|
41
|
+
end
|
42
|
+
if o[:type]==:list
|
43
|
+
o[:class_name] = WebUtils.guess_related_class_name(self.name,o[:class_name]||name)
|
44
|
+
o[:dasherized_class_name] = WebUtils.dasherize_class_name o[:class_name]
|
45
|
+
else
|
46
|
+
WebUtils.ensure_key! o, :input_attributes, {}
|
47
|
+
o[:input_attributes][:type] = :hidden if o[:type]==:hidden
|
48
|
+
unless o[:type]==:text
|
49
|
+
WebUtils.ensure_key! o[:input_attributes], :type, :text
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def set_id_field
|
55
|
+
field :id, {type: :id}
|
56
|
+
end
|
57
|
+
|
58
|
+
def position_field o={}
|
59
|
+
name = o[:name]||:position
|
60
|
+
o[:type] = :position
|
61
|
+
field name, o
|
62
|
+
sort_by name
|
63
|
+
end
|
64
|
+
|
65
|
+
def label sym # sets the label_field
|
66
|
+
@label_field = sym.to_sym
|
67
|
+
end
|
68
|
+
|
69
|
+
def label_field
|
70
|
+
@label_field || self.fields.keys[1]
|
71
|
+
end
|
72
|
+
|
73
|
+
def sort_by f, direction=:asc
|
74
|
+
raise(ArgumentError) unless [:asc,:desc].include? direction
|
75
|
+
raise(ArgumentError) unless self.new.respond_to? f
|
76
|
+
@sort_proc = Proc.new do |a,b|
|
77
|
+
a,b = b,a if direction==:desc
|
78
|
+
a.__send__(f)<=>b.__send__(f)
|
79
|
+
end
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
def relationships; @relationships ||= {}; end
|
84
|
+
|
85
|
+
def relationship name, o={}
|
86
|
+
o[:class_name] = WebUtils.guess_related_class_name(self.name,o[:class_name]||name)
|
87
|
+
WebUtils.ensure_key! o, :label, name.to_s.capitalize
|
88
|
+
WebUtils.ensure_key! o, :foreign_key, "#{WebUtils.dasherize_class_name(self.name).gsub('-','_')}_id"
|
89
|
+
o[:foreign_key] = o[:foreign_key].to_sym
|
90
|
+
WebUtils.ensure_key! o, :dependent, true
|
91
|
+
self.relationships[name] = o
|
92
|
+
end
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module DocumentMixins
|
3
|
+
module Typecasting
|
4
|
+
|
5
|
+
# This module deals with typecasting the fields
|
6
|
+
# when they are received as strings,
|
7
|
+
# generally from a form or a csv file
|
8
|
+
|
9
|
+
def typecast k, v
|
10
|
+
unless self.class.fields.key?(k)
|
11
|
+
return WebUtils.automatic_typecast(v)
|
12
|
+
end
|
13
|
+
f = self.class.fields[k].dup
|
14
|
+
meth = "typecast_#{f[:type]}".to_sym
|
15
|
+
unless respond_to? meth
|
16
|
+
return WebUtils.automatic_typecast(v, [f[:type],:nil])
|
17
|
+
end
|
18
|
+
__send__ meth, k, v
|
19
|
+
end
|
20
|
+
|
21
|
+
def typecast_integer k, v
|
22
|
+
v.to_i
|
23
|
+
end
|
24
|
+
|
25
|
+
def typecast_price k, v
|
26
|
+
return nil if WebUtils.blank?(v)
|
27
|
+
WebUtils.parse_price(v)
|
28
|
+
end
|
29
|
+
|
30
|
+
def typecast_date k, v
|
31
|
+
if v[/\d\d(\/|-)\d\d(\/|-)\d\d\d\d/]
|
32
|
+
Date.parse v
|
33
|
+
else
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def typecast_datetime k, v
|
39
|
+
if v[/\d\d(\/|-)\d\d(\/|-)\d\d\d\d \d\d?:\d\d?:\d\d?/]
|
40
|
+
d,m,y,h,min,s = v.split(/[-:\s\/]/)
|
41
|
+
Time.utc(y,m,d,h,min,s)
|
42
|
+
else
|
43
|
+
nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def typecast_attachment k, v
|
48
|
+
attached = self.attachment k
|
49
|
+
if WebUtils.blank? v
|
50
|
+
attached.delete_all
|
51
|
+
return nil
|
52
|
+
elsif v.is_a?(Hash)&&v.key?(:tempfile)
|
53
|
+
return attached.create v
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module PopulateMe
|
2
|
+
module DocumentMixins
|
3
|
+
module Validation
|
4
|
+
|
5
|
+
attr_accessor :_errors
|
6
|
+
|
7
|
+
def errors; self._errors; end
|
8
|
+
|
9
|
+
def error_on k,v
|
10
|
+
self._errors[k] = (self._errors[k]||[]) << v
|
11
|
+
self
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid?
|
15
|
+
self._errors = {}
|
16
|
+
exec_callback :before_validate
|
17
|
+
validate
|
18
|
+
exec_callback :after_validate
|
19
|
+
nested_docs.reduce self._errors.empty? do |result,d|
|
20
|
+
result &= d.valid?
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate; end
|
25
|
+
|
26
|
+
def error_report
|
27
|
+
report = self._errors.dup || {}
|
28
|
+
persistent_instance_variables.each do |var|
|
29
|
+
value = instance_variable_get var
|
30
|
+
if value.is_a? Array
|
31
|
+
k = var[1..-1].to_sym
|
32
|
+
report[k] = []
|
33
|
+
value.each do |d|
|
34
|
+
report[k] << d.error_report
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
report
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'populate_me/attachment'
|
2
|
+
|
3
|
+
module PopulateMe
|
4
|
+
|
5
|
+
class FileSystemAttachment < Attachment
|
6
|
+
|
7
|
+
set :root, File.expand_path('public')
|
8
|
+
|
9
|
+
def next_available_filename filename
|
10
|
+
FileUtils.mkdir_p self.location_root
|
11
|
+
ext = File.extname(filename)
|
12
|
+
base = File.basename(filename,ext)
|
13
|
+
i = 0
|
14
|
+
loop do
|
15
|
+
suffix = i==0 ? '' : "-#{i}"
|
16
|
+
potential_filename = [base,suffix,ext].join
|
17
|
+
potential_location = self.location_for_filename(potential_filename)
|
18
|
+
if File.exist?(potential_location)
|
19
|
+
i += 1
|
20
|
+
else
|
21
|
+
filename = potential_filename
|
22
|
+
break
|
23
|
+
end
|
24
|
+
end
|
25
|
+
filename
|
26
|
+
end
|
27
|
+
|
28
|
+
def perform_create hash
|
29
|
+
return File.basename(hash[:variation_path]) unless WebUtils.blank?(hash[:variation_path])
|
30
|
+
source = hash[:tempfile].path
|
31
|
+
filename = self.next_available_filename hash[:filename]
|
32
|
+
destination = self.location_for_filename filename
|
33
|
+
FileUtils.cp source, destination
|
34
|
+
filename
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
@@ -0,0 +1,127 @@
|
|
1
|
+
require 'populate_me/attachment'
|
2
|
+
require 'mongo'
|
3
|
+
require 'rack/gridfs'
|
4
|
+
|
5
|
+
module PopulateMe
|
6
|
+
|
7
|
+
class MissingMongoDBError < StandardError; end
|
8
|
+
|
9
|
+
class GridFSAttachment < Attachment
|
10
|
+
|
11
|
+
# set :url_prefix, '/attachment'
|
12
|
+
|
13
|
+
def grid
|
14
|
+
self.class.grid
|
15
|
+
end
|
16
|
+
|
17
|
+
def gridfs
|
18
|
+
self.class.gridfs
|
19
|
+
end
|
20
|
+
|
21
|
+
# Attachee_prefix is moved on field_value for gridfs
|
22
|
+
def url variation_name=:original
|
23
|
+
return nil if WebUtils.blank?(self.field_filename(variation_name))
|
24
|
+
"#{settings.url_prefix.sub(/\/$/,'')}/#{self.field_filename(variation_name)}"
|
25
|
+
end
|
26
|
+
# Attachee_prefix is moved on field_value for gridfs
|
27
|
+
def location_root
|
28
|
+
File.join(
|
29
|
+
settings.root,
|
30
|
+
settings.url_prefix
|
31
|
+
)
|
32
|
+
end
|
33
|
+
|
34
|
+
def deletable? variation_name=:original
|
35
|
+
!WebUtils.blank? self.field_filename(variation_name)
|
36
|
+
# Fine since deleting a non-existent file does not raise an error in mongo
|
37
|
+
end
|
38
|
+
|
39
|
+
def perform_delete variation_name=:original
|
40
|
+
# gridfs works with names instead of IDs
|
41
|
+
gridfs.delete self.field_filename(variation_name)
|
42
|
+
end
|
43
|
+
|
44
|
+
def next_available_filename filename
|
45
|
+
ext = File.extname(filename)
|
46
|
+
base = "#{attachee_prefix}/#{File.basename(filename,ext)}"
|
47
|
+
i = 0
|
48
|
+
loop do
|
49
|
+
suffix = i==0 ? '' : "-#{i}"
|
50
|
+
potential_filename = [base,suffix,ext].join
|
51
|
+
if grid.exist?(filename: potential_filename)
|
52
|
+
i += 1
|
53
|
+
else
|
54
|
+
filename = potential_filename
|
55
|
+
break
|
56
|
+
end
|
57
|
+
end
|
58
|
+
filename
|
59
|
+
end
|
60
|
+
|
61
|
+
def perform_create hash
|
62
|
+
if hash[:variation].nil?
|
63
|
+
fn = next_available_filename(hash[:filename])
|
64
|
+
file = hash[:tempfile]
|
65
|
+
type = hash[:type]
|
66
|
+
else
|
67
|
+
fn = WebUtils.filename_variation hash[:future_field_value], hash[:variation].name, hash[:variation].ext
|
68
|
+
file = File.open(hash[:variation_path])
|
69
|
+
type = Rack::Mime.mime_type ".#{hash[:variation].ext}"
|
70
|
+
end
|
71
|
+
attachment_id = grid.put(
|
72
|
+
file, {
|
73
|
+
filename: fn,
|
74
|
+
content_type: type,
|
75
|
+
metadata: {
|
76
|
+
parent_collection: (self.document.class.respond_to?(:collection) ? self.document.class.collection.name : self.attachee_prefix),
|
77
|
+
}
|
78
|
+
}
|
79
|
+
)
|
80
|
+
file.close unless hash[:variation].nil?
|
81
|
+
fn
|
82
|
+
end
|
83
|
+
|
84
|
+
class << self
|
85
|
+
|
86
|
+
def ensure_db
|
87
|
+
raise MissingMongoDBError, "Attachment class #{self.name} does not have a Mongo database." if settings.db.nil?
|
88
|
+
end
|
89
|
+
|
90
|
+
def grid
|
91
|
+
ensure_db
|
92
|
+
unless settings.grid.is_a?(::Mongo::Grid)
|
93
|
+
set :grid, ::Mongo::Grid.new(settings.db)
|
94
|
+
end
|
95
|
+
settings.grid
|
96
|
+
end
|
97
|
+
|
98
|
+
def gridfs
|
99
|
+
ensure_db
|
100
|
+
unless settings.gridfs.is_a?(::Mongo::GridFileSystem)
|
101
|
+
set :gridfs, ::Mongo::GridFileSystem.new(settings.db)
|
102
|
+
end
|
103
|
+
settings.gridfs
|
104
|
+
end
|
105
|
+
|
106
|
+
def middleware
|
107
|
+
Rack::GridFS
|
108
|
+
end
|
109
|
+
|
110
|
+
def middleware_options
|
111
|
+
[
|
112
|
+
{
|
113
|
+
prefix: settings.url_prefix.dup,
|
114
|
+
db: settings.db,
|
115
|
+
lookup: :path
|
116
|
+
}
|
117
|
+
]
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
GridFS = GridFSAttachment
|
125
|
+
|
126
|
+
end
|
127
|
+
|