Dragonfly gem: images and files in Rails models (Paperclip alternative)

Let’s say you have a product model and wants to insert a picture on it. Unfortunately Rail’s Active Record doesn’t provides a native way to work with binary fields. We can easily add a string field, for example, but we can’t add a file field.

Dragonfly is a gem that extends ActiveRecord, allowing to have binary fields, like videos, files, or… pictures. It’s a good, or even better, alternative for the famous Paperclip gem.

Before start:

we’ve created/started this example app with these commands:

rails new test_df
cd test_df
rails g scaffold product title
rake db:migrate
rails s


1. declare DragonFly gem on Gemfile:

gem 'dragonfly'

2. install:

bundle install

3. generate the initializer file:

rails g dragonfly

PS: this will generate a “config/initializers/dragonfly.rb” file, which can be used to configure DragonFly’s core settings.

Creating an image field:

To add a normal field like “color“, you need to create a migration like this:

rails g migration add_field_to_product color

That’s the way we create a “color” string field. To create a Dragonfly field, you must to add an “_uid at the end of the name. So, in this example, the name would be “color_uid“. If the name is “photo“, it would be “photo_uid“. I will use “image” as the field name.

rails g migration add_field_to_product image_uid

Commit the changes with “rake db:migrate

rake db:migrate

Now we open our product model and tell Rails that this field isn’t a string, but a file by declaring:

dragonfly_accessor :image

Saving a file on a record field:

1. to our test, save this image on your Images folder as “1.jpg”:

2. open the rails console:

rails c

3. load the image file, get a record, put the image on it, and save it:

i = open('../../Images/1.jpg')
p = Product.last
p.image = i

PS: I’m using “../../Images”, because my project is at “~/projects/test_df”, i.e., 2 folders from “~/Images”. Change it at your will.

4. quit and go back again to make sure that the image was saved:

rails c
p = Product.last
# => 

PS: “p.image” isn’t nil, so it was saved


1. to get the file path, we use the “url” method:

# => "/media/W1siZiIsIjIwMTUvMDkvMjYvNGFkMDdrNmhpbl8xLmpwZyJdXQ?sha=0d7af674c4891620"

2. copy and paste this return on the browser and see the file:


3. for images we can use the “thumb” method that generates a new version with different geometries:

 => "/media/W1siZiIsIjIwMTUvMDkvMjcvOGNiNHFmbTU0M18xLmpwZyJdLFsicCIsInRodW1iIiwiODB4NjAiXV0?sha=1931e3387c6b54f5"

4. copy and paste the result on the browser and see the same image with new dimensions.

Dragonfly is on-the-fly:

On the rails server window, we can see the logs that show us that DragonFly is generating the file on the fly.
Webbrick Server

Everytime that someone loads the thumb image on a browser Dragonfly gets the original image and converts it, generating a new image. Just reload the image on the browser and see the logs.

That’s why DragonFly have this name – it’s on-the-fly, like a Dragonfly :)

Displaying on index.html and show.html:

Now, let’s show these images as thumbs on our product index.

1. Open “index.html.erb” and create a “thumb” column. Use “image_tag” to generate a html image tag and “thumb” method to generate a smaller version of the image.

Simplified example:

  <% @products.each do |product| %>
  <% end %>
Title Thumb
<%= product.name %> <%= image_tag product.image.thumb('80x60').url %>

List of Products

2. Do the same on show.html:

Image: <%= @product.image.url %>

3. Check if there’s an image:

If you run the above code you’ll probably get an exception. That’s because you have some records without any image attached, and you’re calling “thumb”/”url” methods from a nil value.

To check if the field have or not an attached file, we can use the Rail’s core “nil?” method or use the “_stored?” method:

<%= product.image_stored? ? image_tag(product.image.thumb('80x60').url) : "" %>


<%= product.image.nil? ? image_tag(product.image.thumb('80x60').url) : "" %>

Using forms:

We’ve added images manually on our model. But how to send the image using a form?

With DragonFly, we do it on the same way that we do with a normal field.

1. open _form.html.erb, create a new html field with the according name, and use the “file_field” method to generate a html file field:

<%= form_for(@product) do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :image %>
<%= f.file_field :image %>
<%= f.submit %>
<% end %>

2. as any normal field, we must allow it on strong parameters:

def product_params
  params.require(:product).permit(:title, :image)

Now we can send an image using the form.
Updating Picture

Performance with cache:

As DragonFly gem generates new versions on the fly, it can be very resource consuming, so we need to use a server cache solution.

Let’s add the rack-cache gem.

1. add to Gemfile:

gem 'rack-cache', require: 'rack/cache', group: :production

2. install:

bundle install

3. enable it on production:

config.action_dispatch.rack_cache = true

4. set your cache tmp folder:

class Application < Rails::Application
  if defined?(Rack::Cache)
    config.middleware.insert 0, Rack::Cache, {
      :verbose     => true, # log verbosity
      :metastore   => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/meta"), # URI encoded in case of spaces
      :entitystore => URI.encode("file:#{Rails.root}/tmp/dragonfly/cache/body")

Attention: of course you don’t need to do that if you already uses a server cache solution like Varnish or nginx.


Use “validates_property” method on the model to validate properties. Examples:

class Product < ActiveRecord::Base
  dragonfly_accessor :image

  validates_property :width, of: :image, in: (0..400)
  validates_property :mime_type, of: :image, in: %w(image/jpeg image/png)
  validates_property :size, of: :image, maximum: 500.kilobytes

As an example, let's say that you want to validate if the attachment is an image, that if you want to check if our users aren't uploading movies or applications:

class Product < ActiveRecord::Base
  dragonfly_accessor :image

  validates_property :mime_type, of: :image, in: %w(image)

S3, Dropbox, Watermarks and More:

That's conclude our basic DragonFly gem tutorial, but I will remind you that DragonFly has many advanced resources: you can use Amazon S3, Dropbox, and other providers as your storage, you can can change the image in so many ways on the fly, like add a waternarjm change to black and white, change the file format, and so on. You can also create your own plugins to extend DragonFly.

You can also work with other binary files like movies or apps, but I won't cover these things here. Maybe on another tutorial ;)

Common problems:

  • "404 - Not Found" error: If you get this, you probably don't have imagemagick installed. On Ubuntu, run a `sudo apt-get install imagemagick` to fix it.

DragonFly gem: https://markevans.github.io/dragonfly/
On GitHub: https://github.com/markevans/dragonfly
DragonFly author: Mark Evans

Close Menu