populate-me 0.12.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/.gitignore +9 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +655 -0
- data/Rakefile +14 -0
- data/example/config.ru +100 -0
- data/lib/populate_me.rb +2 -0
- data/lib/populate_me/admin.rb +157 -0
- data/lib/populate_me/admin/__assets__/css/asmselect.css +63 -0
- data/lib/populate_me/admin/__assets__/css/jquery-ui.min.css +6 -0
- data/lib/populate_me/admin/__assets__/css/main.css +244 -0
- data/lib/populate_me/admin/__assets__/img/help/children.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/create.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/delete.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/edit.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/form.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/list.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/login.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/logout.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/menu.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/overview.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/save.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/sort.png +0 -0
- data/lib/populate_me/admin/__assets__/img/help/sublist.png +0 -0
- data/lib/populate_me/admin/__assets__/js/asmselect.js +412 -0
- data/lib/populate_me/admin/__assets__/js/columnav.js +87 -0
- data/lib/populate_me/admin/__assets__/js/jquery-ui.min.js +7 -0
- data/lib/populate_me/admin/__assets__/js/main.js +388 -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/help.erb +94 -0
- data/lib/populate_me/admin/views/page.erb +189 -0
- data/lib/populate_me/api.rb +124 -0
- data/lib/populate_me/attachment.rb +186 -0
- data/lib/populate_me/document.rb +192 -0
- data/lib/populate_me/document_mixins/admin_adapter.rb +149 -0
- data/lib/populate_me/document_mixins/callbacks.rb +125 -0
- data/lib/populate_me/document_mixins/outcasting.rb +83 -0
- data/lib/populate_me/document_mixins/persistence.rb +95 -0
- data/lib/populate_me/document_mixins/schema.rb +198 -0
- data/lib/populate_me/document_mixins/typecasting.rb +70 -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 +103 -0
- data/lib/populate_me/mongo.rb +160 -0
- data/lib/populate_me/s3_attachment.rb +120 -0
- data/lib/populate_me/variation.rb +38 -0
- data/lib/populate_me/version.rb +4 -0
- data/populate-me.gemspec +34 -0
- data/test/helper.rb +37 -0
- data/test/test_admin.rb +183 -0
- data/test/test_api.rb +246 -0
- data/test/test_attachment.rb +167 -0
- data/test/test_document.rb +128 -0
- data/test/test_document_admin_adapter.rb +221 -0
- data/test/test_document_callbacks.rb +151 -0
- data/test/test_document_outcasting.rb +247 -0
- data/test/test_document_persistence.rb +83 -0
- data/test/test_document_schema.rb +280 -0
- data/test/test_document_typecasting.rb +128 -0
- data/test/test_grid_fs_attachment.rb +239 -0
- data/test/test_mongo.rb +324 -0
- data/test/test_s3_attachment.rb +281 -0
- data/test/test_variation.rb +91 -0
- data/test/test_version.rb +11 -0
- metadata +294 -0
data/test/test_mongo.rb
ADDED
@@ -0,0 +1,324 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'populate_me/mongo'
|
3
|
+
# require 'mongo'
|
4
|
+
|
5
|
+
Mongo::Logger.logger.level = Logger::ERROR
|
6
|
+
|
7
|
+
MONGO = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'populate-me-test')
|
8
|
+
DB = MONGO.database
|
9
|
+
DB.drop
|
10
|
+
OTHER_MONGO = Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'populate-me-test-other')
|
11
|
+
OTHER_DB = OTHER_MONGO.database
|
12
|
+
OTHER_DB.drop
|
13
|
+
PopulateMe::Mongo.set :db, DB
|
14
|
+
|
15
|
+
|
16
|
+
describe 'PopulateMe::Mongo' do
|
17
|
+
# PopulateMe::Mongo is the Mongo specific extention for
|
18
|
+
# Document.
|
19
|
+
#
|
20
|
+
# It contains what is specific to a Mongo
|
21
|
+
# database.
|
22
|
+
|
23
|
+
# parallelize_me!
|
24
|
+
|
25
|
+
class CatFish < PopulateMe::Mongo
|
26
|
+
field :name
|
27
|
+
end
|
28
|
+
module Paradise
|
29
|
+
class CatFish < PopulateMe::Mongo
|
30
|
+
field :name
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'Includes Document Module' do
|
35
|
+
assert_equal "Cat Fish", CatFish.to_s
|
36
|
+
assert_equal "Fred", CatFish.new(name: "Fred").to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
it "Has _id as persistent variable if set" do
|
40
|
+
assert_equal [:@name], CatFish.new(name: "hank").persistent_instance_variables
|
41
|
+
cf = CatFish.new(id: "bbbbb", name: "honk")
|
42
|
+
assert cf.persistent_instance_variables.include?(:@_id)
|
43
|
+
assert cf.persistent_instance_variables.include?(:@name)
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'Database connection' do
|
47
|
+
|
48
|
+
class NoMongoDB < PopulateMe::Mongo; set :db, nil; end
|
49
|
+
|
50
|
+
it 'Should raise if db is not set' do
|
51
|
+
assert_raises(PopulateMe::MissingMongoDBError) do
|
52
|
+
NoMongoDB.collection
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'Should have db set by the parent class' do
|
57
|
+
assert_equal DB, CatFish.settings.db
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'Can override db' do
|
61
|
+
CatFish.set :db, OTHER_DB
|
62
|
+
assert_equal OTHER_DB, CatFish.settings.db
|
63
|
+
CatFish.set :db, DB
|
64
|
+
assert_equal DB, CatFish.settings.db
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'Should set DB collection to dasherized full class name by default' do
|
68
|
+
assert_equal "cat-fish", CatFish.collection_name
|
69
|
+
assert_equal "paradise--cat-fish", Paradise::CatFish.collection_name
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'Finds collection in DB' do
|
73
|
+
assert_equal DB['cat-fish'].name, CatFish.collection.name
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'Should set DB and collection name even for dynamically created classes' do
|
77
|
+
# Happens when an included module automatically happens a class.
|
78
|
+
# e.g. Slides for a Slideshow
|
79
|
+
CatFish.const_set("Item", Class.new(CatFish.superclass))
|
80
|
+
assert_equal "cat-fish--item", CatFish::Item.collection.name
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'Low level CRUD' do
|
86
|
+
|
87
|
+
class LowFish < PopulateMe::Mongo
|
88
|
+
field :name
|
89
|
+
field :lastname
|
90
|
+
end
|
91
|
+
|
92
|
+
before do
|
93
|
+
LowFish.collection.drop
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'Should create' do
|
97
|
+
fred = LowFish.new(name: "Fred")
|
98
|
+
id = fred.perform_create
|
99
|
+
assert_equal id, fred.id
|
100
|
+
refute_nil LowFish.collection.find({'name'=>"Fred"}).first
|
101
|
+
LowFish.collection.delete_one({'name'=>'Fred'})
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'Should create with custom id' do
|
105
|
+
dddd = LowFish.new(id: "dddd", name: "tom")
|
106
|
+
id = dddd.perform_create
|
107
|
+
assert_equal "dddd", id
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'Should update' do
|
111
|
+
jason = LowFish.new(name: "jason")
|
112
|
+
jason.perform_create
|
113
|
+
jason.name = "billy"
|
114
|
+
jason.perform_update
|
115
|
+
assert_equal "billy", LowFish.collection.find({'_id'=> jason.id}).first['name']
|
116
|
+
end
|
117
|
+
|
118
|
+
it "Should get correct item" do
|
119
|
+
jackson_id = LowFish.new(name: "jackson").perform_create
|
120
|
+
assert_equal "jackson", LowFish.admin_get(jackson_id).name
|
121
|
+
assert_equal "jackson", LowFish.admin_get(jackson_id.to_s).name
|
122
|
+
assert_nil LowFish.admin_get("nonexistentid")
|
123
|
+
|
124
|
+
regular_fish_id = LowFish.new(id: 87, name: "regular").perform_create
|
125
|
+
# need to test with .to_s
|
126
|
+
assert_equal "regular", LowFish.admin_get(regular_fish_id).name
|
127
|
+
end
|
128
|
+
|
129
|
+
it "Should get multiple items" do
|
130
|
+
# Order is not respected
|
131
|
+
alpha_id = LowFish.new(name: "alpha").perform_create
|
132
|
+
beta_id = LowFish.new(name: "beta").perform_create
|
133
|
+
gamma_id = LowFish.new(name: "gamma").perform_create
|
134
|
+
items = LowFish.admin_get([alpha_id, beta_id, nil, alpha_id])
|
135
|
+
assert items.is_a?(Array)
|
136
|
+
assert_equal 2, items.count
|
137
|
+
refute_nil items.find{|i| i.id == alpha_id}
|
138
|
+
refute_nil items.find{|i| i.id == beta_id}
|
139
|
+
assert_nil items.find{|i| i.id == gamma_id}
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'Should have the [] shortcut for admin_get' do
|
143
|
+
LowFish.collection.insert_one(_id: 42, name: "H2G2")
|
144
|
+
assert_equal LowFish[42], LowFish.admin_get(42)
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'Should admin_find correctly' do
|
148
|
+
LowFish.collection.insert_one(_id: 10, name: "Arya")
|
149
|
+
LowFish.collection.insert_one(_id: 20, name: "Bran")
|
150
|
+
LowFish.collection.insert_one(_id: 30, name: "Arya")
|
151
|
+
LowFish.collection.insert_one(_id: 40, name: "Bran")
|
152
|
+
items = LowFish.admin_find
|
153
|
+
assert items.is_a?(Array)
|
154
|
+
assert_equal 4, items.count
|
155
|
+
assert_equal 10, items[0].id
|
156
|
+
items = LowFish.admin_find query: {name: 'Bran'}
|
157
|
+
assert items.is_a?(Array)
|
158
|
+
assert 2, items.count
|
159
|
+
assert_equal 20, items[0].id
|
160
|
+
end
|
161
|
+
|
162
|
+
it 'Should admin_find_first correctly' do
|
163
|
+
LowFish.collection.insert_one(_id: 10, name: "Arya")
|
164
|
+
LowFish.collection.insert_one(_id: 20, name: "Bran")
|
165
|
+
LowFish.collection.insert_one(_id: 30, name: "Arya")
|
166
|
+
LowFish.collection.insert_one(_id: 40, name: "Bran")
|
167
|
+
item = LowFish.admin_find_first
|
168
|
+
assert_equal 10, item.id
|
169
|
+
item = LowFish.admin_find_first query: {name: "Bran"}
|
170
|
+
assert_equal 20, item.id
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'Should admin_find while turning fields option into a projection option' do
|
174
|
+
LowFish.collection.insert_one(_id: 42, name: "John", lastname: "Doe")
|
175
|
+
found = LowFish.admin_find(query: {lastname: "Doe"}, fields: ['_id', 'lastname'])[0]
|
176
|
+
assert_equal 42, found.id
|
177
|
+
assert_nil found.name
|
178
|
+
end
|
179
|
+
|
180
|
+
it 'Should delete' do
|
181
|
+
herbert = LowFish.new(name: "herbert")
|
182
|
+
herbert.perform_create
|
183
|
+
refute_nil LowFish.collection.find({"_id"=> herbert.id}).first
|
184
|
+
herbert.perform_delete
|
185
|
+
assert_nil LowFish.collection.find({"_id"=> herbert.id}).first
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'Should not save to the @@documents class variable' do
|
189
|
+
LowFish.collection.insert_one(_id: 42, name: "H2G2")
|
190
|
+
assert_equal [], LowFish.documents
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
describe 'High level CRUD' do
|
196
|
+
|
197
|
+
it 'Should use callbacks' do
|
198
|
+
danny = CatFish.new(name: "danny")
|
199
|
+
assert_nil danny.id
|
200
|
+
assert danny.new?
|
201
|
+
danny.save
|
202
|
+
refute_nil danny.id
|
203
|
+
refute danny.new?
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
describe 'Default Sorting' do
|
209
|
+
|
210
|
+
class MongoSoldier < PopulateMe::Mongo
|
211
|
+
field :name
|
212
|
+
field :position
|
213
|
+
end
|
214
|
+
|
215
|
+
before do
|
216
|
+
MongoSoldier.collection.drop
|
217
|
+
MongoSoldier.new(name: 'Bob', position: 2).perform_create
|
218
|
+
MongoSoldier.new(name: 'Albert', position: 3).perform_create
|
219
|
+
MongoSoldier.new(name: 'Tony', position: 1).perform_create
|
220
|
+
end
|
221
|
+
|
222
|
+
it 'Uses Doc::sort_by to determine the order' do
|
223
|
+
assert_equal 'Albert', MongoSoldier.sort_by(:name).admin_find[0].name
|
224
|
+
assert_equal 'Tony', MongoSoldier.sort_by(:name,:desc).admin_find[0].name
|
225
|
+
assert_equal 1, MongoSoldier.sort_by(:position).admin_find[0].position
|
226
|
+
assert_raises(ArgumentError) do
|
227
|
+
MongoSoldier.sort_by(:name,0)
|
228
|
+
end
|
229
|
+
assert_raises(ArgumentError) do
|
230
|
+
MongoSoldier.sort_by(:namespace)
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
it 'Can write Mongo-specific sort if a Hash or an Array is passed' do
|
235
|
+
assert_equal 'Tony', MongoSoldier.sort_by([[:name, -1]]).admin_find[0].name
|
236
|
+
assert_equal 'Tony', MongoSoldier.sort_by({name: -1}).admin_find[0].name
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
describe 'Manual Sorting' do
|
242
|
+
|
243
|
+
class MongoChampion < PopulateMe::Mongo
|
244
|
+
field :position
|
245
|
+
field :reversed, direction: :desc
|
246
|
+
end
|
247
|
+
|
248
|
+
before do
|
249
|
+
MongoChampion.collection.drop
|
250
|
+
MongoChampion.new(id: 'a').perform_create
|
251
|
+
MongoChampion.new(id: 'b').perform_create
|
252
|
+
MongoChampion.new(id: 'c').perform_create
|
253
|
+
end
|
254
|
+
|
255
|
+
it 'Sets the indexes on the provided field' do
|
256
|
+
MongoChampion.set_indexes(:position,['b','a','c'])
|
257
|
+
assert_equal 1, MongoChampion.admin_get('a').position
|
258
|
+
assert_equal 0, MongoChampion.admin_get('b').position
|
259
|
+
assert_equal 2, MongoChampion.admin_get('c').position
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'Sets the indexes taking direction into account' do
|
263
|
+
MongoChampion.set_indexes(:reversed,['b','a','c'])
|
264
|
+
assert_equal 1, MongoChampion.admin_get('a').reversed
|
265
|
+
assert_equal 2, MongoChampion.admin_get('b').reversed
|
266
|
+
assert_equal 0, MongoChampion.admin_get('c').reversed
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'Sets the indexes correctly even if some ids are not string' do
|
270
|
+
MongoChampion.collection.drop
|
271
|
+
MongoChampion.new(id: 'a').perform_create
|
272
|
+
MongoChampion.new(id: BSON::ObjectId.from_string("507f1f77bcf86cd799439011")).perform_create
|
273
|
+
MongoChampion.new(id: BSON::ObjectId.from_string("507f191e810c19729de860ea")).perform_create
|
274
|
+
MongoChampion.set_indexes(:position,["507f1f77bcf86cd799439011",'a',"507f191e810c19729de860ea"])
|
275
|
+
assert_equal 0, MongoChampion.admin_get("507f1f77bcf86cd799439011").position
|
276
|
+
assert_equal 1, MongoChampion.admin_get('a').position
|
277
|
+
assert_equal 2, MongoChampion.admin_get("507f191e810c19729de860ea").position
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
describe '::admin_distinct' do
|
282
|
+
|
283
|
+
class MongoDistinction < PopulateMe::Mongo
|
284
|
+
attr_accessor :title, :age
|
285
|
+
end
|
286
|
+
|
287
|
+
before do
|
288
|
+
MongoDistinction.collection.drop
|
289
|
+
end
|
290
|
+
|
291
|
+
it 'Can list all distinct values' do
|
292
|
+
MongoDistinction.new(title: 'Lord').save
|
293
|
+
MongoDistinction.new(title: 'Lord').save
|
294
|
+
MongoDistinction.new.save
|
295
|
+
MongoDistinction.new(title: 'Chevalier').save
|
296
|
+
MongoDistinction.new(title: 'Baron').save
|
297
|
+
MongoDistinction.new(title: 'Baron').save
|
298
|
+
result = MongoDistinction.admin_distinct :title
|
299
|
+
assert_instance_of Array, result
|
300
|
+
assert_equal 3, result.size
|
301
|
+
assert_includes result, 'Lord'
|
302
|
+
assert_includes result, 'Chevalier'
|
303
|
+
assert_includes result, 'Baron'
|
304
|
+
end
|
305
|
+
|
306
|
+
it 'Can list all distinct values for a specific selector' do
|
307
|
+
MongoDistinction.new(title: 'Chevalier', age: 33).save
|
308
|
+
MongoDistinction.new(title: 'Chevalier', age: 34).save
|
309
|
+
MongoDistinction.new(title: 'Baron', age: 35).save
|
310
|
+
MongoDistinction.new(title: 'Baron', age: 36).save
|
311
|
+
result = MongoDistinction.admin_distinct :age, query: {title: 'Baron'}
|
312
|
+
assert_instance_of Array, result
|
313
|
+
assert_equal 2, result.size
|
314
|
+
assert_includes result, 35
|
315
|
+
assert_includes result, 36
|
316
|
+
end
|
317
|
+
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
DB.drop
|
323
|
+
OTHER_DB.drop
|
324
|
+
|
@@ -0,0 +1,281 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'populate_me/document'
|
3
|
+
require 'populate_me/s3_attachment'
|
4
|
+
|
5
|
+
s3_resource = Aws::S3::Resource.new
|
6
|
+
s3_bucket = s3_resource.bucket(ENV['BUCKET'])
|
7
|
+
PopulateMe::Document.set :default_attachment_class, PopulateMe::S3Attachment
|
8
|
+
PopulateMe::S3Attachment.set :bucket, s3_bucket
|
9
|
+
|
10
|
+
describe 'PopulateMe::S3Attachment' do
|
11
|
+
# parallelize_me!
|
12
|
+
|
13
|
+
def check_if_public_read(object)
|
14
|
+
grant = object.acl.grants.find do |g|
|
15
|
+
g.grantee.uri=="http://acs.amazonaws.com/groups/global/AllUsers"
|
16
|
+
end
|
17
|
+
raise "grant not found" if grant.nil?
|
18
|
+
['READ','FULL_CONTROL'].include? grant.permission
|
19
|
+
end
|
20
|
+
|
21
|
+
class S3Book < PopulateMe::Document
|
22
|
+
field :cover, type: :attachment, variations: [
|
23
|
+
PopulateMe::Variation.new_image_magick_job(:thumb, :gif, "-resize '300x'")
|
24
|
+
]
|
25
|
+
field :content, type: :attachment, variations: [
|
26
|
+
PopulateMe::Variation.new(:upcase, :txt, lambda{ |src,dst|
|
27
|
+
Kernel.system "cat \"#{src}\" | tr 'a-z' 'A-Z' > \"#{dst}\""
|
28
|
+
})
|
29
|
+
]
|
30
|
+
field :open_content, type: :attachment, url_prefix: 'open', variations: [
|
31
|
+
PopulateMe::Variation.new(:upcase, :txt, lambda{ |src,dst|
|
32
|
+
Kernel.system "cat \"#{src}\" | tr 'a-z' 'A-Z' > \"#{dst}\""
|
33
|
+
})
|
34
|
+
]
|
35
|
+
end
|
36
|
+
|
37
|
+
class S3BookNoPrefix < PopulateMe::Document
|
38
|
+
set :s3_url_prefix, ''
|
39
|
+
field :content, type: :attachment, variations: [
|
40
|
+
PopulateMe::Variation.new(:upcase, :txt, lambda{ |src,dst|
|
41
|
+
Kernel.system "cat \"#{src}\" | tr 'a-z' 'A-Z' > \"#{dst}\""
|
42
|
+
})
|
43
|
+
]
|
44
|
+
end
|
45
|
+
|
46
|
+
before do
|
47
|
+
s3_bucket.clear!
|
48
|
+
end
|
49
|
+
|
50
|
+
# Utils
|
51
|
+
|
52
|
+
it 'Returns URL with bucket url' do
|
53
|
+
book = S3Book.new cover: "candy.jpg"
|
54
|
+
assert_equal "#{s3_bucket.url}/candy.jpg", book.attachment(:cover).url
|
55
|
+
assert_equal "#{s3_bucket.url}/candy.thumb.gif", book.attachment(:cover).url(:thumb)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'Has nil URL when field is blank' do
|
59
|
+
book = S3Book.new
|
60
|
+
assert_nil book.attachment(:cover).url
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'Has location root without attachee prefix' do
|
64
|
+
book = S3Book.new
|
65
|
+
refute_match book.attachment(:cover).attachee_prefix, book.attachment(:cover).location_root
|
66
|
+
end
|
67
|
+
|
68
|
+
# Create
|
69
|
+
|
70
|
+
it "Saves attachments on create with variations" do
|
71
|
+
book = S3Book.new
|
72
|
+
|
73
|
+
file = Tempfile.new('foo')
|
74
|
+
file.write('hello')
|
75
|
+
file.rewind
|
76
|
+
|
77
|
+
field_value = book.attachment(:content).create({
|
78
|
+
tempfile: file,
|
79
|
+
filename: 'story.txt',
|
80
|
+
type: 'text/plain'
|
81
|
+
})
|
82
|
+
assert_equal 'public/s-3-book/story.txt', field_value
|
83
|
+
assert s3_bucket.object('public/s-3-book/story.txt').exists?
|
84
|
+
assert s3_bucket.object('public/s-3-book/story.upcase.txt').exists?
|
85
|
+
|
86
|
+
s3file = s3_bucket.object('public/s-3-book/story.txt')
|
87
|
+
assert_equal 'text/plain', s3file.content_type
|
88
|
+
assert check_if_public_read(s3file)
|
89
|
+
assert_equal 's-3-book', s3file.metadata['parent_collection']
|
90
|
+
assert_equal 'hello', s3file.get.body.read
|
91
|
+
|
92
|
+
vars3file = s3_bucket.object('public/s-3-book/story.upcase.txt')
|
93
|
+
assert_equal 'text/plain', vars3file.content_type
|
94
|
+
assert check_if_public_read(vars3file)
|
95
|
+
assert_equal 's-3-book', vars3file.metadata['parent_collection']
|
96
|
+
assert_equal 'HELLO', vars3file.get.body.read
|
97
|
+
|
98
|
+
file.close
|
99
|
+
file.unlink
|
100
|
+
end
|
101
|
+
|
102
|
+
it "Can override the url_prefix at document class level" do
|
103
|
+
file = Tempfile.new('foo')
|
104
|
+
book = S3BookNoPrefix.new
|
105
|
+
|
106
|
+
field_value = book.attachment(:content).create({
|
107
|
+
tempfile: file,
|
108
|
+
filename: 'story.txt',
|
109
|
+
type: 'text/plain'
|
110
|
+
})
|
111
|
+
|
112
|
+
assert_equal 's-3-book-no-prefix/story.txt', field_value
|
113
|
+
assert s3_bucket.object('s-3-book-no-prefix/story.txt').exists?
|
114
|
+
assert s3_bucket.object('s-3-book-no-prefix/story.upcase.txt').exists?
|
115
|
+
end
|
116
|
+
|
117
|
+
it "Can override the url_prefix at field level" do
|
118
|
+
file = Tempfile.new('foo')
|
119
|
+
book = S3Book.new
|
120
|
+
|
121
|
+
field_value = book.attachment(:open_content).create({
|
122
|
+
tempfile: file,
|
123
|
+
filename: 'story.txt',
|
124
|
+
type: 'text/plain'
|
125
|
+
})
|
126
|
+
|
127
|
+
assert_equal 'open/s-3-book/story.txt', field_value
|
128
|
+
assert s3_bucket.object('open/s-3-book/story.txt').exists?
|
129
|
+
assert s3_bucket.object('open/s-3-book/story.upcase.txt').exists?
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'Does not create 2 files with the same name' do
|
133
|
+
file = Tempfile.new('foo')
|
134
|
+
|
135
|
+
book = S3Book.new
|
136
|
+
|
137
|
+
field_value = book.attachment(:content).create({
|
138
|
+
tempfile: file,
|
139
|
+
filename: 'story.txt',
|
140
|
+
type: 'text/plain'
|
141
|
+
})
|
142
|
+
|
143
|
+
assert_equal 'public/s-3-book/story.txt', field_value
|
144
|
+
|
145
|
+
field_value = book.attachment(:content).create({
|
146
|
+
tempfile: file,
|
147
|
+
filename: 'story.txt',
|
148
|
+
type: 'text/plain'
|
149
|
+
})
|
150
|
+
|
151
|
+
assert_equal 'public/s-3-book/story-1.txt', field_value
|
152
|
+
|
153
|
+
field_value = book.attachment(:content).create({
|
154
|
+
tempfile: file,
|
155
|
+
filename: 'story.txt',
|
156
|
+
type: 'text/plain'
|
157
|
+
})
|
158
|
+
|
159
|
+
assert_equal 'public/s-3-book/story-2.txt', field_value
|
160
|
+
|
161
|
+
file.close
|
162
|
+
file.unlink
|
163
|
+
end
|
164
|
+
|
165
|
+
# Delete
|
166
|
+
|
167
|
+
it 'Is deletable when field is not blank' do
|
168
|
+
book = S3Book.new cover: "candy.jpg"
|
169
|
+
assert book.attachment(:cover).deletable?
|
170
|
+
end
|
171
|
+
|
172
|
+
it 'Is not deletable when field is blank' do
|
173
|
+
book = S3Book.new
|
174
|
+
refute book.attachment(:cover).deletable?
|
175
|
+
end
|
176
|
+
|
177
|
+
it 'Deletes all attachments' do
|
178
|
+
file = Tempfile.new('foo')
|
179
|
+
|
180
|
+
book = S3Book.new
|
181
|
+
|
182
|
+
field_value = book.attachment(:content).create({
|
183
|
+
tempfile: file,
|
184
|
+
filename: 'story.txt',
|
185
|
+
type: 'text/plain'
|
186
|
+
})
|
187
|
+
book.content = field_value
|
188
|
+
|
189
|
+
assert s3_bucket.object('public/s-3-book/story.txt').exists?
|
190
|
+
assert s3_bucket.object('public/s-3-book/story.upcase.txt').exists?
|
191
|
+
|
192
|
+
book.attachment(:content).delete_all
|
193
|
+
|
194
|
+
refute s3_bucket.object('public/s-3-book/story.txt').exists?
|
195
|
+
refute s3_bucket.object('public/s-3-book/story.upcase.txt').exists?
|
196
|
+
|
197
|
+
file.close
|
198
|
+
file.unlink
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'Deletes one attachment at a time' do
|
202
|
+
file = Tempfile.new('foo')
|
203
|
+
|
204
|
+
book = S3Book.new
|
205
|
+
|
206
|
+
field_value = book.attachment(:content).create({
|
207
|
+
tempfile: file,
|
208
|
+
filename: 'story.txt',
|
209
|
+
type: 'text/plain'
|
210
|
+
})
|
211
|
+
book.content = field_value
|
212
|
+
|
213
|
+
assert s3_bucket.object('public/s-3-book/story.txt').exists?
|
214
|
+
assert s3_bucket.object('public/s-3-book/story.upcase.txt').exists?
|
215
|
+
|
216
|
+
book.attachment(:content).delete
|
217
|
+
|
218
|
+
refute s3_bucket.object('public/s-3-book/story.txt').exists?
|
219
|
+
assert s3_bucket.object('public/s-3-book/story.upcase.txt').exists?
|
220
|
+
|
221
|
+
book.attachment(:content).delete :upcase
|
222
|
+
|
223
|
+
refute s3_bucket.object('public/s-3-book/story.upcase.txt').exists?
|
224
|
+
|
225
|
+
file.close
|
226
|
+
file.unlink
|
227
|
+
end
|
228
|
+
|
229
|
+
# Update
|
230
|
+
|
231
|
+
it 'Deletes previous attachment when saving a new one' do
|
232
|
+
file = Tempfile.new('foo')
|
233
|
+
file.write('hello')
|
234
|
+
file.rewind
|
235
|
+
|
236
|
+
book = S3Book.new
|
237
|
+
|
238
|
+
field_value = book.attachment(:content).create({
|
239
|
+
tempfile: file,
|
240
|
+
filename: 'story.txt',
|
241
|
+
type: 'text/plain'
|
242
|
+
})
|
243
|
+
book.content = field_value
|
244
|
+
|
245
|
+
assert s3_bucket.object('public/s-3-book/story.txt').exists?
|
246
|
+
assert s3_bucket.object('public/s-3-book/story.upcase.txt').exists?
|
247
|
+
|
248
|
+
file.rewind
|
249
|
+
file.write('world')
|
250
|
+
file.rewind
|
251
|
+
|
252
|
+
field_value = book.attachment(:content).create({
|
253
|
+
tempfile: file,
|
254
|
+
filename: 'history.md',
|
255
|
+
type: 'text/markdown'
|
256
|
+
})
|
257
|
+
book.content = field_value
|
258
|
+
|
259
|
+
refute s3_bucket.object('public/s-3-book/story.txt').exists?
|
260
|
+
refute s3_bucket.object('public/s-3-book/story.upcase.txt').exists?
|
261
|
+
assert s3_bucket.object('public/s-3-book/history.md').exists?
|
262
|
+
assert s3_bucket.object('public/s-3-book/history.upcase.txt').exists?
|
263
|
+
|
264
|
+
s3file = s3_bucket.object('public/s-3-book/history.md')
|
265
|
+
assert_equal 'text/markdown', s3file.content_type
|
266
|
+
assert_equal 's-3-book', s3file.metadata['parent_collection']
|
267
|
+
assert_equal 'world', s3file.get.body.read
|
268
|
+
|
269
|
+
s3file = s3_bucket.object('public/s-3-book/history.upcase.txt')
|
270
|
+
assert_equal 'text/plain', s3file.content_type
|
271
|
+
assert_equal 's-3-book', s3file.metadata['parent_collection']
|
272
|
+
assert_equal 'WORLD', s3file.get.body.read
|
273
|
+
|
274
|
+
file.close
|
275
|
+
file.unlink
|
276
|
+
end
|
277
|
+
|
278
|
+
end
|
279
|
+
|
280
|
+
s3_bucket.clear!
|
281
|
+
|