dragonfly 0.6.2 → 0.7.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.
- data/.gitignore +2 -0
- data/.specopts +2 -0
- data/.yardopts +11 -5
- data/Gemfile +22 -0
- data/Gemfile.rails.2.3.5 +13 -0
- data/History.md +49 -0
- data/README.md +18 -28
- data/Rakefile +24 -36
- data/VERSION +1 -1
- data/config.ru +4 -1
- data/dragonfly.gemspec +85 -99
- data/extra_docs/Analysers.md +66 -30
- data/extra_docs/Caching.md +22 -0
- data/extra_docs/Configuration.md +116 -0
- data/extra_docs/DataStorage.md +114 -14
- data/extra_docs/Encoding.md +62 -37
- data/extra_docs/GeneralUsage.md +118 -0
- data/extra_docs/Generators.md +92 -0
- data/extra_docs/Heroku.md +51 -0
- data/extra_docs/Index.md +8 -9
- data/extra_docs/MimeTypes.md +18 -17
- data/extra_docs/Models.md +251 -0
- data/extra_docs/Processing.md +94 -70
- data/extra_docs/Rack.md +53 -0
- data/extra_docs/Rails2.md +44 -0
- data/extra_docs/Rails3.md +51 -0
- data/extra_docs/Sinatra.md +21 -0
- data/extra_docs/URLs.md +114 -0
- data/features/images.feature +6 -7
- data/features/no_processing.feature +0 -6
- data/features/rails_2.3.5.feature +1 -1
- data/features/rails_3.0.0.rc.feature +8 -0
- data/features/steps/dragonfly_steps.rb +14 -12
- data/features/steps/rails_steps.rb +20 -9
- data/features/support/env.rb +10 -11
- data/fixtures/files/app/views/albums/new.html.erb +4 -4
- data/fixtures/files/app/views/albums/show.html.erb +1 -1
- data/fixtures/files/features/manage_album_images.feature +1 -1
- data/fixtures/files/features/step_definitions/{album_steps.rb → image_steps.rb} +4 -3
- data/fixtures/files/features/support/paths.rb +2 -0
- data/fixtures/files/features/text_images.feature +7 -0
- data/fixtures/rails_3.0.0.rc/template.rb +21 -0
- data/irbrc.rb +2 -1
- data/lib/dragonfly.rb +4 -16
- data/lib/dragonfly/{active_record_extensions.rb → active_model_extensions.rb} +1 -1
- data/lib/dragonfly/active_model_extensions/attachment.rb +146 -0
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/class_methods.rb +5 -6
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/instance_methods.rb +1 -1
- data/lib/dragonfly/{active_record_extensions → active_model_extensions}/validations.rb +5 -9
- data/lib/dragonfly/analyser.rb +59 -0
- data/lib/dragonfly/analysis/file_command_analyser.rb +1 -1
- data/lib/dragonfly/analysis/r_magick_analyser.rb +46 -31
- data/lib/dragonfly/app.rb +138 -173
- data/lib/dragonfly/config/heroku.rb +19 -0
- data/lib/dragonfly/config/r_magick.rb +37 -0
- data/lib/dragonfly/config/{rails_defaults.rb → rails.rb} +6 -7
- data/lib/dragonfly/configurable.rb +30 -27
- data/lib/dragonfly/core_ext/object.rb +1 -1
- data/lib/dragonfly/data_storage/file_data_store.rb +59 -26
- data/lib/dragonfly/data_storage/mongo_data_store.rb +65 -0
- data/lib/dragonfly/data_storage/s3data_store.rb +31 -12
- data/lib/dragonfly/encoder.rb +13 -0
- data/lib/dragonfly/encoding/r_magick_encoder.rb +10 -19
- data/lib/dragonfly/endpoint.rb +43 -0
- data/lib/dragonfly/function_manager.rb +65 -0
- data/lib/dragonfly/{processing/r_magick_text_processor.rb → generation/r_magick_generator.rb} +25 -11
- data/lib/dragonfly/generator.rb +9 -0
- data/lib/dragonfly/job.rb +290 -0
- data/lib/dragonfly/job_builder.rb +39 -0
- data/lib/dragonfly/job_definitions.rb +26 -0
- data/lib/dragonfly/job_endpoint.rb +17 -0
- data/lib/dragonfly/loggable.rb +28 -0
- data/lib/dragonfly/middleware.rb +21 -14
- data/lib/dragonfly/processing/r_magick_processor.rb +71 -48
- data/lib/dragonfly/processor.rb +9 -0
- data/lib/dragonfly/r_magick_utils.rb +24 -0
- data/lib/dragonfly/rails/images.rb +10 -7
- data/lib/dragonfly/routed_endpoint.rb +42 -0
- data/lib/dragonfly/serializer.rb +32 -0
- data/lib/dragonfly/simple_cache.rb +23 -0
- data/lib/dragonfly/simple_endpoint.rb +64 -0
- data/lib/dragonfly/temp_object.rb +77 -45
- data/spec/argument_matchers.rb +7 -17
- data/spec/dragonfly/active_model_extensions/active_model_setup.rb +97 -0
- data/spec/dragonfly/active_model_extensions/active_record_setup.rb +85 -0
- data/spec/dragonfly/{active_record_extensions → active_model_extensions}/model_spec.rb +282 -244
- data/spec/dragonfly/active_model_extensions/spec_helper.rb +11 -0
- data/spec/dragonfly/analyser_spec.rb +123 -0
- data/spec/dragonfly/analysis/file_command_analyser_spec.rb +2 -2
- data/spec/dragonfly/analysis/r_magick_analyser_spec.rb +10 -1
- data/spec/dragonfly/app_spec.rb +175 -69
- data/spec/dragonfly/configurable_spec.rb +14 -0
- data/spec/dragonfly/data_storage/data_store_spec.rb +36 -9
- data/spec/dragonfly/data_storage/file_data_store_spec.rb +61 -38
- data/spec/dragonfly/data_storage/mongo_data_store_spec.rb +18 -0
- data/spec/dragonfly/data_storage/s3_data_store_spec.rb +34 -39
- data/spec/dragonfly/deprecation_spec.rb +20 -0
- data/spec/dragonfly/function_manager_spec.rb +154 -0
- data/spec/dragonfly/generation/r_magick_generator_spec.rb +119 -0
- data/spec/dragonfly/job_builder_spec.rb +37 -0
- data/spec/dragonfly/job_definitions_spec.rb +35 -0
- data/spec/dragonfly/job_endpoint_spec.rb +66 -0
- data/spec/dragonfly/job_spec.rb +605 -0
- data/spec/dragonfly/loggable_spec.rb +80 -0
- data/spec/dragonfly/middleware_spec.rb +37 -17
- data/spec/dragonfly/processing/r_magick_processor_spec.rb +182 -166
- data/spec/dragonfly/routed_endpoint_spec.rb +48 -0
- data/spec/dragonfly/serializer_spec.rb +61 -0
- data/spec/dragonfly/simple_cache_spec.rb +27 -0
- data/spec/dragonfly/simple_endpoint_spec.rb +78 -0
- data/spec/dragonfly/temp_object_spec.rb +154 -119
- data/spec/simple_matchers.rb +22 -0
- data/spec/spec_helper.rb +28 -4
- data/yard/templates/default/layout/html/layout.erb +18 -11
- metadata +89 -190
- data/config.rb +0 -5
- data/extra_docs/ActiveRecord.md +0 -196
- data/extra_docs/ExampleUseCases.md +0 -189
- data/extra_docs/GettingStarted.md +0 -114
- data/extra_docs/Shortcuts.md +0 -118
- data/extra_docs/UsingWithRails.md +0 -81
- data/features/rails_3.0.0.beta3.feature +0 -7
- data/fixtures/rails_3.0.0.beta3/template.rb +0 -16
- data/lib/dragonfly/active_record_extensions/attachment.rb +0 -170
- data/lib/dragonfly/analyser_list.rb +0 -9
- data/lib/dragonfly/analysis/base.rb +0 -10
- data/lib/dragonfly/belongs_to_app.rb +0 -24
- data/lib/dragonfly/config/heroku_rails_images.rb +0 -23
- data/lib/dragonfly/config/r_magick_images.rb +0 -69
- data/lib/dragonfly/config/r_magick_text.rb +0 -25
- data/lib/dragonfly/config/rails_images.rb +0 -13
- data/lib/dragonfly/data_storage/base.rb +0 -21
- data/lib/dragonfly/data_storage/base64_data_store.rb +0 -23
- data/lib/dragonfly/data_storage/transparent_data_store.rb +0 -21
- data/lib/dragonfly/delegatable.rb +0 -14
- data/lib/dragonfly/delegator.rb +0 -62
- data/lib/dragonfly/encoder_list.rb +0 -9
- data/lib/dragonfly/encoding/base.rb +0 -14
- data/lib/dragonfly/encoding/transparent_encoder.rb +0 -14
- data/lib/dragonfly/extended_temp_object.rb +0 -120
- data/lib/dragonfly/parameters.rb +0 -163
- data/lib/dragonfly/processing/base.rb +0 -10
- data/lib/dragonfly/processor_list.rb +0 -9
- data/lib/dragonfly/url_handler.rb +0 -147
- data/spec/dragonfly/active_record_extensions/attachment_spec.rb +0 -8
- data/spec/dragonfly/active_record_extensions/migration.rb +0 -42
- data/spec/dragonfly/active_record_extensions/models.rb +0 -6
- data/spec/dragonfly/active_record_extensions/spec_helper.rb +0 -24
- data/spec/dragonfly/belongs_to_app_spec.rb +0 -55
- data/spec/dragonfly/delegatable_spec.rb +0 -32
- data/spec/dragonfly/delegator_spec.rb +0 -145
- data/spec/dragonfly/extended_temp_object_spec.rb +0 -71
- data/spec/dragonfly/parameters_spec.rb +0 -298
- data/spec/dragonfly/processing/r_magick_text_processor_spec.rb +0 -84
- data/spec/dragonfly/url_handler_spec.rb +0 -247
- data/spec/dragonfly_spec.rb +0 -16
- data/spec/ginger_scenarios.rb +0 -13
data/config.rb
DELETED
data/extra_docs/ActiveRecord.md
DELETED
@@ -1,196 +0,0 @@
|
|
1
|
-
ActiveRecord Extensions
|
2
|
-
=======================
|
3
|
-
|
4
|
-
Dragonfly provides a module that extends ActiveRecord so that you can access Dragonfly objects as if they were just another model attribute.
|
5
|
-
|
6
|
-
Registering with ActiveRecord
|
7
|
-
-----------------------------
|
8
|
-
If you've used a rails generator, or required the file 'dragonfly/rails/images.rb', then this step will be already done for you.
|
9
|
-
|
10
|
-
Suppose we have a dragonfly app
|
11
|
-
|
12
|
-
app = Dragonfly::App[:my_app_name]
|
13
|
-
|
14
|
-
We can define an accessor on ActiveRecord models using
|
15
|
-
|
16
|
-
Dragonfly.active_record_macro(:image, app)
|
17
|
-
|
18
|
-
The first argument is the prefix for the accessor macro (in this case 'image').
|
19
|
-
|
20
|
-
Adding accessors
|
21
|
-
----------------
|
22
|
-
Now we have the method `image_accessor` available in our model classes, which we can use as many times as we like
|
23
|
-
|
24
|
-
class Album
|
25
|
-
image_accessor :cover_image
|
26
|
-
image_accessor :band_photo # Note: this is a different image altogether, not a thumbnail of cover_image
|
27
|
-
end
|
28
|
-
|
29
|
-
For each accessor, we need a database field ..._uid, as a string, so in our migrations:
|
30
|
-
|
31
|
-
class MyMigration < ActiveRecord::Migration
|
32
|
-
|
33
|
-
def self.up
|
34
|
-
add_column :albums, :cover_image_uid, :string
|
35
|
-
add_column :albums, :band_photo_uid, :string
|
36
|
-
end
|
37
|
-
|
38
|
-
def self.down
|
39
|
-
remove_column :albums, :cover_image_uid
|
40
|
-
remove_column :albums, :band_photo_uid
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
Using the accessors
|
46
|
-
-------------------
|
47
|
-
|
48
|
-
We can use the attribute much like other other active record attributes:
|
49
|
-
|
50
|
-
album = Album.new
|
51
|
-
|
52
|
-
album.cover_image = "\377???JFIF\000\..." # can assign as a string...
|
53
|
-
album.cover_image = File.new('path/to/my_image.png') # ... or as a file...
|
54
|
-
album.cover_image = some_tempfile # ... or as a tempfile
|
55
|
-
|
56
|
-
album.cover_image # => #<Dragonfly::ActiveRecordExtensions::Attachment:0x103ef6128...
|
57
|
-
|
58
|
-
album.cover_image = nil
|
59
|
-
album.cover_image # => nil
|
60
|
-
|
61
|
-
We can inspect properties of the attribute
|
62
|
-
|
63
|
-
album.cover_image.width # => 280
|
64
|
-
album.cover_image.height # => 140
|
65
|
-
album.cover_image.number_of_colours # => 34703 (can also use American spelling)
|
66
|
-
album.cover_image.mime_type # => 'image/png'
|
67
|
-
|
68
|
-
The properties available (i.e. 'width', etc.) come from the app's registered analysers - see {file:Analysers.md Analysers}.
|
69
|
-
|
70
|
-
We can play around with the data
|
71
|
-
|
72
|
-
album.cover_image.data # => "\377???JFIF\000\..."
|
73
|
-
album.cover_image.to_file('out.png') # writes to file 'out.png' and returns a readable file object
|
74
|
-
album.cover_image.tempfile # => #<File:/var/folders/st/strHv74sH044JPabSiODz... a closed Tempfile object
|
75
|
-
album.cover_image.file # => #<File:/var/folders/st/strHv74sH044JPabSiODz... a readable (open) File object
|
76
|
-
album.cover_image.file do |f| # Yields an open file object, returns the return value of
|
77
|
-
data = f.read(256) # the block, and closes the file object
|
78
|
-
end
|
79
|
-
album.cover_image.path # => '/var/folders/st/strHv74sH044JPabSiODz...' i.e. the path of the tempfile
|
80
|
-
album.cover_image.size # => 134507 (size in bytes)
|
81
|
-
|
82
|
-
We can process the data
|
83
|
-
|
84
|
-
temp_object = album.cover_image.process(:resize, :geometry => '20x20') # returns an ExtendedTempObject, with similar properties
|
85
|
-
temp_object.width # => 20
|
86
|
-
album.cover_image.width # => 280 (no change)
|
87
|
-
|
88
|
-
album.cover_image.process!(:resize, :geometry => '20x20') # (operates on self)
|
89
|
-
album.cover_image.width # => 20
|
90
|
-
|
91
|
-
The available processing methods available (i.e. 'resize', etc.) come from the {Dragonfly} app's registered processors - see {file:Processing.md Processing}
|
92
|
-
|
93
|
-
We can encode the data
|
94
|
-
|
95
|
-
temp_object = album.cover_image.encode(:gif) # returns an ExtendedTempObject, with similar properties
|
96
|
-
temp_object.mime_type # => 'image/gif'
|
97
|
-
album.cover_image.mime_type # => 'image/png' (no change)
|
98
|
-
|
99
|
-
album.cover_image.encode!(:gif) # (operates on self)
|
100
|
-
album.cover_image.mime_type # => 'image/gif'
|
101
|
-
|
102
|
-
The encoding is implemented by the {Dragonfly} app's registered encoders (which will usually just be one) - see {file:Encoding.md Encoding}
|
103
|
-
|
104
|
-
If we have a combination of processing and encoding that we often use, e.g.
|
105
|
-
|
106
|
-
album.cover_image.process(:resize_and_crop, :width => 300, :height => 200, :gravity => 'nw').encode(:gif)
|
107
|
-
|
108
|
-
then we can register a shortcut (see {file:Shortcuts.md Shortcuts}) and use that with `transform`, e.g.
|
109
|
-
|
110
|
-
album.cover_image.transform('300x200#nw', :gif) # returns an ExtendedTempObject, like process and encode above
|
111
|
-
album.cover_image.transform!('300x200#nw', :gif) # (operates on self)
|
112
|
-
|
113
|
-
Persisting
|
114
|
-
----------
|
115
|
-
When the model is saved, a before_save callback persists the data to the {Dragonfly::App App}'s configured datastore (see {file:DataStorage.md DataStorage})
|
116
|
-
The uid column is then filled in.
|
117
|
-
|
118
|
-
album = Album.new
|
119
|
-
|
120
|
-
album.cover_image_uid # => nil
|
121
|
-
|
122
|
-
album.cover_image = File.new('path/to/my_image.png')
|
123
|
-
album.cover_image_uid # => 'PENDING' (actually a Dragonfly::ActiveRecordExtensions::PendingUID)
|
124
|
-
|
125
|
-
album.save
|
126
|
-
album.cover_image_uid # => '2009/12/05/170406_file' (some unique uid, used by the datastore)
|
127
|
-
|
128
|
-
URLs
|
129
|
-
----
|
130
|
-
Once the model is saved, we can get a url for the image (which is served by the Dragonfly {Dragonfly::App App} itself):
|
131
|
-
|
132
|
-
album.cover_image.url # => '/media/2009/12/05/170406_file' (Note there is no extension)
|
133
|
-
album.cover_image.url(:png) # => '/media/2009/12/05/170406_file.png'
|
134
|
-
album.cover_image.url('300x200#nw', :gif) # => '/media/2009/12/05/170406_file.tif?m=resize_and_crop&o[height]=...'
|
135
|
-
|
136
|
-
Note that any arguments given to `url` are of the same form as those used for `transform`, i.e. those registered as shortcuts (see {file:Shortcuts.md Shortcuts})
|
137
|
-
These urls are what you would use in, for example, html views.
|
138
|
-
|
139
|
-
Validations
|
140
|
-
-----------
|
141
|
-
`validates_presence_of` and `validates_size_of` work out of the box, and Dragonfly provides two more,
|
142
|
-
`validates_property` and `validates_mime_type_of` (which is actually just a thin wrapper around `validates_property`).
|
143
|
-
|
144
|
-
class Album
|
145
|
-
|
146
|
-
validates_presence_of :cover_image
|
147
|
-
validates_size_of :cover_image, :maximum => 500.kilobytes
|
148
|
-
validates_mime_type_of :cover_image, :in => %w(image/jpeg image/png image/gif)
|
149
|
-
validates_property :width, :of => :cover_image, :in => (0..400)
|
150
|
-
|
151
|
-
# ...
|
152
|
-
end
|
153
|
-
|
154
|
-
The property argument of `validates_property` will generally be one of the registered analyser properties as described in {file:Analysers.md Analysers}.
|
155
|
-
However it would actually work for arbitrary properties, including those of non-dragonfly model attributes.
|
156
|
-
See {Dragonfly::ActiveRecordExtensions::Validations Validations} for more info.
|
157
|
-
|
158
|
-
Name and extension
|
159
|
-
------------------
|
160
|
-
If the object assigned is a file, or responds to `original_filename` (as is the case with file uploads in Rails, etc.), then `name` and `ext` will be set.
|
161
|
-
|
162
|
-
album.cover_image = File.new('path/to/my_image.png')
|
163
|
-
|
164
|
-
album.cover_image.name # => 'my_image.png'
|
165
|
-
album.cover_image.ext # => 'png'
|
166
|
-
|
167
|
-
|
168
|
-
'Magic' Attributes
|
169
|
-
------------------
|
170
|
-
The only model column necessary for the migration, as described above, is the uid column, e.g. `cover_image_uid`.
|
171
|
-
However, in many cases you may want to record some other properties in the database, whether it be for using in sql queries, or
|
172
|
-
for caching an attribute for performance reasons.
|
173
|
-
|
174
|
-
For the properties `name`, `ext`, `size` and any of the registered analysis methods (e.g. `width`, etc. in the examples above),
|
175
|
-
this is done automatically for you, if the corresponding column exists.
|
176
|
-
For example:
|
177
|
-
|
178
|
-
In the migration:
|
179
|
-
|
180
|
-
add_column :albums, :cover_image_ext, :string
|
181
|
-
add_column :albums, :cover_image_width, :integer
|
182
|
-
|
183
|
-
These are automatically set when assigned:
|
184
|
-
|
185
|
-
album.cover_image = File.new('path/to/my_image.png')
|
186
|
-
|
187
|
-
album.cover_image_ext # => 'png'
|
188
|
-
album.cover_image_width # => 280
|
189
|
-
|
190
|
-
They can be used to avoid retrieving data from the datastore for analysis (e.g. if you've used something like S3 to store data - see {file:DataStorage.md DataStorage})
|
191
|
-
|
192
|
-
album = Album.first
|
193
|
-
|
194
|
-
album.cover_image.ext # => 'png' - no need to retrieve data - takes it from `cover_image_ext`
|
195
|
-
album.cover_image.width # => 280 - no need to retrieve data - takes it from `cover_image_width`
|
196
|
-
album.cover_image.size # => 134507 - but it needs to retrieve data from the data store, then analyse
|
@@ -1,189 +0,0 @@
|
|
1
|
-
Example Use Cases
|
2
|
-
=================
|
3
|
-
|
4
|
-
This document is concerned with different Dragonfly configurations, for various use cases.
|
5
|
-
|
6
|
-
In a Rails app the configuration would generally be done in an initializer.
|
7
|
-
|
8
|
-
In other Rack-based apps it could be config.ru, or anywhere where the application is generally set up.
|
9
|
-
|
10
|
-
Image thumbnails in Rails
|
11
|
-
-------------------------
|
12
|
-
See {file:UsingWithRails}
|
13
|
-
|
14
|
-
|
15
|
-
Image thumbnails in Rails, hosted on Heroku with S3 storage
|
16
|
-
-----------------------------------------------------------
|
17
|
-
{http://heroku.com Heroku} is a commonly used platform for hosting Rack-based websites.
|
18
|
-
The following assumes your site is set up for deployment onto Heroku.
|
19
|
-
|
20
|
-
The default configuration won't work out of the box for Heroku, because
|
21
|
-
|
22
|
-
- Heroku doesn't allow saving files to the filesystem (although it does use tempfiles)
|
23
|
-
- We won't need {http://tomayko.com/src/rack-cache/ Rack::Cache} on Heroku because it already uses the caching proxy {http://varnish.projects.linpro.no/ Varnish}, which we can make use of
|
24
|
-
|
25
|
-
Instead of the normal {Dragonfly::DataStorage::FileDataStore FileDataStore}, we can use the {Dragonfly::DataStorage::S3DataStore S3DataStore}.
|
26
|
-
Amazon's {http://aws.amazon.com/s3 S3} is a commonly used platform for storing data.
|
27
|
-
|
28
|
-
The following assumes you have an S3 account set up, and know your provided 'access key' and 'secret'.
|
29
|
-
|
30
|
-
### Rails 2.3
|
31
|
-
|
32
|
-
environment.rb:
|
33
|
-
|
34
|
-
config.gem 'rmagick', :lib => 'RMagick'
|
35
|
-
gem 'aws-s3', :lib => 'aws/s3'
|
36
|
-
config.gem 'dragonfly'
|
37
|
-
|
38
|
-
and
|
39
|
-
.gems:
|
40
|
-
|
41
|
-
dragonfly
|
42
|
-
aws-s3
|
43
|
-
|
44
|
-
### Rails 3
|
45
|
-
|
46
|
-
Gemfile:
|
47
|
-
|
48
|
-
gem 'rmagick', '2.12.2', :require => 'RMagick'
|
49
|
-
gem 'aws-s3', :require => 'aws/s3'
|
50
|
-
gem 'dragonfly'
|
51
|
-
|
52
|
-
Apparently to use Bundler you need to switch to the 'Bamboo' stack - see {http://docs.heroku.com/bamboo}
|
53
|
-
|
54
|
-
### All versions
|
55
|
-
|
56
|
-
Initializer (e.g. config/initializers/dragonfly.rb):
|
57
|
-
|
58
|
-
require 'dragonfly'
|
59
|
-
app = Dragonfly::App[:images]
|
60
|
-
app.configure_with(Dragonfly::Config::HerokuRailsImages, 'my_bucket_name')
|
61
|
-
Dragonfly.active_record_macro(:image, app)
|
62
|
-
|
63
|
-
The datastore remains as the {Dragonfly::DataStorage::FileDataStore FileDataStore} for non-production environments.
|
64
|
-
|
65
|
-
environment.rb (application.rb in Rails 3):
|
66
|
-
|
67
|
-
config.middleware.insert_after 'Rack::Lock', 'Dragonfly::Middleware', :images
|
68
|
-
|
69
|
-
We don't store the S3 access key and secret in the repository, rather we use Heroku's
|
70
|
-
{http://docs.heroku.com/config-vars config variables} using the command line (we only have to do this once).
|
71
|
-
|
72
|
-
From your app's directory:
|
73
|
-
|
74
|
-
heroku config:add S3_KEY=XXXXXXXXX S3_SECRET=XXXXXXXXXX
|
75
|
-
|
76
|
-
Obviously you replace 'XXXXXXXXX' with your access key and secret.
|
77
|
-
|
78
|
-
Now you can benefit use Dragonfly in the normal way, benefitting from super-fast images served straight from Heroku's cache!
|
79
|
-
|
80
|
-
NOTE: HEROKU'S CACHE IS CLEARED EVERY TIME YOU DEPLOY.
|
81
|
-
If this is an issue you may want to look into using something like a Memcached add-on, or maybe an after-deploy hook for hitting specific Dragonfly urls you want to cache, etc.
|
82
|
-
It won't be a problem for most sites though.
|
83
|
-
|
84
|
-
|
85
|
-
Attaching files to ActiveRecord models with no processing or encoding
|
86
|
-
---------------------------------------------------------------------
|
87
|
-
Although Dragonfly is normally concerned with processing and encoding, you may want to just use it with arbitrary uploaded files
|
88
|
-
(e.g. .doc, .xls, .pdf files, etc.) without processing or encoding them, so as to still benefit from the {file:ActiveRecord ActiveRecord Extensions} API.
|
89
|
-
|
90
|
-
The below shows how to do it in Rails, but the principles are the same in any context.
|
91
|
-
|
92
|
-
Initializer, e.g. config/initializers/dragonfly.rb:
|
93
|
-
|
94
|
-
require 'dragonfly'
|
95
|
-
|
96
|
-
app = Dragonfly::App[:attachments]
|
97
|
-
app.configure_with(Dragonfly::Config::RailsDefaults) do |c|
|
98
|
-
c.register_analyser(Dragonfly::Analysis::FileCommandAnalyser)
|
99
|
-
c.register_encoder(Dragonfly::Encoding::TransparentEncoder)
|
100
|
-
end
|
101
|
-
Dragonfly.active_record_macro(:attachment, app)
|
102
|
-
|
103
|
-
The {Dragonfly::Analysis::FileCommandAnalyser FileCommandAnalyser} is needed to know the mime-type of the content,
|
104
|
-
and the {Dragonfly::Encoding::TransparentEncoder TransparentEncoder} is like a 'dummy' encoder which does nothing
|
105
|
-
(the way to switch off encoding will be simplified in future versions of Dragonfly).
|
106
|
-
|
107
|
-
environment.rb (application.rb in Rails 3):
|
108
|
-
|
109
|
-
config.middleware.insert_after 'Rack::Lock', 'Dragonfly::Middleware', :attachments
|
110
|
-
|
111
|
-
If a user uploads a file called 'report.pdf', then normally the original file extension will be lost.
|
112
|
-
Thankfully, to record it is as easy as adding an 'ext' column as well as the usual uid column to our migration
|
113
|
-
(see {file:ActiveRecord} for more info about 'magic attributes'):
|
114
|
-
|
115
|
-
add_column :my_models, :attachment_uid, :string
|
116
|
-
add_column :my_models, :attachment_ext, :string
|
117
|
-
|
118
|
-
Then we include a helper method in our model for setting the correct file extension when we link to the attachment:
|
119
|
-
|
120
|
-
class MyModel < ActiveRecord::Base
|
121
|
-
|
122
|
-
attachment_accessor :attachment
|
123
|
-
|
124
|
-
def url_for_attachment
|
125
|
-
attachment.url :format => attachment_ext
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
Now we can add links to the attached file in our views:
|
130
|
-
|
131
|
-
<%= link_to 'Attachment', @my_model.url_for_attachment %>
|
132
|
-
|
133
|
-
|
134
|
-
Generating test data
|
135
|
-
--------------------
|
136
|
-
We may want to generate a load of test data in a test / populate script.
|
137
|
-
|
138
|
-
Each {Dragonfly::App Dragonfly App} has a 'generate' method, which returns an {Dragonfly::ExtendedTempObject ExtendedTempObject} with generated data.
|
139
|
-
The actual generation is delegated to the registered processors (along with any args passed in).
|
140
|
-
|
141
|
-
For example, if our app is registered with the {Dragonfly::Processing::RMagickProcessor RMagickProcessor} (which is already done if using with one of
|
142
|
-
the RMagick/RailsImage configurations)
|
143
|
-
|
144
|
-
Dragonfly::App[:my_app].register_processor(Dragonfly::Processing::RMagickProcessor)
|
145
|
-
|
146
|
-
then we can generate images of different sizes/formats):
|
147
|
-
|
148
|
-
image = Dragonfly::App[:my_app].generate(300, 200) # creates a png image of size 300x200 (as an ExtendedTempObject)
|
149
|
-
image.to_file('out.png') # writes to file 'out.png'
|
150
|
-
image = Dragonfly::App[:my_app].generate(50, 50, :gif) # creates a gif image of size 50x50
|
151
|
-
|
152
|
-
|
153
|
-
Text image replacement
|
154
|
-
----------------------
|
155
|
-
A common technique for making sure a specific font is displayed on a website is replacing text with images.
|
156
|
-
|
157
|
-
We can easily use Dragonfly to do this on-the-fly.
|
158
|
-
|
159
|
-
Configuration (e.g. initializer in Rails):
|
160
|
-
|
161
|
-
require 'dragonfly'
|
162
|
-
Dragonfly::App[:text].configure_with(Dragonfly::Config::RMagickText) do |c|
|
163
|
-
c.url_handler.path_prefix = '/text'
|
164
|
-
end
|
165
|
-
|
166
|
-
If using Rails, then in environment.rb (application.rb in Rails 3):
|
167
|
-
|
168
|
-
config.middleware.insert_after 'Rack::Lock', 'Dragonfly::Middleware', :text
|
169
|
-
|
170
|
-
You probably will want to insert Rack::Cache too or use some other caching proxy - see {file:UsingWithRails}.
|
171
|
-
|
172
|
-
Then when we visit a url like
|
173
|
-
|
174
|
-
url = Dragonfly::App[:text].url_for('some text', :text, :font_size => 30, :font_family => 'Monaco')
|
175
|
-
|
176
|
-
we get a png image of the text. We could easily wrap this in some kind of helper if we use it often.
|
177
|
-
|
178
|
-
This configuration uses the {Dragonfly::Processing::RMagickTextProcessor RMagickTextProcessor} processor.
|
179
|
-
Options can be specified either css-like (e.g. `'font-family' => 'Helvetica'`), or with underscore-style symbols
|
180
|
-
(e.g. `:font_family => 'Helvetica'`).
|
181
|
-
|
182
|
-
Available options are `font` (see {http://www.imagemagick.org/RMagick/doc/draw.html#font}),
|
183
|
-
`'font-family'`,
|
184
|
-
`'stroke_color'`,
|
185
|
-
`'color'`,
|
186
|
-
`'font_style'`,
|
187
|
-
`'font_stretch'`,
|
188
|
-
`'font_weight'` and
|
189
|
-
`'padding'` (or `'padding-left'`, `'padding-top'`, etc.)
|
@@ -1,114 +0,0 @@
|
|
1
|
-
Getting Started
|
2
|
-
===============
|
3
|
-
|
4
|
-
Below is a general guide for setting up and using Dragonfly.
|
5
|
-
|
6
|
-
For setting up with Ruby on Rails, see {file:UsingWithRails UsingWithRails}.
|
7
|
-
|
8
|
-
For more info about using Rack applications, see the docs at {http://rack.rubyforge.org/}
|
9
|
-
|
10
|
-
Running as a Standalone Rack Application
|
11
|
-
----------------------------------------
|
12
|
-
|
13
|
-
Basic usage of a dragonfly app involves storing data (e.g. images),
|
14
|
-
then serving that data, either in its original form, processed, encoded or both.
|
15
|
-
|
16
|
-
A basic rackup file `config.ru`:
|
17
|
-
|
18
|
-
require 'rubygems'
|
19
|
-
require 'dragonfly'
|
20
|
-
|
21
|
-
Dragonfly::App[:my_app_name].configure do |c|
|
22
|
-
# ...
|
23
|
-
c.some_attribute = 'blah'
|
24
|
-
# ...
|
25
|
-
end
|
26
|
-
|
27
|
-
run Dragonfly:App[:my_app_name]
|
28
|
-
|
29
|
-
As you can see, this involves instantiating an app, configuring it (how data is stored,
|
30
|
-
processing, encoding, etc.), then running it.
|
31
|
-
|
32
|
-
You can have multiple dragonfly apps, each with their own configuration.
|
33
|
-
Each app has a name, and is referred to by that name.
|
34
|
-
|
35
|
-
Dragonfly::App[:images] # ===> Creates an app called 'images'
|
36
|
-
Dragonfly::App[:images] # ===> Refers to the already created app 'images'
|
37
|
-
|
38
|
-
Example: Using to serve resized images
|
39
|
-
--------------------------------------
|
40
|
-
|
41
|
-
`config.ru`:
|
42
|
-
|
43
|
-
require 'rubygems'
|
44
|
-
require 'dragonfly'
|
45
|
-
require 'rack/cache'
|
46
|
-
|
47
|
-
app = Dragonfly::App[:images]
|
48
|
-
app.configure_with(Dragonfly::Config::RMagickImages)
|
49
|
-
|
50
|
-
use Rack::Cache,
|
51
|
-
:verbose => true,
|
52
|
-
:metastore => 'file:/var/cache/rack/meta',
|
53
|
-
:entitystore => 'file:/var/cache/rack/body'
|
54
|
-
|
55
|
-
run app
|
56
|
-
|
57
|
-
This configures the app to use the RMagick {Dragonfly::Processing::RMagickProcessor processor},
|
58
|
-
{Dragonfly::Encoding::RMagickEncoder encoder} and {Dragonfly::Analysis::RMagickAnalyser analyser}.
|
59
|
-
By default the {Dragonfly::DataStorage::FileDataStore file data store} is used.
|
60
|
-
|
61
|
-
Elsewhere in our code:
|
62
|
-
|
63
|
-
app = Dragonfly::App[:images]
|
64
|
-
|
65
|
-
# Store
|
66
|
-
uid = app.store(File.new('path/to/image.png')) # ===> returns a unique uid for that image, "2009/11/29/145804_file"
|
67
|
-
|
68
|
-
# Get the url for a thumbnail
|
69
|
-
url = app.url_for(uid, '30x30', :gif) # ===> "/2009/11/29/145804_file.gif?m=resize&o[geometry]=30x30"
|
70
|
-
|
71
|
-
Now when we visit the url `/2009/11/29/145804_file.gif?m=resize&o[geometry]=30x30` in the browser, we get the resized
|
72
|
-
image!
|
73
|
-
|
74
|
-
Caching
|
75
|
-
-------
|
76
|
-
Processing and encoding can be an expensive operation. The first time we visit the url,
|
77
|
-
the image is processed, and there might be a short delay and getting the response.
|
78
|
-
|
79
|
-
However, dragonfly apps send `Cache-Control` and `ETag` headers in the response, so we can easily put a caching
|
80
|
-
proxy like {http://varnish.projects.linpro.no Varnish}, {http://www.squid-cache.org Squid},
|
81
|
-
{http://tomayko.com/src/rack-cache/ Rack::Cache}, etc. in front of the app.
|
82
|
-
|
83
|
-
In the example above, we've put the middleware {http://tomayko.com/src/rack-cache/ Rack::Cache} in front of the app.
|
84
|
-
So although the first time we access the url the content is processed, every time after that it is received from the
|
85
|
-
cache, and is served super quick!
|
86
|
-
|
87
|
-
Avoiding Denial-of-service attacks
|
88
|
-
----------------------------------
|
89
|
-
The url given above, `/2009/11/29/145804_file.gif?m=resize&o[geometry]=30x30`, could easily be modified to
|
90
|
-
generate all different sizes of thumbnails, just by changing the size, e.g.
|
91
|
-
|
92
|
-
`/2009/11/29/145804_file.gif?m=resize&o[geometry]=30x31`,
|
93
|
-
|
94
|
-
`/2009/11/29/145804_file.gif?m=resize&o[geometry]=30x32`,
|
95
|
-
|
96
|
-
etc.
|
97
|
-
|
98
|
-
Therefore the app can protect the url by generating a unique sha from a secret specified by you
|
99
|
-
|
100
|
-
Dragonfly::App[:images].url_handler.configure do |c|
|
101
|
-
c.protect_from_dos_attacks = true # Actually this is true by default
|
102
|
-
c.secret = 'You should supply some random secret here'
|
103
|
-
end
|
104
|
-
|
105
|
-
Then the required urls become something more like
|
106
|
-
|
107
|
-
`/2009/12/10/215214_file.gif?m=resize&o[geometry]=30x30&s=aa78e877ad3f6bc9`,
|
108
|
-
|
109
|
-
with a sha parameter on the end.
|
110
|
-
If we try to hack this url to get a different thumbnail,
|
111
|
-
|
112
|
-
`/2009/12/10/215214_file.gif?m=resize&o[geometry]=30x31&s=aa78e877ad3f6bc9`,
|
113
|
-
|
114
|
-
then we get a 400 (bad parameters) error.
|