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

Let’s say you want to add a picture field to your product model. Unfortunately, Rail’s Active Record doesn’t provide a native way to work with binary fields, like pictures. We can easily add a string field, 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 this example app with these commands:


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

Installation:

1. Declare DragonFly gem on Gemfile:

2. Install:


bundle install

3. Generate the initializer file:


rails g dragonfly

This command generates 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. Let’s 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 let Rails know this field isn’t a string, but a file by declaring:


Saving a file on a record field:

1. For our test, save this image in 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:

We are using “../../Images”, because my project is at “~/projects/test-dragonfly”, i.e., 2 folders from “~/Images”. Change it at your will.

4. Close the console and re-open it again to make sure that the image has been saved:

If “p.image” isn’t nil, it has been saved


Retrieving:

1. To get the file path, we use the url method:

2. Copy and paste the result on the browser and you will see the file:


http://localhost:3000/media/W1siZiIsIjIwMTUvMDkvMjYvNGFkMDdrNmhpbl8xLmpwZyJdXQ?sha=0d7af674c4891620

3. For images, we can use the “thumb” method. It generates a new version with different geometries:

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


Dragonfly is on-the-fly:

In the rails server window, we can see the logs showing the DragonFly is generating the file on the fly:

Every time that someone loads the thumb image on a browser, Dragonfly gets the original image and converts it, generating a new image.

To see this process happening, just reload the image on the browser and check the logs.

That’s why DragonFly has 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 an HTML image tag and the thumb() method to generate a smaller version of the image.

Simplified example:

2. Do the same on show.html.erb:

3. Check if the image exists:

If you run the above code you are going to 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 has an attached file or not, use Rail’s core nil? method or use the _stored? method:

OR


Using it with forms:

We’ve added images using the console. But how to save the image through a form?

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

1. Open _form.html.erb, create a new HTML field with the corresponding name, and use the “file_field” method to generate an HTML file field:

2. Like any other field, we must allow it in strong parameters:

Now we can send and save an image using the form.


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:

2. Install:


bundle install

3. Enable it on production:

4. Set your cache temp folder:

You don’t need to do this if you already use a server cache solution like Varnish or Nginx.


Validations:

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

As an example, let's say that you want to validate if the attachment is an image, so you can make sure your users aren't uploading movies or applications:


S3, Dropbox, Watermarks and More:

That concludes our basic DragonFly gem tutorial, but I will remind you that DragonFly has many more advanced resources: you can use Amazon S3, Dropbox, and other providers as your storage. You can change the image in so many ways on the fly: add a watermark, 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.

More info:

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

Close Menu