Rails Refile tutorial

22 July 2015

If you’re a Rails programmer, you may already be familiar with gems that handle file uploads, such as Paperclip (made by the very awesome guys at thoughtbot).

The newest player in town for file uploads is Refile, and I decided to recently give it a try for a project, just to see what it’s all about. There is already a great intro video tutorial on how to get started on GoRails if you want to check it out. I mostly want to focus on the gotchas of using Refile currently.

Getting started is easy:

1) Add Refile and Refile Mini Magick to your Gemfile:

gem "refile", require: "refile/rails"
gem "refile-mini_magick"

2) IMPORTANT: Do not forget to also install ImageMagick, which you will need to make Refile work. I used Homebrew to install it with brew install imagemagick.

What happens if you don’t install ImageMagick? Literally nothing. You don’t see an error or anything, all that happens is that when you submit a form, the form resets because Rails can’t find ImageMagick so it doesn’t know what to do. Don’t forget to install ImageMagick! (If you’re deploying to Heroku, Heroku already “comes with it”, so to speak, so you don’t have to do anything special.)

3) Call the “attachment” method on whichever model you want the file to be related to. Refile is essentially a join table, so it will add a foreign key to the table where you want the file association. For example, if you want your users to have profile pics, you would add it to your User model.

class User < ActiveRecord::Base
  attachment :profile_image
  #You can name this whatever you want, really
end

4) The last step is to generate a migration to add the association with your model.

rails generate migration add_profile_image_to_users profile_image_id:string
rake db:migrate

Why is profile_image_id a string, you ask? Initially I thought profile_image_id should be an integer because it’s an id, but the id generated by refile is a string of random numbers and letters, that’s why it’s a string.

5) STOP! Are you using Devise? You will need to add profile_image_id to your strong params. There are different ways to do this. You can add the additional params to a method in your Application Controller, like so:

class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters
    devise_parameter_sanitizer.for(:user) << :profile_image_id
  end
end

OR, you can just add a Registrations Controller to handle it, which is what I did:

class RegistrationsController < Devise::RegistrationsController

  private

  def sign_up_params
    params.require(:user).permit( ... :profile_image_id)
  end

  def account_update_params
    params.require(:user).permit( ... :profile_image_id)
  end
end

Now it should work like a charm.

6) All you have to do now is use this helper method in your form <%= form.attachment_field :profile_image %>

7) But wait, there’s more! If you have followed this so far, things should be working pretty well for you now. However, after a while, the images are going to disappear from your site. That is because, by default, Refile stores images in a TMP folder, which gets flushed regularly. We don’t want this. You will want to store your images somewhere. Your options are:

There are gems for all of that, but some of them are not as updated as others.

Storing your images in Postgres

This worked fine for me locally, but once I deployed to Heroku, my application was very, very slow. I would recommend this only for very small files (say small gifs or pngs) and not large images or anything like that, the performance is just too slow.

Storing images using Fog

Fog is a Ruby gem that facilitates working with cloud-based services, like AWS, Google Web Services, Rackspace, etc. There is a Refile-specific version of this gem called Refile Fog but I do not recommend it. This gem has not been updated in long enough that the latest version of Refile is not compatible with Refile Fog. There is also a bug in which an attr_reader is missing for a method, which is an easy fix, but the gem also uses a deprecated Refile method called ‘verify uploadable’, which will throw out an error as well when you try to upload an image. Until those bugs are fixed, I would recommend not using Refile Fog.

Using Refile S3

Refile S3 is a gem that facilitates uploading Refile images to Amazon S3 and is by far the best option I saw out of all image storage options. It is very easy to get up and running. All you have to do is:

Install the gem: gem "refile-s3"

Add an initializer in your config/initializers folder, like so:

require "refile/s3"

aws = {
  access_key_id: "xyz",
  secret_access_key: "abc",
  region: "sa-east-1",
  bucket: "my-bucket",
}
Refile.cache = Refile::S3.new(prefix: "cache", **aws)
Refile.store = Refile::S3.new(prefix: "store", **aws)

Ruby Newbies beware: Do not, I repeat, DO NOT copy your AWS keys in that initializer file. You will want to use something like Figaro to hide your keys. If you do use Figaro, don’t forget to run figaro heroku:set -e production so Heroku can read your keys from Figaro, otherwise you will get an AWS credentials error.

And that is it, if you follow these steps and pay attention to the gotchas I outlined, you should be able to get Refile working pretty easily.