dragonfly 0.9.15 → 1.0
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of dragonfly might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitignore +1 -8
- data/.travis.yml +11 -0
- data/Gemfile +1 -0
- data/History.md +52 -2
- data/LICENSE +1 -1
- data/README.md +38 -95
- data/dev/grid.jpg +0 -0
- data/dev/irbrc.rb +27 -0
- data/dev/rails_template.rb +38 -0
- data/dev/test.ru +56 -0
- data/dev/test_rails +19 -0
- data/dragonfly.gemspec +3 -21
- data/lib/dragonfly.rb +45 -44
- data/lib/dragonfly/app.rb +175 -96
- data/lib/dragonfly/configurable.rb +71 -170
- data/lib/dragonfly/content.rb +211 -0
- data/lib/dragonfly/core_ext/object.rb +1 -6
- data/lib/dragonfly/file_data_store.rb +197 -0
- data/lib/dragonfly/image_magick/analysers/image_properties.rb +23 -0
- data/lib/dragonfly/image_magick/generators/convert.rb +19 -0
- data/lib/dragonfly/image_magick/generators/plain.rb +26 -0
- data/lib/dragonfly/image_magick/generators/plasma.rb +25 -0
- data/lib/dragonfly/image_magick/generators/text.rb +127 -0
- data/lib/dragonfly/image_magick/plugin.rb +83 -0
- data/lib/dragonfly/image_magick/processors/convert.rb +29 -0
- data/lib/dragonfly/image_magick/processors/encode.rb +18 -0
- data/lib/dragonfly/image_magick/processors/thumb.rb +76 -0
- data/lib/dragonfly/job.rb +118 -134
- data/lib/dragonfly/job_endpoint.rb +2 -0
- data/lib/dragonfly/memory_data_store.rb +34 -0
- data/lib/dragonfly/middleware.rb +5 -3
- data/lib/dragonfly/{active_model_extensions.rb → model.rb} +5 -3
- data/lib/dragonfly/{active_model_extensions → model}/attachment.rb +40 -35
- data/lib/dragonfly/{active_model_extensions → model}/attachment_class_methods.rb +36 -40
- data/lib/dragonfly/model/class_methods.rb +109 -0
- data/lib/dragonfly/{active_model_extensions → model}/instance_methods.rb +2 -2
- data/lib/dragonfly/{active_model_extensions → model}/validations.rb +17 -12
- data/lib/dragonfly/railtie.rb +8 -6
- data/lib/dragonfly/register.rb +27 -0
- data/lib/dragonfly/response.rb +47 -52
- data/lib/dragonfly/routed_endpoint.rb +4 -0
- data/lib/dragonfly/serializer.rb +15 -5
- data/lib/dragonfly/server.rb +56 -29
- data/lib/dragonfly/shell.rb +12 -23
- data/lib/dragonfly/spec/data_store_examples.rb +64 -0
- data/lib/dragonfly/temp_object.rb +32 -47
- data/lib/dragonfly/url_attributes.rb +19 -22
- data/lib/dragonfly/url_mapper.rb +3 -0
- data/lib/dragonfly/utils.rb +12 -0
- data/lib/dragonfly/version.rb +1 -1
- data/lib/dragonfly/whitelist.rb +19 -0
- data/lib/rails/generators/dragonfly/USAGE +8 -0
- data/lib/rails/generators/dragonfly/dragonfly_generator.rb +24 -0
- data/lib/rails/generators/dragonfly/templates/initializer.rb.erb +27 -0
- data/samples/gif.gif +0 -0
- data/spec/dragonfly/app_spec.rb +270 -64
- data/spec/dragonfly/configurable_spec.rb +142 -418
- data/spec/dragonfly/content_spec.rb +353 -0
- data/spec/dragonfly/cookie_monster_spec.rb +2 -1
- data/spec/dragonfly/file_data_store_spec.rb +301 -0
- data/spec/dragonfly/image_magick/analysers/image_properties_spec.rb +20 -0
- data/spec/dragonfly/image_magick/generators/convert_spec.rb +19 -0
- data/spec/dragonfly/image_magick/generators/plain_spec.rb +50 -0
- data/spec/dragonfly/image_magick/generators/plasma_spec.rb +32 -0
- data/spec/dragonfly/image_magick/generators/text_spec.rb +77 -0
- data/spec/dragonfly/image_magick/plugin_spec.rb +131 -0
- data/spec/dragonfly/image_magick/processors/convert_spec.rb +56 -0
- data/spec/dragonfly/image_magick/processors/thumb_spec.rb +173 -0
- data/spec/dragonfly/job_endpoint_spec.rb +30 -73
- data/spec/dragonfly/job_spec.rb +280 -608
- data/spec/dragonfly/memory_data_store_spec.rb +20 -0
- data/spec/dragonfly/middleware_spec.rb +47 -27
- data/spec/dragonfly/{active_model_extensions → model}/model_spec.rb +331 -555
- data/spec/dragonfly/model/validations_spec.rb +196 -0
- data/spec/dragonfly/register_spec.rb +35 -0
- data/spec/dragonfly/routed_endpoint_spec.rb +6 -6
- data/spec/dragonfly/serializer_spec.rb +13 -15
- data/spec/dragonfly/server_spec.rb +122 -46
- data/spec/dragonfly/shell_spec.rb +43 -24
- data/spec/dragonfly/temp_object_spec.rb +69 -94
- data/spec/dragonfly/url_attributes_spec.rb +49 -0
- data/spec/dragonfly/utils_spec.rb +32 -0
- data/spec/dragonfly/whitelist_spec.rb +30 -0
- data/spec/dragonfly_spec.rb +43 -0
- data/spec/fixtures/deprecated_stored_content/eggs.bonus +1 -0
- data/spec/fixtures/deprecated_stored_content/eggs.bonus.meta +1 -0
- data/spec/functional/configuration_spec.rb +19 -0
- data/spec/functional/model_urls_spec.rb +43 -41
- data/spec/functional/remote_on_the_fly_spec.rb +14 -16
- data/spec/functional/shell_commands_spec.rb +24 -14
- data/spec/functional/to_response_spec.rb +10 -10
- data/spec/functional/urls_spec.rb +5 -3
- data/spec/spec_helper.rb +23 -28
- data/spec/support/argument_matchers.rb +7 -8
- data/spec/support/image_matchers.rb +14 -36
- data/spec/support/model_helpers.rb +97 -0
- data/spec/support/simple_matchers.rb +12 -0
- metadata +92 -393
- data/.yardopts +0 -29
- data/Rakefile +0 -36
- data/config.ru +0 -14
- data/docs.watchr +0 -1
- data/extra_docs/Analysers.md +0 -68
- data/extra_docs/Caching.md +0 -23
- data/extra_docs/Configuration.md +0 -149
- data/extra_docs/Couch.md +0 -49
- data/extra_docs/DataStorage.md +0 -226
- data/extra_docs/Encoding.md +0 -67
- data/extra_docs/ExampleUseCases.md +0 -116
- data/extra_docs/GeneralUsage.md +0 -105
- data/extra_docs/Generators.md +0 -68
- data/extra_docs/Heroku.md +0 -50
- data/extra_docs/ImageMagick.md +0 -136
- data/extra_docs/Index.md +0 -33
- data/extra_docs/MimeTypes.md +0 -40
- data/extra_docs/Models.md +0 -441
- data/extra_docs/Mongo.md +0 -42
- data/extra_docs/Processing.md +0 -77
- data/extra_docs/Rack.md +0 -52
- data/extra_docs/Rails2.md +0 -57
- data/extra_docs/Rails3.md +0 -56
- data/extra_docs/ServingRemotely.md +0 -104
- data/extra_docs/Sinatra.md +0 -25
- data/extra_docs/URLs.md +0 -203
- data/features/images.feature +0 -47
- data/features/no_processing.feature +0 -14
- data/features/rails.feature +0 -8
- data/features/steps/common_steps.rb +0 -8
- data/features/steps/dragonfly_steps.rb +0 -66
- data/features/steps/rails_steps.rb +0 -40
- data/features/support/env.rb +0 -13
- data/features/support/setup.rb +0 -41
- data/fixtures/rails/files/app/models/album.rb +0 -6
- data/fixtures/rails/files/app/views/albums/new.html.erb +0 -7
- data/fixtures/rails/files/app/views/albums/show.html.erb +0 -6
- data/fixtures/rails/files/config/initializers/dragonfly.rb +0 -4
- data/fixtures/rails/files/features/manage_album_images.feature +0 -38
- data/fixtures/rails/files/features/step_definitions/helper_steps.rb +0 -7
- data/fixtures/rails/files/features/step_definitions/image_steps.rb +0 -25
- data/fixtures/rails/files/features/step_definitions/web_steps.rb +0 -189
- data/fixtures/rails/files/features/support/paths.rb +0 -17
- data/fixtures/rails/files/features/text_images.feature +0 -7
- data/fixtures/rails/template.rb +0 -20
- data/irbrc.rb +0 -19
- data/lib/dragonfly/active_model_extensions/class_methods.rb +0 -98
- data/lib/dragonfly/analyser.rb +0 -58
- data/lib/dragonfly/analysis/file_command_analyser.rb +0 -33
- data/lib/dragonfly/analysis/image_magick_analyser.rb +0 -6
- data/lib/dragonfly/config/heroku.rb +0 -26
- data/lib/dragonfly/config/image_magick.rb +0 -6
- data/lib/dragonfly/config/rails.rb +0 -20
- data/lib/dragonfly/data_storage.rb +0 -11
- data/lib/dragonfly/data_storage/couch_data_store.rb +0 -83
- data/lib/dragonfly/data_storage/file_data_store.rb +0 -144
- data/lib/dragonfly/data_storage/mongo_data_store.rb +0 -96
- data/lib/dragonfly/data_storage/s3data_store.rb +0 -168
- data/lib/dragonfly/encoder.rb +0 -13
- data/lib/dragonfly/encoding/image_magick_encoder.rb +0 -6
- data/lib/dragonfly/function_manager.rb +0 -67
- data/lib/dragonfly/generation/image_magick_generator.rb +0 -6
- data/lib/dragonfly/generator.rb +0 -9
- data/lib/dragonfly/image_magick/analyser.rb +0 -53
- data/lib/dragonfly/image_magick/config.rb +0 -44
- data/lib/dragonfly/image_magick/encoder.rb +0 -57
- data/lib/dragonfly/image_magick/generator.rb +0 -147
- data/lib/dragonfly/image_magick/processor.rb +0 -114
- data/lib/dragonfly/image_magick/utils.rb +0 -46
- data/lib/dragonfly/image_magick_utils.rb +0 -4
- data/lib/dragonfly/job_builder.rb +0 -39
- data/lib/dragonfly/job_definitions.rb +0 -30
- data/lib/dragonfly/loggable.rb +0 -28
- data/lib/dragonfly/processing/image_magick_processor.rb +0 -6
- data/lib/dragonfly/processor.rb +0 -9
- data/lib/dragonfly/rails/images.rb +0 -32
- data/lib/dragonfly/simple_cache.rb +0 -23
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +0 -95
- data/spec/dragonfly/analyser_spec.rb +0 -123
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +0 -49
- data/spec/dragonfly/data_storage/couch_data_store_spec.rb +0 -84
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +0 -308
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +0 -81
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +0 -277
- data/spec/dragonfly/data_storage/shared_data_store_examples.rb +0 -77
- data/spec/dragonfly/function_manager_spec.rb +0 -154
- data/spec/dragonfly/image_magick/analyser_spec.rb +0 -73
- data/spec/dragonfly/image_magick/encoder_spec.rb +0 -46
- data/spec/dragonfly/image_magick/generator_spec.rb +0 -178
- data/spec/dragonfly/image_magick/processor_spec.rb +0 -293
- data/spec/dragonfly/job_builder_spec.rb +0 -37
- data/spec/dragonfly/job_definitions_spec.rb +0 -57
- data/spec/dragonfly/loggable_spec.rb +0 -80
- data/spec/dragonfly/simple_cache_spec.rb +0 -27
- data/spec/dragonfly/url_attributes.rb +0 -47
- data/spec/functional/deprecations_spec.rb +0 -51
- data/spec/functional/image_magick_app_spec.rb +0 -27
- data/spec/test_imagemagick.ru +0 -49
- data/yard/handlers/configurable_attr_handler.rb +0 -38
- data/yard/setup.rb +0 -15
- data/yard/templates/default/fulldoc/html/css/common.css +0 -109
- data/yard/templates/default/layout/html/layout.erb +0 -93
- data/yard/templates/default/module/html/configuration_summary.erb +0 -31
- data/yard/templates/default/module/setup.rb +0 -17
data/extra_docs/Mongo.md
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
Mongo
|
2
|
-
=====
|
3
|
-
Dragonfly can be used with any ActiveModel-compatible model, therefore libraries like [Mongoid](http://mongoid.org) work out of the box.
|
4
|
-
|
5
|
-
Furthermore, Mongo DB has support for storing blob-like objects directly in the database (using MongoDB 'GridFS'),
|
6
|
-
so you can make use of this with the supplied {Dragonfly::DataStorage::MongoDataStore MongoDataStore}.
|
7
|
-
|
8
|
-
For more info about ActiveModel, see {file:Models}.
|
9
|
-
|
10
|
-
For more info about using the Mongo data store, see {file:DataStorage}.
|
11
|
-
|
12
|
-
Example setup in Rails, using Mongoid
|
13
|
-
-------------------------------------
|
14
|
-
In config/initializers/dragonfly.rb:
|
15
|
-
|
16
|
-
require 'dragonfly'
|
17
|
-
|
18
|
-
app = Dragonfly[:images]
|
19
|
-
|
20
|
-
# Configure to use ImageMagick, Rails defaults, and the Mongo data store
|
21
|
-
app.configure_with(:imagemagick)
|
22
|
-
app.configure_with(:rails) do |c|
|
23
|
-
c.datastore = Dragonfly::DataStorage::MongoDataStore.new :db => Mongoid.database
|
24
|
-
end
|
25
|
-
|
26
|
-
# Allow all mongoid models to use the macro 'image_accessor'
|
27
|
-
app.define_macro_on_include(Mongoid::Document, :image_accessor)
|
28
|
-
|
29
|
-
# ... any other setup, see Rails docs
|
30
|
-
|
31
|
-
Then in models:
|
32
|
-
|
33
|
-
class Album
|
34
|
-
include Mongoid::Document
|
35
|
-
|
36
|
-
field :cover_image_uid
|
37
|
-
image_accessor :cover_image
|
38
|
-
|
39
|
-
# ...
|
40
|
-
end
|
41
|
-
|
42
|
-
See {file:Models} for more info.
|
data/extra_docs/Processing.md
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
Processing
|
2
|
-
==========
|
3
|
-
Registered processors allow you to modify data, e.g. resizing an image.
|
4
|
-
|
5
|
-
You can register as many processors as you like.
|
6
|
-
|
7
|
-
Let's say we have a Dragonfly app
|
8
|
-
|
9
|
-
app = Dragonfly[:images]
|
10
|
-
|
11
|
-
and an image object (actually a {Dragonfly::Job Job} object)...
|
12
|
-
|
13
|
-
image = app.fetch('some/uid')
|
14
|
-
|
15
|
-
...OR a Dragonfly model accessor...
|
16
|
-
|
17
|
-
image = @album.cover_image
|
18
|
-
|
19
|
-
We can process it using any processing methods that have been registered with the processor.
|
20
|
-
|
21
|
-
Lazy evaluation
|
22
|
-
---------------
|
23
|
-
|
24
|
-
new_image = image.process(:some_method)
|
25
|
-
|
26
|
-
doesn't actually do anything until you call something on the returned {Dragonfly::Job Job} object, like `url`, `data`, etc.
|
27
|
-
|
28
|
-
Bang method
|
29
|
-
-----------
|
30
|
-
|
31
|
-
image.process!(:some_method)
|
32
|
-
|
33
|
-
modifies the image object itself, rather than returning a new object.
|
34
|
-
|
35
|
-
ImageMagick Processor
|
36
|
-
---------------------
|
37
|
-
See {file:ImageMagick}.
|
38
|
-
|
39
|
-
Custom Processors
|
40
|
-
-----------------
|
41
|
-
|
42
|
-
To register a single custom processor:
|
43
|
-
|
44
|
-
app.processor.add :watermark do |temp_object, *args|
|
45
|
-
# use temp_object.data, temp_object.path, temp_object.file, etc.
|
46
|
-
SomeLibrary.add_watermark(temp_object.data, 'some/watermark/file.png')
|
47
|
-
# return a String, Pathname, File or Tempfile
|
48
|
-
end
|
49
|
-
|
50
|
-
new_image = image.process(:watermark)
|
51
|
-
|
52
|
-
You can create a class like the ImageMagick one above, in which case all public methods will be counted as processing methods.
|
53
|
-
Each method takes the temp_object as its argument, plus any other args.
|
54
|
-
|
55
|
-
class MyProcessor
|
56
|
-
|
57
|
-
def coolify(temp_object, opts={})
|
58
|
-
SomeLib.coolify(temp_object.data, opts)
|
59
|
-
end
|
60
|
-
|
61
|
-
def uglify(temp_object, ugliness)
|
62
|
-
`uglify -i #{temp_object.path} -u #{ugliness}`
|
63
|
-
end
|
64
|
-
|
65
|
-
private
|
66
|
-
|
67
|
-
def my_helper_method
|
68
|
-
# do stuff
|
69
|
-
end
|
70
|
-
|
71
|
-
end
|
72
|
-
|
73
|
-
app.processor.register(MyProcessor)
|
74
|
-
|
75
|
-
new_image = image.coolify(:some => :args)
|
76
|
-
|
77
|
-
new_image = image.uglify(:loads)
|
data/extra_docs/Rack.md
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
Rack
|
2
|
-
====
|
3
|
-
For more info about using Rack applications, see the docs at {http://rack.rubyforge.org/}
|
4
|
-
|
5
|
-
Basic usage involves storing data (e.g. images),
|
6
|
-
then serving it in some form.
|
7
|
-
|
8
|
-
A basic rackup file `config.ru`:
|
9
|
-
|
10
|
-
require 'rubygems'
|
11
|
-
require 'dragonfly'
|
12
|
-
|
13
|
-
Dragonfly[:my_app_name].configure do |c|
|
14
|
-
# ... configuration here
|
15
|
-
end
|
16
|
-
|
17
|
-
run Dragonfly:App[:my_app_name]
|
18
|
-
|
19
|
-
See {file:Configuration} for more details.
|
20
|
-
|
21
|
-
The basic flow is instantiate an app -> configure it -> run it.
|
22
|
-
|
23
|
-
Example: Using to serve resized images
|
24
|
-
--------------------------------------
|
25
|
-
|
26
|
-
`config.ru`:
|
27
|
-
|
28
|
-
require 'rubygems'
|
29
|
-
require 'dragonfly'
|
30
|
-
|
31
|
-
app = Dragonfly[:images].configure_with(:imagemagick)
|
32
|
-
|
33
|
-
run app
|
34
|
-
|
35
|
-
This enables the app to use all the ImageMagick goodies provided by Dragonfly (see {file:Configuration}).
|
36
|
-
By default the {Dragonfly::DataStorage::FileDataStore file data store} is used.
|
37
|
-
|
38
|
-
In the console:
|
39
|
-
|
40
|
-
app = Dragonfly[:images]
|
41
|
-
|
42
|
-
# Store
|
43
|
-
uid = app.store(File.new('path/to/image.png')) # ===> unique uid
|
44
|
-
|
45
|
-
# Get the url for a thumbnail
|
46
|
-
url = app.fetch(uid).thumb('400x300').url # ===> "/media/BAhbBlsHOgZmIg9hc..."
|
47
|
-
|
48
|
-
Now when we visit the url `/media/BAhbBlsHOgZmIg9hc...` in the browser, we get a resized image!
|
49
|
-
|
50
|
-
Mounting in Rack
|
51
|
-
----------------
|
52
|
-
See {file:URLs}
|
data/extra_docs/Rails2.md
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
Using With Rails 2.3
|
2
|
-
====================
|
3
|
-
|
4
|
-
**NOTE: RAILS 2.3 IS NOT SUPPORTED IN NEW VERSIONS OF DRAGONFLY SO PLEASE USE VERSION 0.8.5**
|
5
|
-
|
6
|
-
Setting up the quick way
|
7
|
-
------------------------
|
8
|
-
config/initializers/dragonfly.rb:
|
9
|
-
|
10
|
-
require 'dragonfly/rails/images'
|
11
|
-
|
12
|
-
Setting up the more explicit way
|
13
|
-
--------------------------------
|
14
|
-
You can do the above explicitly.
|
15
|
-
|
16
|
-
config/initializers/dragonfly.rb:
|
17
|
-
|
18
|
-
require 'dragonfly'
|
19
|
-
|
20
|
-
app = Dragonfly[:images]
|
21
|
-
app.configure_with(:imagemagick)
|
22
|
-
app.configure_with(:rails)
|
23
|
-
|
24
|
-
app.define_macro(ActiveRecord::Base, :image_accessor)
|
25
|
-
|
26
|
-
environment.rb:
|
27
|
-
|
28
|
-
config.middleware.insert 0, 'Dragonfly::Middleware', :images, '/media'
|
29
|
-
config.middleware.insert_before 'Dragonfly::Middleware', 'Rack::Cache', {
|
30
|
-
:verbose => true,
|
31
|
-
:metastore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"),
|
32
|
-
:entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
|
33
|
-
}
|
34
|
-
|
35
|
-
Gems
|
36
|
-
----
|
37
|
-
environment.rb
|
38
|
-
|
39
|
-
config.gem 'dragonfly', '0.8.5'
|
40
|
-
config.gem 'rack-cache', :lib => 'rack/cache'
|
41
|
-
|
42
|
-
Capistrano
|
43
|
-
----------
|
44
|
-
If using Capistrano with the above, you probably will want to keep the cache between deploys, so in deploy.rb:
|
45
|
-
|
46
|
-
namespace :dragonfly do
|
47
|
-
desc "Symlink the Rack::Cache files"
|
48
|
-
task :symlink, :roles => [:app] do
|
49
|
-
run "mkdir -p #{shared_path}/tmp/dragonfly && ln -nfs #{shared_path}/tmp/dragonfly #{release_path}/tmp/dragonfly"
|
50
|
-
end
|
51
|
-
end
|
52
|
-
after 'deploy:update_code', 'dragonfly:symlink'
|
53
|
-
|
54
|
-
Use it!
|
55
|
-
-------
|
56
|
-
|
57
|
-
To see what you can do with the model accessors, see {file:Models}.
|
data/extra_docs/Rails3.md
DELETED
@@ -1,56 +0,0 @@
|
|
1
|
-
Using With Rails 3
|
2
|
-
==================
|
3
|
-
|
4
|
-
Setting up the quick way
|
5
|
-
------------------------
|
6
|
-
config/initializers/dragonfly.rb:
|
7
|
-
|
8
|
-
require 'dragonfly/rails/images'
|
9
|
-
|
10
|
-
Setting up the more explicit way
|
11
|
-
--------------------------------
|
12
|
-
You can do the above explicitly.
|
13
|
-
|
14
|
-
config/initializers/dragonfly.rb:
|
15
|
-
|
16
|
-
require 'dragonfly'
|
17
|
-
|
18
|
-
app = Dragonfly[:images]
|
19
|
-
app.configure_with(:imagemagick)
|
20
|
-
app.configure_with(:rails)
|
21
|
-
|
22
|
-
app.define_macro(ActiveRecord::Base, :image_accessor)
|
23
|
-
|
24
|
-
application.rb:
|
25
|
-
|
26
|
-
config.middleware.insert 0, 'Rack::Cache', {
|
27
|
-
:verbose => true,
|
28
|
-
:metastore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"),
|
29
|
-
:entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")
|
30
|
-
} # unless Rails.env.production? ## uncomment this 'unless' in Rails 3.1,
|
31
|
-
## because it already inserts Rack::Cache in production
|
32
|
-
|
33
|
-
config.middleware.insert_after 'Rack::Cache', 'Dragonfly::Middleware', :images
|
34
|
-
|
35
|
-
Gemfile
|
36
|
-
-------
|
37
|
-
|
38
|
-
gem 'dragonfly', '~>0.9.15'
|
39
|
-
gem 'rack-cache', :require => 'rack/cache'
|
40
|
-
|
41
|
-
Capistrano
|
42
|
-
----------
|
43
|
-
If using Capistrano with the above, you probably will want to keep the cache between deploys, so in deploy.rb:
|
44
|
-
|
45
|
-
namespace :dragonfly do
|
46
|
-
desc "Symlink the Rack::Cache files"
|
47
|
-
task :symlink, :roles => [:app] do
|
48
|
-
run "mkdir -p #{shared_path}/tmp/dragonfly && ln -nfs #{shared_path}/tmp/dragonfly #{release_path}/tmp/dragonfly"
|
49
|
-
end
|
50
|
-
end
|
51
|
-
after 'deploy:update_code', 'dragonfly:symlink'
|
52
|
-
|
53
|
-
Use it!
|
54
|
-
-------
|
55
|
-
|
56
|
-
To see what you can do with the model accessors, see {file:Models}.
|
@@ -1,104 +0,0 @@
|
|
1
|
-
Serving Content Remotely
|
2
|
-
========================
|
3
|
-
|
4
|
-
Dragonfly stores original versions of content in a datastore which could be the {file:DataStorage#File\_datastore filesystem},
|
5
|
-
{file:DataStorage#S3\_datastore S3}, etc., but when it comes to serving it, or serving a processed version
|
6
|
-
(e.g. an image thumbnail), it fetches it and serves locally from the {Dragonfly::Server dragonfly server}.
|
7
|
-
|
8
|
-
For most cases, this is the way to go - you have control over it and you can {file:Caching cache it using HTTP caching}.
|
9
|
-
|
10
|
-
However, if for whatever reason you must serve content from the datastore directly, e.g. for lightening the load on your server, Dragonfly
|
11
|
-
provides a number of ways of doing this.
|
12
|
-
|
13
|
-
Original Content
|
14
|
-
----------------
|
15
|
-
The {file:DataStorage#File\_datastore FileDataStore}, {file:DataStorage#S3\_datastore S3DataStore} and
|
16
|
-
{file:DataStorage#Couch\_datastore CouchDataStore} allow for serving data directly, so given a Dragonfly app
|
17
|
-
|
18
|
-
app = Dragonfly[:my_app]
|
19
|
-
|
20
|
-
and the uid for some stored content
|
21
|
-
|
22
|
-
uid = app.store(Pathname.new('some/file.jpg'))
|
23
|
-
|
24
|
-
we can get the remote url using
|
25
|
-
|
26
|
-
app.remote_url_for(uid) # e.g. http://my-bucket.s3.amazonaws.com/2011/04/01/03/03/05/243/file.jpg
|
27
|
-
|
28
|
-
or from a model attachment:
|
29
|
-
|
30
|
-
my_model.attachment.remote_url # http://my-bucket.s3.amazonaws.com/2011...
|
31
|
-
|
32
|
-
Processed Content
|
33
|
-
-----------------
|
34
|
-
If using models, the quick and easy way to serve e.g. image thumbnails remotely is to process them _on upload_
|
35
|
-
like most other attachment ruby gems (see {file:Models#Up-front_thumbnailing}),
|
36
|
-
e.g. for my avatar model,
|
37
|
-
|
38
|
-
class Avatar
|
39
|
-
image_accessor :image do
|
40
|
-
copy_to(:small_image){|a| a.thumb('200x200#') }
|
41
|
-
end
|
42
|
-
image_accessor :small_image
|
43
|
-
end
|
44
|
-
|
45
|
-
Then we can use `remote_url` for for each accessor.
|
46
|
-
|
47
|
-
avatar.image.remote_url # http://my-bucket.s3.amazonaws.com/some/path.jpg
|
48
|
-
avatar.small_image.remote_url # http://my-bucket.s3.amazonaws.com/some/other/path.jpg
|
49
|
-
|
50
|
-
However, this has all the limitations that come with up-front processing, such as having to regenerate the thumbnail when the size requirement changes.
|
51
|
-
|
52
|
-
Serving Processed Content *on-the-fly*
|
53
|
-
--------------------------------------
|
54
|
-
Serving processed versions of content such as thumbnails remotely is a bit more tricky as we need to upload the thumbnail
|
55
|
-
to the datastore in the on-the-fly manner.
|
56
|
-
|
57
|
-
Dragonfly provides a way of doing this using `define_url` and `before_serve` methods.
|
58
|
-
|
59
|
-
The details of keeping track of/expiring these thumbnails is up to you.
|
60
|
-
|
61
|
-
We need to keep track of which thumbnails have been already created, by storing a uid for each one.
|
62
|
-
Below is an example using an ActiveRecord 'Thumb' table to keep track of already created thumbnail uids.
|
63
|
-
It has two string columns; 'job' and 'uid'.
|
64
|
-
|
65
|
-
app.configure do |c|
|
66
|
-
|
67
|
-
# Override the .url method...
|
68
|
-
c.define_url do |app, job, opts|
|
69
|
-
thumb = Thumb.find_by_job(job.serialize)
|
70
|
-
# If (fetch 'some_uid' then resize to '40x40') has been stored already, give the datastore's remote url ...
|
71
|
-
if thumb
|
72
|
-
app.datastore.url_for(thumb.uid)
|
73
|
-
# ...otherwise give the local Dragonfly server url
|
74
|
-
else
|
75
|
-
app.server.url_for(job)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# Before serving from the local Dragonfly server...
|
80
|
-
c.server.before_serve do |job, env|
|
81
|
-
# ...store the thumbnail in the datastore...
|
82
|
-
uid = job.store
|
83
|
-
|
84
|
-
# ...keep track of its uid so next time we can serve directly from the datastore
|
85
|
-
Thumb.create!(
|
86
|
-
:uid => uid,
|
87
|
-
:job => job.serialize # 'BAhbBls...' - holds all the job info
|
88
|
-
) # e.g. fetch 'some_uid' then resize to '40x40'
|
89
|
-
end
|
90
|
-
|
91
|
-
end
|
92
|
-
|
93
|
-
This would give
|
94
|
-
|
95
|
-
app.fetch('some_uid').thumb('40x40').url # normal Dragonfly url e.g. /media/BAhbBls...
|
96
|
-
|
97
|
-
then from the second time onwards
|
98
|
-
|
99
|
-
app.fetch('some_uid').thumb('40x40').url # http://my-bucket.s3.amazonaws.com/2011...
|
100
|
-
|
101
|
-
The above is just an example - there are a number of things you could do with `before_serve` and `define_url` -
|
102
|
-
you could use e.g. Redis or some key-value store to keep track of thumbnails.
|
103
|
-
You'd also probably want a way of expiring the thumbnails or destroying them when the original is destroyed, but this
|
104
|
-
is left up to you as it's outside of the scope of Dragonfly.
|
data/extra_docs/Sinatra.md
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
Sinatra
|
2
|
-
=======
|
3
|
-
You can use {Dragonfly::Job Job}'s `to_response` method like so:
|
4
|
-
|
5
|
-
app = Dragonfly[:images].configure_with(:imagemagick)
|
6
|
-
|
7
|
-
get '/images/:size.:format' do |size, format|
|
8
|
-
app.fetch_file('~/some/image.png').thumb(size).encode(format).to_response(env)
|
9
|
-
end
|
10
|
-
|
11
|
-
`to_response` returns a rack-style response array with status, headers and body.
|
12
|
-
|
13
|
-
NOTE: uids from the datastore may have slashes and dots in them so make sure you escape url-escape them when using ':uid' as
|
14
|
-
a path segment.
|
15
|
-
|
16
|
-
or you can mount as a middleware, like in rails:
|
17
|
-
|
18
|
-
Dragonfly[:images].configure_with(:imagemagick) do |c|
|
19
|
-
c.url_format = '/media/:job'
|
20
|
-
end
|
21
|
-
|
22
|
-
use Dragonfly::Middleware, :images
|
23
|
-
|
24
|
-
get '/' #... do
|
25
|
-
# ...
|
data/extra_docs/URLs.md
DELETED
@@ -1,203 +0,0 @@
|
|
1
|
-
URLs
|
2
|
-
====
|
3
|
-
|
4
|
-
We can get urls for any kind of job:
|
5
|
-
|
6
|
-
app = Dragonfly[:images]
|
7
|
-
|
8
|
-
app.fetch('my_uid').process(:flip).url # "/BAhbBlsH..."
|
9
|
-
app.generate(:text, 'hello').thumb('500x302').gif.url # "/BAhbCFsHOgZ..."
|
10
|
-
|
11
|
-
Path format
|
12
|
-
-----------
|
13
|
-
The format of the standard urls can be configured using `url_format`:
|
14
|
-
|
15
|
-
app.configure do |c|
|
16
|
-
c.url_format = '/:job'
|
17
|
-
end
|
18
|
-
|
19
|
-
(or call `app.server.url_format=` directly).
|
20
|
-
|
21
|
-
`url_format = '/:job/:basename.:format'`:
|
22
|
-
|
23
|
-
media = app.fetch('my_uid')
|
24
|
-
media.url # "/BAhbBlsHOgZmSSIJbWlsawY6BkVU"
|
25
|
-
media.name = 'milk.txt'
|
26
|
-
media.url # "/BAhbBlsHOgZmSSIJbWlsawY6BkVU/milk.txt"
|
27
|
-
media.encode(:pdf).url # "/BAhbB1sHOgZ...RbBzoGZToIcGRm/milk.pdf"
|
28
|
-
media.url(:format => 'bang') # "/BAhbBlsHOgZmSSIJbWlsawY6BkVU/milk.bang"
|
29
|
-
media.url(:some => 'thing') # "/BAhbBlsHOgZmSSIJbWlsawY6BkVU/milk.txt?some=thing"
|
30
|
-
|
31
|
-
`url_format = '/some-prefix/:job'`:
|
32
|
-
|
33
|
-
media = app.fetch('my_uid')
|
34
|
-
media.url # "/some-prefix/BAhbBlsHOgZmSSIJbWlsawY6BkVU"
|
35
|
-
|
36
|
-
`url_format = '/blah'`:
|
37
|
-
|
38
|
-
media = app.fetch('my_uid')
|
39
|
-
media.url # "/blah?job=BAhbBlsHOgZmSSIJbWlsawY6BkVU"
|
40
|
-
|
41
|
-
When using {file:Models}, any {file:Models#_Magic__Attributes magic attributes} will be used in url generation, e.g.
|
42
|
-
|
43
|
-
app.server.url_format = '/frogs/:job/:basename-:width.:format'
|
44
|
-
|
45
|
-
with
|
46
|
-
|
47
|
-
class Frog
|
48
|
-
image_accessor :face # columns face_uid, face_name and face_width
|
49
|
-
end
|
50
|
-
|
51
|
-
gives
|
52
|
-
|
53
|
-
frog = Frog.new :face => Pathname.new('froggie.jpg') # image with width 400
|
54
|
-
|
55
|
-
frog.face.url # "/frogs/BAhbBlsHOgZmSSIIc2RmBjoGRVQ/froggie-400.jpg"
|
56
|
-
|
57
|
-
Host
|
58
|
-
----
|
59
|
-
You can also set a host for the urls
|
60
|
-
|
61
|
-
app.configure{|c| c.url_host = 'http://some.host' } # or directly on app.server
|
62
|
-
|
63
|
-
app.fetch('my_uid').url # "http://some.host/BAhb..."
|
64
|
-
|
65
|
-
app.fetch('my_uid').url(:host => 'http://localhost:80') # "http://localhost:80/BAh..."
|
66
|
-
|
67
|
-
Content-Disposition
|
68
|
-
-------------------
|
69
|
-
You can manually set the content-disposition of the response:
|
70
|
-
|
71
|
-
app.content_disposition = :attachment # should be :inline or :attachment (or :hidden)
|
72
|
-
|
73
|
-
`:attachment` tells the browser to download it, `:inline` tells it to display in-browser if possible.
|
74
|
-
|
75
|
-
You can also use a block:
|
76
|
-
|
77
|
-
app.content_disposition = proc{|job, request|
|
78
|
-
if job.format == :jpg || request['d'] == 'inline' # request is a Rack::Request object
|
79
|
-
:inline
|
80
|
-
else
|
81
|
-
:attachment
|
82
|
-
end
|
83
|
-
}
|
84
|
-
|
85
|
-
Downloaded filename
|
86
|
-
-------------------
|
87
|
-
To specify the filename the browser uses for 'Save As' dialogues:
|
88
|
-
|
89
|
-
app.content_filename = proc{|job, request|
|
90
|
-
if job.process_steps.any?
|
91
|
-
"#{job.basename}_#{job.process_steps.first.name}.#{job.format}"
|
92
|
-
else
|
93
|
-
"#{job.basename}.#{job.format}"
|
94
|
-
end
|
95
|
-
}
|
96
|
-
|
97
|
-
This will for example give the following filenames for the following jobs:
|
98
|
-
|
99
|
-
app.fetch('some/tree.png') # -> 'tree.png'
|
100
|
-
app.fetch('some/tree.png').process(:greyscale) # -> 'tree_greyscale.png'
|
101
|
-
app.fetch('some/tree.png').process(:greyscale).gif # -> 'tree_greyscale.gif'
|
102
|
-
|
103
|
-
By default the original filename is used, with a modified extension if it's been encoded.
|
104
|
-
|
105
|
-
Routed Endpoints
|
106
|
-
----------------
|
107
|
-
You can also use a number of Rack-based routers and create Dragonfly endpoints.
|
108
|
-
|
109
|
-
If we have an app set up for using ImageMagick:
|
110
|
-
|
111
|
-
app = Dragonfly[:images].configure_with(:imagemagick)
|
112
|
-
|
113
|
-
Then to get the url '/text/hello' to display the text "hello"...
|
114
|
-
|
115
|
-
Rails 3 (routes.rb):
|
116
|
-
|
117
|
-
match '/text/:text' => app.endpoint { |params, app|
|
118
|
-
app.generate(:text, params[:text])
|
119
|
-
}
|
120
|
-
|
121
|
-
{http://github.com/josh/rack-mount Rack-Mount}:
|
122
|
-
|
123
|
-
Routes = Rack::Mount::RouteSet.new do |set|
|
124
|
-
|
125
|
-
set.add_route app.endpoint{|params, a| a.generate(:text, params[:text]) },
|
126
|
-
:path_info => %r{/text/(?:<text>.+)}
|
127
|
-
|
128
|
-
# ...
|
129
|
-
|
130
|
-
end
|
131
|
-
|
132
|
-
{http://github.com/joshbuddy/usher Usher}:
|
133
|
-
|
134
|
-
routes = Usher::Interface.for(:rack) do
|
135
|
-
add('/text/:text').to app.endpoint { |params, app|
|
136
|
-
app.generate(:text, params[:text])
|
137
|
-
}
|
138
|
-
end
|
139
|
-
|
140
|
-
{http://github.com/joshbuddy/http_router HTTP Router}:
|
141
|
-
|
142
|
-
r = HttpRouter.new
|
143
|
-
r.add('/text/:text').to app.endpoint { |params, app|
|
144
|
-
app.generate(:text, params[:text])
|
145
|
-
}
|
146
|
-
|
147
|
-
In each case the url will need to be generated by the router of choice, or manually.
|
148
|
-
|
149
|
-
NOTE: Ruby treats curly braces slightly differently to `do`...`end` so be aware of this when using the above examples.
|
150
|
-
|
151
|
-
Simple Endpoints
|
152
|
-
----------------
|
153
|
-
{Dragonfly::Job Job} objects can also be turned straight into Rack endpoints using `to_app`, e.g. in Rails 3:
|
154
|
-
|
155
|
-
match '/beach' => app.fetch_file('~/some/image.png').thumb('100x100#').jpg.to_app
|
156
|
-
|
157
|
-
|
158
|
-
Denial-of-service attacks
|
159
|
-
-------------------------
|
160
|
-
Although the standard urls are fairly cryptic, a malicious person who knows the Dragonfly source code could potentially
|
161
|
-
work out how to generate urls to spam your server with heavy requests, e.g. resize to 100000 by 100000 pixels.
|
162
|
-
|
163
|
-
Therefore the app can be protected by requiring the presence of a "DOS-protection" SHA in the urls:
|
164
|
-
|
165
|
-
app.configure do |c|
|
166
|
-
c.protect_from_dos_attacks = true
|
167
|
-
c.secret = 'You should supply some random secret here'
|
168
|
-
end
|
169
|
-
|
170
|
-
Then the standard generated urls will have a SHA query parameter attached:
|
171
|
-
|
172
|
-
app.fetch('my_uid').url # "/BAhbBlsHOgZmIghzZGY?s=df76ba27"
|
173
|
-
|
174
|
-
Any requests without the correct SHA parameter result in a 400 (bad parameters) error response.
|
175
|
-
|
176
|
-
You can also validate for a correct SHA using routed endpoints:
|
177
|
-
|
178
|
-
match '/text/:text' => app.endpoint{|params, app|
|
179
|
-
app.generate(:text, params[:text]).validate_sha!(params[:sha])
|
180
|
-
}
|
181
|
-
|
182
|
-
... where obviously you need to pass in a 'sha' parameter to the url, which can be found using
|
183
|
-
|
184
|
-
app.generate(:text, 'some text').sha
|
185
|
-
|
186
|
-
Overriding responses
|
187
|
-
--------------------
|
188
|
-
You can override/add headers using `response_headers`:
|
189
|
-
|
190
|
-
app.configure do |c|
|
191
|
-
c.response_headers['X-Something'] = 'Custom header' # set directly..
|
192
|
-
c.response_headers['summink'] = proc{|job, request| # ...or via a callback
|
193
|
-
job.image? ? 'image yo' : 'not an image'
|
194
|
-
}
|
195
|
-
end
|
196
|
-
|
197
|
-
You can intercept the response from the dragonfly server by throwing `:halt` with a Rack response array from inside the `before_serve` callback:
|
198
|
-
|
199
|
-
app.configure do |c|
|
200
|
-
c.server.before_serve do |job, env|
|
201
|
-
throw :halt, [200, {'Content-type' => 'text/plain'}, ['hello']]
|
202
|
-
end
|
203
|
-
end
|