Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From \$16.50/m

Length:MediumLanguages:

This is the last article in the "Uploading with Rails" series. In the past couple of months we have already discussed the Shrine, Dragonfly, and Carrierwave gems. Today's guest is Paperclip by Thoughtbot, a company which manages gems such as FactoryGirl and Bourbon.

Paperclip is probably the most popular attachment management solution for Rails (more than 13 million downloads), and for a good reason: it has lots of features, a great community, and thorough documentation. So hopefully you are eager to learn more about this gem!

• Prepare for Paperclip installation
• Integrate Paperclip into a Rails application
• Generate thumbnails and process images
• Obfuscate URLs
• Store attachments on Amazon S3
• Secure files in the cloud by introducing authorization logic

## Preparations

Before we dive into the code, let's firstly discuss some caveats that you need to know about in order to successfully work with Paperclip:

• The latest version of Paperclip supports Rails 4.2+ and Ruby 2.1+. This gem can also be used without Rails.
• ImageMagick must be installed on your PC (it is available for all major platforms), and Paperclip should be able to access it.
• The file command should be available from the command line. For Windows it is available via Development Kit, so follow these instructions if you don't have DevKit installed yet.

When you are ready, go ahead and create a new Rails application (I will be using Rails 5.0.2) without the default testing suite:

### Integrating Paperclip

Drop in the Paperclip gem:

#### Gemfile

Install it:

Suppose we are creating a bookshelf application that presents a list of books. Each book will have a title, a description, an author's name, and a cover image. To start off, generate and apply the following migration:

Note the attachment type that is presented for us by Paperclip. Under the hood, it is going to create four fields for us:

• image_file_name
• image_file_size
• image_content_type
• image_updated_at

In contrast to the Shrine and Carrierwave gems, Paperclip does not have a separate file with configurations. All settings are defined inside the model itself using the has_attached_file method, so add it now:

#### models/book.rb

Before proceeding to the main part, let's also create a controller along with some views and routes.

### Creating the Controller, Views, and Routes

Our controller will be very basic:

#### books_controller.rb

Here is an index view and a partial:

Now the routes:

#### config/routes.rb

Nice! Now let's proceed to the main section and code the new action and a form.

All in all, doing uploads with Paperclip is easy. You only need to permit the corresponding attribute (in our case that's the image attribute, and we've already permitted it) and present a file field in your form. Let's do it now:

#### views/books/_form.html.erb

With this setup, you can already start performing uploads, but it's a good idea to introduce some validations as well.

Validations in Paperclip can be written using old helpers like validates_attachment_presence and validates_attachment_content_type or by employing the validates_attachment method to define multiple rules at once. Let's stick with the latter option:

#### models/book.rb

The code is really simple, as you can see. We require the file to be an image less than 1 megabyte in size. Note that if the validation fails, no post-processing will be performed. Paperclip already has some errors messages set for the English language, but if you want to support other languages, include the paperclip-i18n gem into your Gemfile.

Another important thing to mention is that Paperclip requires you to validate content type or filename of all attachments, otherwise it will raise an error. If you are 100% sure you don't need such validations (which is a rare case), use do_not_validate_attachment_file_type to explicitly say which fields shouldn't be checked.

Having added validations, let's also display error messages in our form:

## Displaying Images

Okay, so now the uploaded images should be displayed somehow. This is done by using the image_tag helper and a url method. Create a show view:

#### views/books/show.html.erb

We are displaying an image only if it really exists on the drive. Moreover, if you are using cloud storage, then Paperclip will perform a network request and check the file's existence. Of course, this operation may take some time, so you might use the present? or file? methods instead: they will simply make sure that the image_file_name field is populated with some content.

### URI Obfuscation

By default, all attachments are stored inside the public/system folder, so you will probably want to exclude it from the version control system:

#### .gitignore

However, displaying a full URI to the file may not always be a good idea, and you might need to obfuscate it somehow. The easiest way to enable obfuscation is by providing two parameters to the has_attached_file method:

#### models/book.rb

The proper values will be interpolated into the url automatically. hash_secret is a required field, and the easiest way to generate it is by using:

### Working With Styles

In many cases, it is preferred to display an image's thumbnail with some predefined width and height to save bandwidth. Paperclip solves this by using styles: each style has a name and a set of rules, like dimensions, format, quality, etc.

Suppose that we want the original image and its thumbnail to be converted to JPEG format. The thumbnail should be cropped to 300x300px:

#### models/book.rb

# is a geometry setting meaning: "Crop if necessary while maintaining aspect ratio."

We can also provide additional conversion options for each style. For example, let's provide 70% quality for thumbs while removing all metadata and 90% quality for the original image to make it a bit smaller:

#### models/book.rb

Nice! Display the thumbnail and provide the link to the original image:

#### views/books/show.html.erb

Note that unlike Carrierwave, for example, Paperclip does not allow you to write @book.image.thumb.url.

If, for some reason, you wish to manually update uploaded images, then you may use the following commands to refresh only thumbnails, add missing styles, or refresh all images:

• rake paperclip:refresh:thumbnails CLASS=Book
• rake paperclip:refresh:missing_styles CLASS=Book
• rake paperclip:refresh CLASS=Book

## Storing Files in the Cloud

Like all similar solutions, Paperclip allows you to upload files to the cloud. Out of the box, it has support for the S3 and Fog adapters, but there are third-party gems for Azure and Dropbox as well. In this section, I will show you how to integrate Paperclip with Amazon S3. First, drop in the aws-sdk gem:

Install it:

Next, provide a new set of options to the has_attached_file method:

#### models/book.rb

Here I am sticking to the dotenv-rails gem to set environment variables. You may provide all values directly inside the model, but do not make it publicly available.

What's interesting is that s3_credentials also accepts a path to a YAML file containing your keys and a bucket name. Moreover, you can set different values for different environments like this:

That's it! All the files you upload will now be located in your S3 bucket.

## Securing Files in the Cloud

Suppose you don't want your uploaded files to be available to everyone. By default, all uploads into the cloud are marked as public, meaning that anyone can open the file via the direct link. If you wish to introduce some authorization logic and check who is able to view the file, set the s3_permissions option to :private like this:

Now, however, no one except for you will be able to see the files. Therefore, let's create a new download action for the BooksController:

#### books_controller.rb

This action will simply redirect users to the image via an expiring link. Using this approach, you can now introduce any authorization logic using gems like CanCanCan or Pundit.

Don't forget to set the member route:

#### config/routes.rb

The helper should be used like this:

## Conclusion

We've come to the end of this article! Today we have seen Paperclip, an attachment management solution for Rails, in action and discussed its main concepts. There is much more to this gem, so be sure to view its documentation.

Also, I recommend visiting Paperclip's wiki page as it presents a list of "how to" tutorials and a bunch of links to third-party gems supporting Azure and Cloudinary and allowing you to easily minify uploaded files.

Thank you for staying with me, and see you soon!