Creating a Custom Formtastic File Upload Input with Image Thumbnail

Just today, I ran into a situation where I wanted to modify the output generated by Formtastic while building an input element. In this particular scenario, the input field was a file input in which the user is expected to upload an image (PNG, JPG, or GIF). The customization I wanted was the ability to display the thumbnail of the current image if one has already been uploaded. A screenshot of the goal can be seen below.

My first approach was not at all elegant, although it achieved the goal. Depending on whether this is a new or existing record, I conditionally display the input differently.

There are a few problems with this. For one, I have repeated code between the two conditions. For example, the “hint” string is repeated, as well as the required setting. If I ever change the value in one spot, I have to remember to change it in the other. The other bigger problem is that my code is based upon the internal rendering performed by Formtastic. That means that if I ever update Formtastic, I need to make sure my custom HTML is updated to match as well.

Being somewhat of a perfectionist (well, at least as close as I can get) when it comes to my code, I wanted to address these issues right away rather than putting it on a “to do” list that would always take second place to other more important tasks.

After doing a bit of digging, I was reminded about Formtastic’s ability to utilize custom inputs. This can be seen on the “Creating New Inputs Based on Existing Ones” section of Formtastic’s README. In only 5-10 minutes of coding, I was able to completely refactor my original approach. First, I created my custom input class.

Note the additional :image option. In order to know what URL to render for the image, this option must be supplied. In the example above, I utilized a Proc object to generate the URL string. The Proc receives the object that the form is currently working with. In this case, it is the instance of my model.

Alternatively, I set up my AttachmentInput class to accept a Symbol representing the name of a method on the object to call, as well as any other object type that is simply cast to a String. Examples of these implementations can be seen below.

Formtastic inputs also accepts custom HTML options via :input_html, :wrapper_html, and :button_html Hash options depending on what is currently being generated. Similarly, a new :image_html Hash option can be provided when building an AttachmentInput.