ladder 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +3 -1
- data/README.md +133 -110
- data/ladder.gemspec +6 -5
- data/lib/ladder/file.rb +15 -17
- data/lib/ladder/resource.rb +32 -22
- data/lib/ladder/resource/dynamic.rb +43 -49
- data/lib/ladder/resource/serializable.rb +54 -0
- data/lib/ladder/searchable.rb +5 -4
- data/lib/ladder/searchable/background.rb +43 -0
- data/lib/ladder/searchable/resource.rb +5 -64
- data/lib/ladder/version.rb +1 -1
- data/spec/ladder/file_spec.rb +53 -6
- data/spec/ladder/resource/dynamic_spec.rb +117 -115
- data/spec/ladder/resource_spec.rb +273 -8
- data/spec/ladder/searchable/background_spec.rb +112 -0
- data/spec/ladder/{file/searchable_spec.rb → searchable/file_spec.rb} +6 -26
- data/spec/ladder/searchable/resource_spec.rb +83 -0
- data/spec/shared/file.rb +8 -52
- data/spec/shared/resource.rb +54 -272
- data/spec/shared/searchable/file.rb +50 -0
- data/spec/shared/searchable/resource.rb +223 -0
- data/spec/spec_helper.rb +1 -0
- metadata +55 -33
- data/spec/ladder/resource/searchable_spec.rb +0 -221
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e349ffdb2f8ef8f274a8f9f00e0b45c3f46b4a70
|
4
|
+
data.tar.gz: 1c2122ef4ef2b18dc2ff74ac2ce59a7e5d5e38fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63cb325392cdd3525780f8a46c75c5c0a7e70b94521bb23aea92a44e984fdcdc3596304609502add4911e80c22c369b409d2a8f4803ab3196510369e9d01573c
|
7
|
+
data.tar.gz: b3654ba928cc613c5eb12955c1c29593215434de4a2cede575b4d6d3788fda62b715677f3c6b85ebae52558d5c38d33f8d44319621aa96bc37af636e80b66672
|
data/.travis.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
language: ruby
|
2
2
|
cache: bundler
|
3
|
-
sudo: false
|
3
|
+
#sudo: false
|
4
4
|
rvm:
|
5
5
|
- 1.9.3
|
6
6
|
- 2.1.1
|
@@ -13,4 +13,6 @@ services:
|
|
13
13
|
- mongodb
|
14
14
|
- elasticsearch
|
15
15
|
before_script:
|
16
|
+
- sudo /usr/share/elasticsearch/bin/plugin -install elasticsearch/elasticsearch-mapper-attachments/2.4.1
|
17
|
+
- sudo service elasticsearch restart
|
16
18
|
- sleep 15
|
data/README.md
CHANGED
@@ -1,24 +1,23 @@
|
|
1
1
|
![Ladder logo](https://github.com/ladder/ladder/blob/master/logo.png)
|
2
2
|
|
3
|
-
[![Gem Version](http://img.shields.io/gem/v/ladder.svg)](https://rubygems.org/gems/ladder) [![Build Status](https://travis-ci.org/ladder/ladder.svg)](https://travis-ci.org/ladder/ladder)
|
3
|
+
[![Gem Version](http://img.shields.io/gem/v/ladder.svg)](https://rubygems.org/gems/ladder) [![Inline docs](http://inch-ci.org/github/ladder/ladder.svg?branch=master)](http://inch-ci.org/github/ladder/ladder) [![Build Status](https://travis-ci.org/ladder/ladder.svg)](https://travis-ci.org/ladder/ladder)
|
4
4
|
|
5
5
|
# Ladder
|
6
6
|
|
7
|
-
Ladder is a dynamic [Linked Data](http://en.wikipedia.org/wiki/Linked_data)
|
7
|
+
Ladder is a dynamic framework for [Linked Data](http://en.wikipedia.org/wiki/Linked_data) modelling, persistence, and full-text indexing. It is implemented as a series of Ruby modules that can be used individually and incorporated within existing ActiveModel frameworks (eg. [Project Hydra](http://projecthydra.org)), or combined as a comprehensive stack.
|
8
8
|
|
9
|
-
|
9
|
+
Ladder is intended to encourage the [GLAM](http://en.wikipedia.org/wiki/GLAM_(industry_sector)) community to think less dogmatically about established (often monolithic and/or niche) tools and instead embrace a broader vision of adopting more widely-used technologies.
|
10
10
|
|
11
|
-
|
11
|
+
### Components
|
12
12
|
|
13
|
-
|
13
|
+
- [Mongoid](http://mongoid.org) for persistence
|
14
|
+
- [ElasticSearch](http://www.elasticsearch.org) for full-text indexing
|
15
|
+
- [ActiveTriples](https://github.com/no-reply/ActiveTriples) for linked data
|
16
|
+
- [ActiveJob](https://github.com/rails/rails/tree/master/activejob) for background job execution
|
14
17
|
|
15
|
-
##
|
18
|
+
## History
|
16
19
|
|
17
|
-
|
18
|
-
- Full-text indexing ([ElasticSearch](http://www.elasticsearch.org))
|
19
|
-
- RDF ([ActiveTriples](https://github.com/no-reply/ActiveTriples)/RDF.rb)
|
20
|
-
- Asynchronous job execution ([Sidekiq](http://sidekiq.org)/Redis)
|
21
|
-
- HTTP interaction ([Padrino](http://www.padrinorb.com)/Sinatra)
|
20
|
+
Ladder was loosely conceived over the course of several years prior to 2011. In early 2012, Ladder began existence as an opportunity to escape from a decade of LAMP development and become familiar with Ruby. From 2012 to late 2013, a closed prototype was built under the auspices of [Deliberate Data](http://deliberatedata.com) as a proof-of-concept to test the feasibility of the design. For those interested in the historical code, the original [prototype](https://github.com/ladder/ladder/tree/prototype) branch is available, as is an [experimental](https://github.com/ladder/ladder/tree/l2) branch.
|
22
21
|
|
23
22
|
## Installation
|
24
23
|
|
@@ -41,9 +40,11 @@ Or install it yourself as:
|
|
41
40
|
* [Resources](#resources)
|
42
41
|
* [Configuring Resources](#configuring-resources)
|
43
42
|
* [Dynamic Resources](#dynamic-resources)
|
44
|
-
* [Indexing for Search](#indexing-for-search)
|
45
43
|
* [Files](#files)
|
44
|
+
* [Indexing](#indexing)
|
45
|
+
* [Indexing Resources](#indexing-resources)
|
46
46
|
* [Indexing Files](#indexing-files)
|
47
|
+
* [Background Indexing](#background-indexing)
|
47
48
|
|
48
49
|
### Resources
|
49
50
|
|
@@ -341,35 +342,101 @@ steve.as_jsonld
|
|
341
342
|
# }
|
342
343
|
```
|
343
344
|
|
344
|
-
Note that due to the way Mongoid handles dynamic fields, dynamic properties **can not** be localized. They can be any kind of literal, but they **can not** be a related object. They can, however, contain
|
345
|
+
Note that due to the way Mongoid handles dynamic fields, dynamic properties **can not** be localized. They can be any kind of literal, but they **can not** be a related object. They can, however, contain the related object's URI.
|
345
346
|
|
346
|
-
###
|
347
|
+
### Files
|
347
348
|
|
348
|
-
|
349
|
+
Files are bytestreams that store binary content using MongoDB's GridFS storage system. They are still identifiable by a URI, and contain technical metadata about the File's contents.
|
349
350
|
|
350
351
|
```ruby
|
351
352
|
class Person
|
352
353
|
include Ladder::Resource
|
353
|
-
include Ladder::Searchable
|
354
354
|
|
355
355
|
configure type: RDF::FOAF.Person
|
356
356
|
|
357
357
|
property :first_name, predicate: RDF::FOAF.name
|
358
|
-
property :
|
358
|
+
property :thumbnails, predicate: RDF::FOAF.depiction, class_name: 'Image', inverse_of: nil
|
359
359
|
end
|
360
360
|
|
361
|
-
|
362
|
-
|
361
|
+
class Image
|
362
|
+
include Ladder::File
|
363
|
+
end
|
363
364
|
```
|
364
365
|
|
365
|
-
|
366
|
+
Similar to Resources, using `#property` will create a has-many relation for a File by default; however, because Files must be the target of a one-way relation, the `inverse_of: nil` option is required. Note that due to the way GridFS is designed, Files **can not** be embedded.
|
366
367
|
|
367
368
|
```ruby
|
368
|
-
Person.
|
369
|
-
=> :
|
369
|
+
steve = Person.new(first_name: 'Steve')
|
370
|
+
=> #<Person _id: 549d83c64169720b32010000, first_name: {"en"=>"Steve"}>
|
370
371
|
|
371
|
-
|
372
|
-
=>
|
372
|
+
thumb = Image.new(file: open('http://some.image/pic.jpg'))
|
373
|
+
=> #<Image _id: 549d83c24169720b32000000>
|
374
|
+
|
375
|
+
steve.thumbnails << thumb
|
376
|
+
=> [#<Image _id: 549d83c24169720b32000000, >]
|
377
|
+
|
378
|
+
steve.as_jsonld
|
379
|
+
# => {
|
380
|
+
# "@context": {
|
381
|
+
# "foaf": "http://xmlns.com/foaf/0.1/"
|
382
|
+
# },
|
383
|
+
# "@id": "http://example.org/people/549d83c64169720b32010000",
|
384
|
+
# "@type": "foaf:Person",
|
385
|
+
# "foaf:depiction": {
|
386
|
+
# "@id": "http://example.org/images/549d83c24169720b32000000"
|
387
|
+
# },
|
388
|
+
# "foaf:name": {
|
389
|
+
# "@language": "en",
|
390
|
+
# "@value": "Steve"
|
391
|
+
# }
|
392
|
+
# }
|
393
|
+
|
394
|
+
steve.save
|
395
|
+
# ... File is stored to GridFS ...
|
396
|
+
=> true
|
397
|
+
```
|
398
|
+
|
399
|
+
Files have all the attributes of a GridFS file, and the stored binary content is accessed using `#data`.
|
400
|
+
|
401
|
+
```ruby
|
402
|
+
thumb.reload
|
403
|
+
=> #<Image _id: 549d86184169720b6a000000, >
|
404
|
+
|
405
|
+
thumb.as_document
|
406
|
+
=> {"_id"=>BSON::ObjectId('549d86184169720b6a000000'),
|
407
|
+
"length"=>59709,
|
408
|
+
"chunkSize"=>4194304,
|
409
|
+
"uploadDate"=>2014-12-26 16:00:29 UTC,
|
410
|
+
"md5"=>"0d4a486e2cd71c51b7a92cfe96f29324",
|
411
|
+
"contentType"=>"image/jpeg",
|
412
|
+
"filename"=>"549d86184169720b6a000000/open-uri20141226-2922-u66ap6"}
|
413
|
+
|
414
|
+
thumb.length
|
415
|
+
=> 59709
|
416
|
+
|
417
|
+
thumb.data
|
418
|
+
=> # ... binary data ...
|
419
|
+
```
|
420
|
+
|
421
|
+
### Indexing
|
422
|
+
|
423
|
+
#### Indexing Resources
|
424
|
+
|
425
|
+
You can index Resources for keyword searching by mixing in the Ladder::Searchable module:
|
426
|
+
|
427
|
+
```ruby
|
428
|
+
class Person
|
429
|
+
include Ladder::Resource
|
430
|
+
include Ladder::Searchable
|
431
|
+
|
432
|
+
configure type: RDF::FOAF.Person
|
433
|
+
|
434
|
+
property :first_name, predicate: RDF::FOAF.name
|
435
|
+
property :description, predicate: RDF::DC.description
|
436
|
+
end
|
437
|
+
|
438
|
+
kimchy = Person.new(first_name: 'Shay', description: 'Real genius')
|
439
|
+
=> #<Person _id: 543b457b41697231c5000000, first_name: {"en"=>"Shay"}, description: {"en"=>"Real genius"}>
|
373
440
|
|
374
441
|
kimchy.save
|
375
442
|
=> true
|
@@ -393,10 +460,10 @@ results.records.first == kimchy
|
|
393
460
|
=> true
|
394
461
|
```
|
395
462
|
|
396
|
-
When indexing, you can control how your model is stored in the index by supplying
|
463
|
+
When indexing, you can control how your model is stored in the index by calling `#index_for_search` and supplying a block that returns a serializable hash:
|
397
464
|
|
398
465
|
```ruby
|
399
|
-
Person.index_for_search
|
466
|
+
Person.index_for_search { as_jsonld }
|
400
467
|
=> :as_indexed_json
|
401
468
|
|
402
469
|
kimchy.as_indexed_json
|
@@ -417,7 +484,7 @@ kimchy.as_indexed_json
|
|
417
484
|
# }
|
418
485
|
# }
|
419
486
|
|
420
|
-
Person.index_for_search
|
487
|
+
Person.index_for_search { as_qname }
|
421
488
|
=> :as_indexed_json
|
422
489
|
|
423
490
|
kimchy.as_indexed_json
|
@@ -434,7 +501,7 @@ kimchy.as_indexed_json
|
|
434
501
|
# }
|
435
502
|
```
|
436
503
|
|
437
|
-
You can also index related objects as framed JSON-LD
|
504
|
+
You can also index related objects as framed JSON-LD using `#as_framed_jsonld` or by using the `related: true` option with `#as_qname`:
|
438
505
|
|
439
506
|
```ruby
|
440
507
|
class Project
|
@@ -456,10 +523,10 @@ es = Project.new(project_name: 'ElasticSearch', description: 'You know, for sear
|
|
456
523
|
es.developers << kimchy
|
457
524
|
=> [#<Person _id: 543b457b41697231c5000000, first_name: {"en"=>"Shay"}, description: {"en"=>"Real genius"}, project_ids: [BSON::ObjectId('544562c24169728b4e010000')]>]
|
458
525
|
|
459
|
-
Person.index_for_search
|
526
|
+
Person.index_for_search { as_framed_jsonld }
|
460
527
|
=> :as_indexed_json
|
461
528
|
|
462
|
-
Project.index_for_search
|
529
|
+
Project.index_for_search { as_framed_jsonld }
|
463
530
|
=> :as_indexed_json
|
464
531
|
|
465
532
|
kimchy.as_indexed_json
|
@@ -530,10 +597,10 @@ es.as_indexed_json
|
|
530
597
|
# }
|
531
598
|
# }
|
532
599
|
|
533
|
-
Person.index_for_search
|
600
|
+
Person.index_for_search { as_qname related: true }
|
534
601
|
=> :as_indexed_json
|
535
602
|
|
536
|
-
Project.index_for_search
|
603
|
+
Project.index_for_search { as_qname related: true }
|
537
604
|
=> :as_indexed_json
|
538
605
|
|
539
606
|
kimchy.as_indexed_json
|
@@ -587,83 +654,9 @@ es.as_indexed_json
|
|
587
654
|
# }
|
588
655
|
```
|
589
656
|
|
590
|
-
### Files
|
591
|
-
|
592
|
-
Files are bytestreams that store binary content using MongoDB's GridFS storage system. They are still identifiable by a URI, and contain technical metadata about the File's contents.
|
593
|
-
|
594
|
-
```ruby
|
595
|
-
class Person
|
596
|
-
include Ladder::Resource
|
597
|
-
|
598
|
-
configure type: RDF::FOAF.Person
|
599
|
-
|
600
|
-
property :first_name, predicate: RDF::FOAF.name
|
601
|
-
property :thumbnails, predicate: RDF::FOAF.depiction, class_name: 'Image', inverse_of: nil
|
602
|
-
end
|
603
|
-
|
604
|
-
class Image
|
605
|
-
include Ladder::File
|
606
|
-
end
|
607
|
-
```
|
608
|
-
|
609
|
-
Similar to Resources, using `#property` as above will create a has-many relation for a File by default; however, because Files must be the target of a one-way relation, the `inverse_of: nil` option is required. Note that due to the way GridFS is designed, Files **can not** be embedded.
|
610
|
-
|
611
|
-
```ruby
|
612
|
-
steve = Person.new(first_name: 'Steve')
|
613
|
-
=> #<Person _id: 549d83c64169720b32010000, first_name: {"en"=>"Steve"}>
|
614
|
-
|
615
|
-
thumb = Image.new(file: open('http://some.image/pic.jpg'))
|
616
|
-
=> #<Image _id: 549d83c24169720b32000000>
|
617
|
-
|
618
|
-
steve.thumbnails << thumb
|
619
|
-
=> [#<Image _id: 549d83c24169720b32000000, >]
|
620
|
-
|
621
|
-
steve.as_jsonld
|
622
|
-
# => {
|
623
|
-
# "@context": {
|
624
|
-
# "foaf": "http://xmlns.com/foaf/0.1/"
|
625
|
-
# },
|
626
|
-
# "@id": "http://example.org/people/549d83c64169720b32010000",
|
627
|
-
# "@type": "foaf:Person",
|
628
|
-
# "foaf:depiction": {
|
629
|
-
# "@id": "http://example.org/images/549d83c24169720b32000000"
|
630
|
-
# },
|
631
|
-
# "foaf:name": {
|
632
|
-
# "@language": "en",
|
633
|
-
# "@value": "Steve"
|
634
|
-
# }
|
635
|
-
# }
|
636
|
-
|
637
|
-
steve.save
|
638
|
-
# ... File is stored to GridFS ...
|
639
|
-
=> true
|
640
|
-
```
|
641
|
-
|
642
|
-
Files have all the attributes of a GridFS file, and the stored binary content is accessed using `#data`.
|
643
|
-
|
644
|
-
```ruby
|
645
|
-
thumb.reload
|
646
|
-
=> #<Image _id: 549d86184169720b6a000000, >
|
647
|
-
|
648
|
-
thumb.as_document
|
649
|
-
=> {"_id"=>BSON::ObjectId('549d86184169720b6a000000'),
|
650
|
-
"length"=>59709,
|
651
|
-
"chunkSize"=>4194304,
|
652
|
-
"uploadDate"=>2014-12-26 16:00:29 UTC,
|
653
|
-
"md5"=>"0d4a486e2cd71c51b7a92cfe96f29324",
|
654
|
-
"contentType"=>"image/jpeg",
|
655
|
-
"filename"=>"549d86184169720b6a000000/open-uri20141226-2922-u66ap6"}
|
656
|
-
|
657
|
-
thumb.length
|
658
|
-
=> 59709
|
659
|
-
|
660
|
-
thumb.data
|
661
|
-
=> # ... binary data ...
|
662
|
-
```
|
663
|
-
|
664
657
|
#### Indexing Files
|
665
658
|
|
666
|
-
Files that contain textual content (eg. HTML, PDF, ePub, DOC, etc) can be
|
659
|
+
Files that contain textual content (eg. HTML, PDF, ePub, DOC, etc) can be indexed when they are stored, again by mixing in the Ladder::Searchable module. This can be useful if you want to retrieve a File by searching for the textual content that it contains. Note that this requires the [Mapper Attachments Plugin for Elasticsearch](https://github.com/elasticsearch/elasticsearch-mapper-attachments) to be installed.
|
667
660
|
|
668
661
|
```ruby
|
669
662
|
class OCR
|
@@ -705,7 +698,7 @@ results.records.first.data
|
|
705
698
|
=> # ... binary data ...
|
706
699
|
```
|
707
700
|
|
708
|
-
|
701
|
+
Note the use of `#records` to access the Ladder::File instances directly ([see here for more information](https://github.com/elasticsearch/elasticsearch-rails/tree/master/elasticsearch-model#search-results-as-database-records)). However, if you want to get information about the file characteristics (including the extracted textual content), you can use a modified search query:
|
709
702
|
|
710
703
|
```ruby
|
711
704
|
results = OCR.search 'Moomintroll', fields: '*'
|
@@ -754,7 +747,37 @@ results.first.highlight.file
|
|
754
747
|
", but at the same time <em>his</em> nose caught a new smell. It was a more \nserious smell than any he had met"]
|
755
748
|
```
|
756
749
|
|
757
|
-
More information about
|
750
|
+
More information about highlighting queries is available in the [Elasticsearch documentation](http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/search-request-highlighting.html).
|
751
|
+
|
752
|
+
#### Background Indexing
|
753
|
+
|
754
|
+
In large-scale production environments, sending an HTTP request to Elasticsearch during the database transaction isn't optimal (especially for large Files), so Ladder uses ActiveJob to queue and process indexing operations in the background. Just use the Ladder::Searchable::Background module in your model:
|
755
|
+
|
756
|
+
```ruby
|
757
|
+
class OCR
|
758
|
+
include Ladder::File
|
759
|
+
include Ladder::Searchable::Background
|
760
|
+
end
|
761
|
+
|
762
|
+
# ...
|
763
|
+
|
764
|
+
class Person
|
765
|
+
include Ladder::Resource
|
766
|
+
include Ladder::Searchable::Background
|
767
|
+
|
768
|
+
configure type: RDF::FOAF.Person
|
769
|
+
end
|
770
|
+
|
771
|
+
# ...
|
772
|
+
```
|
773
|
+
|
774
|
+
You'll also have to set the queue adapter in your application, depending on which backend you're using:
|
775
|
+
|
776
|
+
```ruby
|
777
|
+
ActiveJob::Base.queue_adapter = :sidekiq
|
778
|
+
```
|
779
|
+
|
780
|
+
For more information on available queueing adapters and their features, see the [ActiveJob documentation](http://api.rubyonrails.org/classes/ActiveJob/QueueAdapters.html).
|
758
781
|
|
759
782
|
## Contributing
|
760
783
|
|
@@ -779,4 +802,4 @@ Many thanks to Christopher Knight [@NomadicKnight](https://twitter.com/Nomadic_K
|
|
779
802
|
## License
|
780
803
|
|
781
804
|
Apache License Version 2.0
|
782
|
-
http://apache.org/licenses/LICENSE-2.0.txt
|
805
|
+
http://apache.org/licenses/LICENSE-2.0.txt
|
data/ladder.gemspec
CHANGED
@@ -20,17 +20,18 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
21
|
spec.require_paths = ["lib"]
|
22
22
|
|
23
|
+
spec.add_dependency "active-triples", "~> 0.6"
|
24
|
+
spec.add_dependency "activejob", "~> 4.2"
|
25
|
+
spec.add_dependency "elasticsearch-model", "~> 0.1"
|
23
26
|
spec.add_dependency "mongoid", "~> 4.0"
|
24
27
|
spec.add_dependency "mongoid-grid_fs", "~> 2.1"
|
25
|
-
spec.add_dependency "active-triples", "~> 0.4"
|
26
|
-
spec.add_dependency "elasticsearch-model", "~> 0.1"
|
27
|
-
spec.add_dependency "mimemagic", "~> 0.2"
|
28
28
|
|
29
29
|
spec.add_development_dependency "bundler", "~> 1.7"
|
30
|
+
spec.add_development_dependency "mimemagic", "~> 0.2"
|
30
31
|
spec.add_development_dependency "pry", "~> 0.10"
|
31
|
-
spec.add_development_dependency "wirble", "~> 0.1"
|
32
32
|
spec.add_development_dependency "rspec", "~> 3.1"
|
33
33
|
spec.add_development_dependency "rake", "~> 10.4"
|
34
|
-
spec.add_development_dependency "yard", "~> 0.8"
|
35
34
|
spec.add_development_dependency "simplecov", "~> 0.9"
|
35
|
+
spec.add_development_dependency "wirble", "~> 0.1"
|
36
|
+
spec.add_development_dependency "yard", "~> 0.8"
|
36
37
|
end
|
data/lib/ladder/file.rb
CHANGED
@@ -10,7 +10,7 @@ module Ladder::File
|
|
10
10
|
included do
|
11
11
|
configure base_uri: RDF::URI.new(LADDER_BASE_URI) / name.underscore.pluralize if defined? LADDER_BASE_URI
|
12
12
|
|
13
|
-
store_in :
|
13
|
+
store_in collection: "#{ grid.prefix }.files"
|
14
14
|
|
15
15
|
# Define accessor methods for attributes
|
16
16
|
define_method(:content_type) { read_attribute(:contentType) }
|
@@ -18,24 +18,12 @@ module Ladder::File
|
|
18
18
|
grid::File.fields.keys.map(&:to_sym).each do |attr|
|
19
19
|
define_method(attr) { read_attribute(attr) }
|
20
20
|
end
|
21
|
-
end
|
22
|
-
|
23
|
-
attr_accessor :file
|
24
|
-
|
25
|
-
##
|
26
|
-
# Make save behave like Mongoid::Document as much as possible
|
27
|
-
def save
|
28
|
-
# FIXME: this raises on a freshly-retrieved document; should either set @file or catch @grid_file
|
29
|
-
raise Mongoid::Errors::InvalidValue.new(IO, NilClass) if file.nil?
|
30
21
|
|
31
|
-
|
32
|
-
|
33
|
-
run_callbacks(:save) do
|
34
|
-
attributes[:content_type] = file.content_type if file.respond_to? :content_type
|
35
|
-
@grid_file ? @grid_file.save : !! @grid_file = self.class.grid.put(file, attributes.symbolize_keys)
|
36
|
-
end
|
22
|
+
around_save :save_file
|
37
23
|
end
|
38
24
|
|
25
|
+
attr_accessor :file
|
26
|
+
|
39
27
|
##
|
40
28
|
# Output content of object from stored file or readable input
|
41
29
|
def data
|
@@ -51,6 +39,17 @@ module Ladder::File
|
|
51
39
|
def update_resource
|
52
40
|
resource
|
53
41
|
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
##
|
46
|
+
# Make save behave like Mongoid::Document as much as possible
|
47
|
+
def save_file(&block)
|
48
|
+
attributes[:content_type] = file.content_type if file.respond_to? :content_type
|
49
|
+
@grid_file ? @grid_file.save : !! @grid_file = self.class.grid.put(file, attributes.symbolize_keys)
|
50
|
+
|
51
|
+
persisted? ? run_callbacks(:update) : run_callbacks(:create)
|
52
|
+
end
|
54
53
|
|
55
54
|
module ClassMethods
|
56
55
|
##
|
@@ -58,7 +57,6 @@ module Ladder::File
|
|
58
57
|
def grid
|
59
58
|
@grid ||= Mongoid::GridFs.build_namespace_for name
|
60
59
|
end
|
61
|
-
|
62
60
|
end
|
63
61
|
|
64
62
|
end
|