Skip to content

Upgrading from 0.9 to 1.0

Bill Ruddock edited this page Sep 3, 2018 · 27 revisions

Most of the changes in 1.0 affect the configuration and writing custom processors, rather than general usage of Dragonfly.

Basic steps for Rails upgrade

Here is a basic flow for upgrading most rails apps.

  1. comment out references in your code to Dragonfly[:my_app_name] and model dragonfly accessors (e.g. image_accessor)
  2. update Gemfile to dragonfly "~>1.0.3" and bundle install
  3. mv config/initializers/dragonfly.rb old_dragonfly.rb (keeping it temporarily for reference)
  4. rails generate dragonfly to generate a new config/initializers/dragonfly.rb
  5. Update references to Dragonfly apps anywhere in your code
  • If you're using just one Dragonfly app (the default) then e.g. Dragonfly[:images] becomes Dragonfly.app
  • If you're using more than one then e.g. Dragonfly[:images] and Dragonfly[:assets] becomes Dragonfly.app(:images) and Dragonfly.app(:assets)
  1. Check insertion of Dragonfly::Middleware (in dragonfly.rb/application.rb/environment files)
  • If using just one Dragonfly app then it should already be inserted in config/initializers/dragonfly.rb so you can remove it from other places (like application.rb, .rb, etc.)
  • If you're using more than one Dragonfly app then add a line for each in config/initializers/dragonfly.rb Rails.application.middleware.use Dragonfly::Middleware, :images Rails.application.middleware.use Dragonfly::Middleware, :assets
  1. Check correct usage of rack-cache - see http://markevans.github.io/dragonfly/rails#caching
  2. Update dragonfly.rb with any custom configuration you had in old_dragonfly.rb, but with the new syntax - see the sections below for more details. Afterwards you can delete old_dragonfly.rb
  3. Change xxx_accessor to dragonfly_accessor in models
  • If using multiple Dragonfly apps then add the :app option to specify which app the accessor refers to (not necessary if only using one) e.g. dragonfly_accessor :app => :images
  1. See "ImageMagick Changes" below for any changes in imagemagick processors/generators

Phew! Hopefully that is all!!

Dragonfly apps

Previously Dragonfly apps were all named and referred to using e.g.

Dragonfly[:images]

Apps are still named, but are referred to using

Dragonfly.app(:images)

However... there is now a default app

Dragonfly.app

For most purposes, you will only need to use the default app.

dragonfly_accessor

Previously you'd first define a macro

app.define_macro(ActiveRecord::Base, :image_accessor)

Then use it in a model

class MyModel < ActiveRecord::Base
  image_accessor :image
end

to define a model attachment accessor.

Now there's just one macro method, dragonfly_accessor, and you simply extend your class with Dragonfly::Model and use it

class MyModel
  extend Dragonfly::Model
  dragonfly_accessor :image
end

to use with a named Dragonfly app, e.g. Dragonfly.app(:assets), pass the :app option:

dragonfly_accessor :image, app: :assets

Middleware

Previously middleware was mounted with the app name

use Dragonfly::Middleware, :assets

It still is for named apps, however to mount the default app (which you'll usually be doing), there's no need for an argument

use Dragonfly::Middleware

Configuration

Previously configuration blocks yielded an object

app.configure do |c|
  c.url_format = "..."
end

now nothing is yielded and most xxx= methods are just xxx

app.configure do
  url_format "..."
end

Data stores

  c.datastore = Dragonfly::DataStorage::FileDataStore.new
  c.datastore.configure do |d|
    d.root_path = "some/path"
  end

becomes

datastore :file, root_path: 'some/path'
  • i.e. no block, just an options hash, and standard data stores are configured with a symbol.

S3, Mongo and Couch data stores

These have all been extracted into their own gems:

Custom Data Stores

Instead of implementing store and retrieve, these should respond to write and read. They are much the same, although they take a Dragonfly::Content object now, not a Dragonfly::TempObject (which has a similar interface, plus a few extra things like mime_type).

Content not found is signalled by returning nil from read, not by raising a Dragonfly::DataStorage::DataNotFound error.

Rails

The file 'dragonfly/rails/images' no longer exists - instead use the provided generator

rails generate dragonfly

Rack::Cache is NOT inserted by Dragonfly - see http://markevans.github.io/dragonfly/rails for more info.

Metadata

Meta data is now assumed to be serializable to and from JSON, so e.g. image.meta[:name] should become image.meta['name']

Misc config options

Below are some more version 0.9 configuration options and their 1.0 equivalents

c.response_headers['X-Something'] = '...'

is now

response_header 'X-Something', '...'

and

c.cache_duration = 1000000
c.content_filename = proc{...}
c.content_disposition = :attachment

no longer exist - you can customise these response headers yourself using

response_header 'Cache-Control', 'public, max-age=1000000'
response_header 'Content-Disposition' do |job, request, headers|
  'attachment; filename="..."'
end

If using fetch_file and fetch_url:

c.allow_fetch_file = true
c.allow_fetch_url = true

have been replaced by whitelists

  fetch_file_whitelist [
    "/home/images",
    /public/
  ]

  fetch_url_whitelist [
    "http://localhost:5000/image.png",
    /some\.domain/
  ]

If you need pre-Dragonfly-v0.9.12 urls to work, you'll need to do

allow_legacy_urls true

which now defaults to false.

c.fallback_mime_type = 'something/mental'

no longer exists (not really necessary)

c.log = Logger.new($stdout)

is no longer done on a per-app basis, but for the whole of Dragonfly:

Dragonfly.logger = Logger.new($stdout)

The following no longer exists:

c.trust_file_extensions = false

The mime type for the response "Content-Type" header is derived from the file extension (i.e. the extension is implicitly trusted). If you want to do any format validation or customise the "Content-Type" response header then they can do that yourself according to the requirements of your app.

URL options:

c.url_format = '...'
c.url_host = '...'
c.protect_from_dos_attacks = true
c.secret = 'This is my secret yeh!!'

simply become

url_format '...'
url_host '...'
protect_from_dos_attacks true
secret 'This is my secret yeh!!'

Mime-types:

c.register_mime_type(:egg, 'fried/egg')

is now

mime_type 'egg', 'fried/egg'

Remote serving options:

c.define_url do ... end
end
c.server.before_serve do ... end

is now

define_url do ... end
end
before_serve do ... end

(note no .server)

ImageMagick Changes

.jpg, .png and .gif processors no longer exist - use encode('png') instead or create your own processor.

.strip, .crop, .flip, .flop, .resize, .resize_and_crop and .greyscale processors no longer exist - use thumb instead or you can easily create your own processor

.depth, .number_of_colours no longer exist - create your own analyser

.convert("some args", :jpg) becomes .convert("some args", "format" => "jpg")

.generate(:plain, 400, 300, colour, :format => :gif) becomes .generate(:plain, 400, 300, 'color' => colour, 'format' => 'gif')

.generate(:plasma, 10, 10, :gif) becomes .generate(:plasma, 10, 10, 'format' => 'gif')

Previously you could customise imagemagick using

app.configure do |c|
  c.convert_command = "/opt/local/bin/convert"
  c.identify_command = "/opt/local/bin/identify"
  c.log_commands = true
end

Now these are passed to the call to plugin, and log_commands doesn't exist (it does log shell commands when the logger is set to debug mode).

app.configure do
  plugin :imagemagick,
    convert_command: "/opt/local/bin/convert"
    identify_command: "/opt/local/bin/identify"
end

Custom Processors, Generators and Analysers

There are no longer "encoders" - they were much the same as processors anyway, with the added ability to change the url and Content-Type response to reflect the new format, (e.g. jpeg -> png). Processors can now do this anyway so any "encoding" is now just done by processors.

Arguments passed to processors should be serializable to and from JSON

Processors now define a method on Job/Attachment objects, so instead of using

image.process(:optimize, 30)

you can use

image.optimize(30)

Previously registered processors took a Dragonfly::TempObject and returned something

c.processor.add :optimize do |temp_object, amount|
  tempfile = Tempfile.new(['dragonfly','png'])
  tempfile.binmode
  tempfile.close
  `optimize -a#{amount} -out "#{tempfile.path}" "#{temp_object.path}"`
  tempfile
end

Now they take a Dragonfly::Content, and update it, rather than returning anything. It has convenience methods to make using the shell and using other processors easier.

processor :optimize do |content, amount|
  content.shell_update, ext: 'png' do |old_path, new_path|
    "optimize -a#{amount} -out #{old_path} #{new_path}"
  end
end

Note c.processor.add simply becomes processor.

Previously you could register all the public methods of a class as processors

class MyProcessor
  def resize(temp_object, *args)
    # ...
  end
  
  def crop(temp_object, *args)
    # ...
  end
end

app.configure do |c|
  c.processor.register(MyProcessor) # registers resize and crop
end

You can no longer do this, and must register each in turn, either as a block or as an object that responds to call

class MyCropProcessor
  def call(content, *args)
    # ...
  end
end

app.configure do
  processor :resize do |content, *args|
    # ...
  end
  processor :crop, MyCropProcessor.new
end

This way processors can individually implement update_url to update the url when they're used (optional - see http://markevans.github.io/dragonfly/processors#implementing-the-processor).

The same goes for analysers and generators.

Previously you could define a shortcut using job, e.g. to do

image.black_and_white('30x30')

we'd configure

c.job :black_and_white do |size|
  process :greyscale
  process :thumb, size
  encode  :gif
end

This is unnecessary, because defining a black_and_white processor now defines a black_and_white method on Job/Attachment objects, and processors can now access other processors using Content#process!. So instead of using job we just define another processor

processor :black_and_white do |content, size|
  content.process!(:greyscale)
  content.process!(:thumb, size)
  content.process!(:encode, 'gif')
end

Actually we could have used content.process!(:thumb, size, 'format' => 'gif') in the example above but you get the idea.

Plugins

Previously we used

app.configure_with(:imagemagick)

We can still do this, but it's easier to use plugin inside a configuration block:

plugin :imagemagick

Custom plugins now need to implement call, not apply_configuration.

Logger

The default logger will now be dragonfly.log Set it to Rails.logger to streamline it.

Dragonfly.logger = Rails.logger