Choose which file upload library for your Rails project: Compare Active Storage, Shrine and other competitors

Tram Ho

Why do you need a library to support uploading files?

By default, Rails already supports the ability to receive an upload file from the browser. To upload a file from the browser, the user needs to send it to the file selection field in a multipart / form-data form , for example when uploading an avatar image:

Later on the controller, you will get params[:avatar] is an UploadedFile object containing the information and temporary path of the file you have just received. Finally, you can hard-save the file to the server (for example, in the public / uploads directory ), and then save the address to a field (such as avatar_path) in the database to appear as an avatar for the user. But what if:

  • Do you need to validate if the file you uploaded is an image file, or is it a pdf, mp3, … file? Or you want to limit the upload image size to less than 6MB?
  • How to upload files can then be cached on the server, in case the user enters other fields with errors (such as “the title is too short”) without having to select and reload the file from the beginning?
  • You want to change the size (resize) to 500×500 to fit the avatar frame, change the format from gif, png to jpg and compress , reduce the size (compress) the image, … In other words, you want to do. add some file reprocessing after uploading, preferably via a background job?
  • File uploads to the server need different versions . For example, if a user uploads a video, you want to generate artwork (thumbnails / posters), different quality (360p, 720p, Full HD, …), different formats (mp4, webm, ogg, …) to be compatible with many types of browsers and devices.

    In many cases, you also need to create more versions in an on-the-go style (only born when needed). So how to effectively manage multiple corresponding versions of the same upload file, and how to design the database appropriately (such as creating multiple columns in csdl: 360p_mp4, 720p_mp4, 360p_webm, …) ?

  • Instead of saving it on the server, you want to transfer files to S3, Google Cloud Storage, Azure Block Blobs, … as well as use with CDN ?

To do these things effectively and avoid the possibility of bugs or security issues , you should use a library to help support the upload / attach file.

Compare file upload libraries

Popular file upload libraries for Rails today: PaperClip, CarrierWave, Active Storage, Shrine, …

Paperclip

Paperclip is a pretty simple and compact gem upload file. But in a project that uses Paperclip, I encountered a case where it was necessary to cache files in case of fail validate (as the second idea above) and indeed this was very difficult to do with Paperclip. In short, Paperclip does not support uploading cache files .

To upload files using Paperclip with full basic information, you need to add up to 4 different columns in the database:

  • attachment_file_name
  • attachment_file_size
  • attachment_content_type
  • attachment_updated_at

Paperclip background processing can be done by delayedpaperclip . However, it still has many disadvantages. For example, background processing is only done after the file upload has finished everything: after uploading the file to the server and from the server to the external storage. This upload process is also forced in a transaction. This will greatly reduce the throughput of the system.

Moreover, Paperclip seems to have been deprecated , and the gem author switched to recommending Rails’ default ActiveStorage . As such, Paperclip is not a good choice for new Rails projects.

CarrierWave

As of the time of writing, CarrierWave is the most popular upload library for Rails. CarrierWave successfully fulfills the requirements as stated at the beginning of the article: from validate, processing to integration of external storage services. More prominent than Paperclip, CarrierWave supports caching uploaded files in case a validate failure occurs.

After a successful upload, CarrierWave stores the information in JSON format in a column in the database. For example, the user’s avatar will be saved in the column named avatar in the users table.

Although Direct Upload is not available, since CarrerWave already has cache support, it is not difficult for you to build this feature yourself or use additional gems like carrierwave_direct.

Carrierwave_backgrounder library will add features for file processing / deleting files in the background (background job). Overall, the background process is more complete than Paperclip. With CarrierWave, you need to use a separate attribute in the database to save the status of the processed background or not, but pay attention because it is not really thread-safe .

General conclusion: CarrierWave is a great option if you want to find a stable, mature file upload library for the Rails application.

Find out about CarrierWave at github.com/carrierwaveuploader/carrierwave

Active Storage

First of all, the biggest advantage of Active Storage is that it comes with new Rails (5, 6, …), and the future will be a common standard for file upload processing. Active Storage is great for Rails applications that require a simple file upload feature, but has also been tested and runs well on very large systems like Basecamp.

Unlike Paperclip and Carrierwave, Active Storage only uses two independent tables in the database to store information about uploaded files: activestorageblobs and activestorageattachments . By cleverly using polymorphism (polymorphic), Active Record helps us from the need for migration to create a new column if later on Rails application needs more file upload other schools. Although this approach makes querying more complex and risks N + 1 if not done carefully, this is still a breakthrough architecture . It simplifies and helps you not to worry about uploading.

Another strength of Active Storage is the ability to process On-the-fly , ie process files only when they are needed. This is useful for image files, when you do not know what size you need right after uploading. You only need to access the link with the corresponding width x height, Active Storage will create it for you. Features like S3 integration or Direct Upload also have full support.

A bit bananas when Active Storage launched but not yet available the validate feature , but fortunately has gem active_storage_validations help you.

Currently, with the uploaded files, Active Record only gives you a temporary path of the file and will quickly replace and expire. This helps keep uploaded files more secure but prevents you from taking advantage of CDN services to cache uploaded files, but will be fixed in Rails 6.1 .

In short, although Active Storage is still maturing and lacking many features, it is still being actively developed and officially supported by Rails. You should prioritize Active Storage for new Rails projects unless you need something special that Active Storage doesn’t currently meet.

Overview of Active Storage here: guides.rubyonrails.org/active_storage_overview.html

Shrine

Shrine

Shrine is also a gem for uploading / attaching emerging files and was born after the presence of Active Storage . Unlike the aforementioned libraries, the Shrine is not tied to the Rails and Active Record ecosystem . You can use it with Roda, Grape, Sinatra, … with any other ORM like Sequel, ROM, etc.Even if you only care about Rails / Active Record, integrating Shrine is still easy. easy.

Shrine is very light and very modular , which means you only need to choose to use any plugin you need. Shrine plugins are extremely diverse: from backgrounding support, multiple versions (versions, in Shrine 3 version called derivatives), to help extract metadata of any file format.

Shrine supports both file processing right after upload or on-the-fly processing like Active Storage. File processing is not necessarily for image files, but for whatever file format you want. You can use imagemagick / vips to process image files, or use run command shell with ffmpeg to process video files, …

Similar to CarrierWave, the information of each uploaded file type will be saved to a corresponding attribute in the corresponding table. For example, the uploaded user’s avatar will be stored in the avatar_data field in the table. The difference is that this field’s information is stored in JSON format and contains everything related to the file. For example, the avatar, Shrine will save the full path and metadata of the original file, and the path and metadata of all file versions created (versions / derivatives ).

The versions / derivatives feature also allows nesting as many levels as you like . Thus, the derivatives feature of Shrine is extremely suitable to solve the problem of multiple versions , especially when you need to save a variety of formats and different corresponding resolutions (mp4 / webm / ogg / … , 360p / 720p / …) as at the beginning of the article I said.

While the Shrine is a bit new and difficult to find online solutions that are more common than the previous libraries, Shrine has very detailed and complete documentation at shrinerb.com/docs/getting-started . The author is also actively developing this library, being friendly and often helping people at StackOverFlow or Reddit.

In conclusion, Shrine is a great and comprehensive uploading library that has taken care of all the requirements at the beginning of this article , and more. Shrine is also the only best option if you plan to use Roda / Sequel and other combos instead of Rails.

You can learn more about Shrine at shrinerb.com

TL; DR

The victory now belongs to Shrine ?

Refer

Best image uploader for Rails – Revisited

Share the news now

Source : Viblo