<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jean-Michel Gigault</title>
    <description>The latest articles on DEV Community by Jean-Michel Gigault (@jgigault).</description>
    <link>https://dev.to/jgigault</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F213450%2Fe397221b-dc39-4c15-a18a-8d21a7202ef7.jpeg</url>
      <title>DEV Community: Jean-Michel Gigault</title>
      <link>https://dev.to/jgigault</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jgigault"/>
    <language>en</language>
    <item>
      <title>Direct File Upload With Paperclip and S3-compatible Object Storage</title>
      <dc:creator>Jean-Michel Gigault</dc:creator>
      <pubDate>Wed, 21 Apr 2021 08:47:35 +0000</pubDate>
      <link>https://dev.to/jgigault/direct-file-upload-with-paperclip-and-s3-compatible-object-storage-375e</link>
      <guid>https://dev.to/jgigault/direct-file-upload-with-paperclip-and-s3-compatible-object-storage-375e</guid>
      <description>&lt;p&gt;As usual, I will take the opportunity of describing technical solutions to go further with the topic and talk about the why, the how and the whom, with the widest inclusive example I was able to cover. If you are only looking for the technical guidelines, go directly to the third section, or even quicker: open &lt;a href="https://github.com/perangusta/direct-upload-with-paperclip-sample-app"&gt;attached source code&lt;/a&gt; ;-)&lt;/p&gt;

&lt;p&gt;That being said, my name is Jean-Michel and I am a committed engineer at &lt;a href="https://www.per-angusta.com/en/our-engineering-team/"&gt;Per Angusta&lt;/a&gt;. We are building softwares for big companies to solve their need of Procurement Performance Management. We are coding with Ruby on Rails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Direct File Upload principles
&lt;/h3&gt;

&lt;p&gt;Implementing a file upload functionality is not an obvious challenge due to the multiple security concerns (&lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html"&gt;summarised by OWASP&lt;/a&gt;) and the technical implementation, the later being the sole topic of this blog post.&lt;/p&gt;

&lt;p&gt;Modern applications running on services like Heroku often have a connection to an Object Storage system behind the scene, in order to store files such as images and files uploads. Those applications therefore can face into multiple issues when they implement a simple upload interface that require data to transit through its layer. A user trying to upload a 100Mb file through such mechanism would lock a thread of the application during the file upload process, resulting in a reduced threads pool for other users to request the application (increased queue latency) and request timeouts due to hard limits of the hosting provider (the well-known &lt;a href="https://devcenter.heroku.com/articles/request-timeout"&gt;H12 error&lt;/a&gt; on Heroku).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lfKLbgZ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AJh5WI8lNLnnCREEGbwnfxQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lfKLbgZ7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AJh5WI8lNLnnCREEGbwnfxQ.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Be even more naive because request timeouts &lt;strong&gt;do not only occur with huge file uploads or downloads&lt;/strong&gt;. Since the COVID-19 pandemic started, working from home has become an even bigger concern for application editors providing features based on data transfer, because of the bandwidth being more and more based on users’ personal Internet access. At &lt;a href="https://www.per-angusta.com/en/"&gt;Per Angusta&lt;/a&gt;, we have been able to monitor an increased latency due to Internet bandwidth, especially with US-based users who are usually less well equipped with Internet access than Europeans.&lt;/p&gt;

&lt;p&gt;Direct File Upload consists in isolating the expensive data transfer between the Client and the Object Storage, bypassing the layer of the Application. The latter does only pilot the flow, handles the validations and handles expensive operations only in its controlled network. By “controlled network”, I mean both application and Object Storage are efficiently connected together with a stable bandwidth (for instance when both are hosted in the same data center).&lt;/p&gt;

&lt;p&gt;This is exactly the same purpose of pre-signed expiry URLs commonly used to display images on, or download files from, websites that use modern Object Storage connectors (such as Rails’ &lt;a href="https://github.com/rails/rails/blob/main/activestorage/app/controllers/active_storage/blobs/redirect_controller.rb"&gt;ActiveStorage&lt;/a&gt; component).&lt;/p&gt;

&lt;p&gt;The benefits of implementing Direct File Upload bring you the opportunity to increase the file size limits, which can be considered as a feature and not only a performance improvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why ActiveStorage does not fit with our needs
&lt;/h3&gt;

&lt;p&gt;And why to write this blog post today meanwhile Paperclip is &lt;a href="https://thoughtbot.com/blog/closing-the-trombone"&gt;deprecated since 2018&lt;/a&gt; by the maintainers in favour of ActiveStorage?&lt;/p&gt;

&lt;p&gt;To start with, &lt;strong&gt;it’s worth noticing that Paperclip is not dead&lt;/strong&gt; thanks to new active maintainers working on a fork named &lt;a href="https://github.com/kreeti/kt-paperclip/"&gt;kt-paperclip&lt;/a&gt;. &lt;strong&gt;However,&lt;/strong&gt; you would be well advised to start using, or to migrate to, ActiveStorage if you can. As part of Rails, this component has a guaranteed roadmap and qualified maintainers.&lt;/p&gt;

&lt;p&gt;Thus, you may have good reasons for not choosing to migrate, as we decided until now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The lack of customisable &lt;em&gt;Blob#key&lt;/em&gt; configuration, referred as “path” in Paperclip, and which my colleague Frantisek is by the way tackling in &lt;a href="https://github.com/rails/rails/pull/41004"&gt;PR #41004&lt;/a&gt; (please upvote!). Our use case is a base specification: As per our multi-tenancy strategy, &lt;strong&gt;we need to isolate files of clients in a clear manner&lt;/strong&gt; , prefixing all keys with clients identifiers. Relying on ActiveStorage would force us to be dependent on the database stored keys to determine the files owners, resulting in painful (or even risky) maintenance operations such as isolated backups, archiving and reversibility procedure.&lt;/li&gt;
&lt;li&gt;ActiveStorage has a great design but stands totally different from Paperclip’s. As well as with ActionText, data is stored in separate and dedicated tables &lt;em&gt;active_storage_blobs&lt;/em&gt; and &lt;em&gt;active_storage_attachments&lt;/em&gt;, whereas Paperclip invites the domain-level models to store the attributes (there are alternatives, as chosen above in my example of implementation). Having not to rework the models and their interactions can be considered as a pragmatic decision. Especially if you deeply embraced Paperclip’s design, there is no absolute obligation, whenever the association “Paperclip + deprecation” is scary.&lt;/li&gt;
&lt;li&gt;Some other developers reported us a few edge cases or painful implementation of blob manipulation, such as post-processing. Because we are not concerned, this may be speculating :-) Those issues are not specific to ActiveStorage’s pattern, but another reason why keeping a working solution in place may remain a good choice until you face into a real issue with it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Implementing Direct File Upload with Paperclip
&lt;/h3&gt;

&lt;p&gt;Prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Paperclip (&lt;a href="https://github.com/kreeti/kt-paperclip"&gt;forked&lt;/a&gt; or even &lt;a href="https://github.com/thoughtbot/paperclip"&gt;legacy&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/fog/fog-aws"&gt;Fog::Aws&lt;/a&gt; and &lt;a href="https://github.com/aws/aws-sdk-ruby"&gt;AWS S3 SDK&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;S3-compatible Object Storage&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://yarnpkg.com/package/jquery"&gt;jQuery&lt;/a&gt;, &lt;a href="https://yarnpkg.com/package/jquery-ui"&gt;jQuery-UI&lt;/a&gt;, &lt;a href="https://yarnpkg.com/package/blueimp-file-upload"&gt;jQuery File Upload&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;PostgreSQL (if the primary key is part of the path builder, &lt;a href="https://github.com/kreeti/kt-paperclip#understanding-storage"&gt;which is the default behaviour&lt;/a&gt; through &lt;em&gt;:id_partition&lt;/em&gt; key)&lt;/li&gt;
&lt;li&gt;Multipart upload is not supported&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Specifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A model called &lt;em&gt;Attachment&lt;/em&gt;, on which is implemented Paperclip with &lt;em&gt;has_attached_file :upload.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Domain-level models have many &lt;em&gt;attachments&lt;/em&gt; through a polymorphic association named “&lt;em&gt;attachable&lt;/em&gt;”.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Attachment&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:attachable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;polymorphic: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;optional: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;

  &lt;span class="n"&gt;has_attached_file&lt;/span&gt; &lt;span class="ss"&gt;:upload&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;To have the most inclusive example, this post and its related &lt;a href="https://github.com/perangusta/direct-upload-with-paperclip-sample-app"&gt;code source&lt;/a&gt; make the implementation of Direct File Upload compatible with Post Processing, Fingerprint, URI Obfuscating, &lt;em&gt;:path&lt;/em&gt; setting that includes the primary key, and also multiple file uploads.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;has_attached_file&lt;/span&gt; &lt;span class="ss"&gt;:upload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="ss"&gt;styles: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;medium: &lt;/span&gt;&lt;span class="s1"&gt;'300x300&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;thumb: &lt;/span&gt;&lt;span class="s1"&gt;'100x100&amp;gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="ss"&gt;path: &lt;/span&gt;&lt;span class="s1"&gt;':tenant/:class/:attachment/:hash/:style/:filename'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;hash_data: &lt;/span&gt;&lt;span class="s1"&gt;':id/:extension/:fingerprint/:updated_at'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AlA13dIS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AOcjfRbpv084Omqtp826Xvg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AlA13dIS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AOcjfRbpv084Omqtp826Xvg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Request pre-signed URL
&lt;/h4&gt;

&lt;p&gt;Let’s start with the assumption that your front page has a form with a file input, to which you have attached an event listener on submit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;directFileUpload&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[type="file"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;files&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;files&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// start upload process for each single file&lt;/span&gt;
    &lt;span class="nx"&gt;obtainPresignedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;form[data-direct-file-upload="true"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;directFileUpload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For each single file, we start the sequence of requests by obtaining a pre-signed URL from an endpoint of the application with the following specifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Method: POST&lt;/li&gt;
&lt;li&gt;URL: /direct_file_uploads&lt;/li&gt;
&lt;li&gt;Request parameters: The file name and file type, as provided by the browser from the file input&lt;/li&gt;
&lt;li&gt;Response: A pre-signed URL (upload_url) and a unique identifier (upload_key)
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;requestPresignedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/direct_file_uploads&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;authenticity_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;VALID_AUTHENTICITY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// go to step 2&lt;/span&gt;
      &lt;span class="nx"&gt;uploadFileUsingPresignedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;upload_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;upload_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A controller handles the request and prepares a pre-signed URL with the following specifications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;em&gt;upload_key&lt;/em&gt; is partially random to prevent from duplicates and to obfuscate the path to prevent clients from hacking other uploaded files.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;upload_key&lt;/em&gt; retains the file name to strengthen the step 4, and also to facilitate debug.&lt;/li&gt;
&lt;li&gt;The actual path where the file will be uploaded (&lt;em&gt;upload_path&lt;/em&gt;) must be partially built with a specific and hard-coded prefix (understand forced by the backend) in order to prevent clients from hacking and accessing other locations available in your bucket (there is no way to access parent directories using a path with S3, as you would expect on Unix using “..”).&lt;/li&gt;
&lt;li&gt;The file type is appended to headers in the field “Content-Type” to retain the typology of the file.&lt;/li&gt;
&lt;li&gt;The expiration of the link depends on your use case: The greater the size limit is accepted, the longer the expiry time must be. Think about choosing a short duration until you actually need to extend it.&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;upload_url&lt;/em&gt; is obtained using &lt;em&gt;put_object_url&lt;/em&gt; on storage connection. A storage connection can be instantiated using &lt;em&gt;Fog::Storage.new&lt;/em&gt; (please refer to the &lt;a href="https://github.com/perangusta/direct-upload-with-paperclip-sample-app"&gt;code source&lt;/a&gt; for an example).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DirectFileUploadsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="c1"&gt;# POST /direct\_file\_uploads&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="n"&gt;upload_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;SecureRandom&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:file&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="ss"&gt;:name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;upload_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"direct_file_uploads/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;upload_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

    &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:file&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="ss"&gt;:type&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;expires&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minutes&lt;/span&gt;
    &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Paperclip&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:bucket&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;upload_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;STORAGE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object_url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upload_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expires&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;upload_url: &lt;/span&gt;&lt;span class="n"&gt;upload_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;upload_key: &lt;/span&gt;&lt;span class="n"&gt;upload_key&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; 
           &lt;span class="ss"&gt;status: :created&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Upload file using pre-signed URL
&lt;/h4&gt;

&lt;p&gt;Once pre-signed URL is obtained, the browser si expected to start upload to it. In this example, I have been using the jQuery plugin called jQuery File Upload for compatibility, but you can adapt with your other libraries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“fileupload” capability is attached to a cloned form from the original form, to manage each single file individually to prevent conflicts of concurrent uploads.&lt;/li&gt;
&lt;li&gt;“fileInput” and “autoUpload” are disabled because we start the upload manually using “send” at the end of the function.&lt;/li&gt;
&lt;li&gt;“multipart” is disabled because I assume not to have found a working solution that does not break the file integrity ¯_(ツ)_/¯.&lt;/li&gt;
&lt;li&gt;The header “Content-Type” is filled with the file type as of pre-signed URL generation, otherwise S3 would reject the request.&lt;/li&gt;
&lt;li&gt;“paramName” is an arbitrary string to enforce a non-nested parameter name, which would not be correctly handled by S3.&lt;/li&gt;
&lt;li&gt;“dataType” is more or less arbitrarily set to XML, which is the format of S3 responses.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;uploadFileUsingPresignedURL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload_url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tmp_form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;tmp_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileupload&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;fileInput&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;upload_url&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PUT&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;autoUpload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;multipart&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;paramName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;XML&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;beforeSend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;xhr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;xhr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setRequestHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// go to step 3&lt;/span&gt;
      &lt;span class="nx"&gt;requestRecordCreation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;upload_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;

  &lt;span class="c1"&gt;// sending one file at a time&lt;/span&gt;
  &lt;span class="nx"&gt;tmp_form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fileupload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;send&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;files&lt;/span&gt;&lt;span class="p"&gt;:[&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In order to allow file uploads from browsers to S3, you have to update CORS settings of your bucket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AllowedHeaders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AllowedMethods"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"PUT"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"AllowedOrigins"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"http://127.0.0.1:3000"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;development&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"https://your-domain.com"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;production&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="s2"&gt;"https://*.your-domain.com"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;production&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ExposeHeaders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Request record creation
&lt;/h4&gt;

&lt;p&gt;Once upload is done, the browser can notify the application that the file is ready for being referenced into an Attachment record. This is more or less a standard “create” request on Attachment’s controller, to which we simply inject the upload_key obtained at step 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;requestRecordCreation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;upload_key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ajax&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/attachments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;dataType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;authenticity_token&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;VALID_AUTHENTICITY_TOKEN&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
      &lt;span class="na"&gt;upload_key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;upload_key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
      &lt;span class="na"&gt;attachment&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
        &lt;span class="na"&gt;attachable_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ATTACHABLE_TYPE&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;attachable_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ATTACHABLE_ID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  
        &lt;span class="c1"&gt;// put here other attributes if required  &lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// operation completed (step 6)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the backend, the controller would start looking like to that crazy standard implementation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AttachmentsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="c1"&gt;# POST /attachments&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@attachment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attachment_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;upload_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:upload_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;### STEPS 4-5-6 ###&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;attachment_params&lt;/span&gt;
    &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:attachment&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;permit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="ss"&gt;:attachable_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:attachable_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="c1"&gt;# put here others attributes' form if required&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Request file metadata or content
&lt;/h4&gt;

&lt;p&gt;Here is the tricky part of the implementation, and its easiness depends on the use cases you need to handle. You may also want to handle both proposed approaches depending on attachment types, when you have multiple ones in your application.&lt;/p&gt;

&lt;p&gt;Let’s start with the easiest one, and to some extent the safest one, which consists in letting Paperclip doing the job as if it was a simple file upload. The idea is to download the file back on the application layer and assign it to the record, so that all features that come with Paperclip work in a standard way. That also means that the application triggers an extra upload of the file to the object storage on record save, which sounds expensive, but we can rely on the fact that we “control” this part of the network, as mentioned in the blog post introduction.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eZdg2M3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AtJpgXl87FPttnL4YkBrYhg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eZdg2M3Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2AtJpgXl87FPttnL4YkBrYhg.png" alt=""&gt;&lt;/a&gt;Adjusted sequential diagram for the first approach&lt;/p&gt;

&lt;p&gt;If the cost of doing so is too expensive for your use case, you may be interested in the second proposed approach, which consists in faking the IO part of Paperclip by manually assembling all required information. This approach is cost-free because it just needs a few simple API requests, but it has a few limitations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post Processing are not triggered and you need to implement them in a different way, for instance in a background job (which sounds good by the way).&lt;/li&gt;
&lt;li&gt;Fingerprint must be set with the default algorithm (&lt;em&gt;Digest::MD5&lt;/em&gt;), based on what S3 is able to provide through &lt;em&gt;ETag&lt;/em&gt; header and &lt;a href="https://docs.aws.amazon.com/AmazonS3/latest/API/RESTCommonResponseHeaders.html"&gt;given that S3 encryption is set to SSE-S3 or plaintext&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;You have added hard validations on the file type or content, that require the file is physically present on the record while saving it.&lt;/li&gt;
&lt;li&gt;The path builder requires the primary key (by default &lt;em&gt;:id_partition&lt;/em&gt; or commonly &lt;em&gt;:id&lt;/em&gt;) and your database does not provide safe ways to predict the next value. If this is the only one limitation, a workaround consists in switching steps 5 and 6 together (save the record first, and then move the file to the final location), but this is not covered in the present example.&lt;/li&gt;
&lt;li&gt;Any other limitation I have not been able to cover while writing this blog post :-)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s go for the implementation of both solutions, differentiated by the boolean REQUIRES_DOWNLOAD, starting by building back the &lt;em&gt;upload_path&lt;/em&gt; and retrieving &lt;em&gt;bucket&lt;/em&gt; name accordingly with step 1:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AttachmentsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="c1"&gt;# POST /attachments&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="vi"&gt;@attachment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;attachment_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;upload_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:upload_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;upload_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"direct_file_uploads/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;upload_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Paperclip&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_options&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:bucket&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;REQUIRES_DOWNLOAD&lt;/span&gt;
      &lt;span class="c1"&gt;# [...]&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="c1"&gt;# [...]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="c1"&gt;### STEP 6 ###&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;# [...]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first approach is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Obtain a pre-signed URL to download the file. Note that it does not trigger any real API request.&lt;/li&gt;
&lt;li&gt;Ensure to have registered &lt;em&gt;Paperclip::UriAdapter&lt;/em&gt;, and do it only once from an initialiser file such as &lt;em&gt;config/initializers/paperclip.rb&lt;/em&gt;. I have simply put it here to facilitate the reading.&lt;/li&gt;
&lt;li&gt;Assign the URL to the attachment using &lt;em&gt;URI&lt;/em&gt;, and let’s Paperclip’s internal IO adapter processing the file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;REQUIRES_DOWNLOAD&lt;/span&gt;
  &lt;span class="n"&gt;download_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;STORAGE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;directories&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;key: &lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;key: &lt;/span&gt;&lt;span class="n"&gt;upload_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;url&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="no"&gt;Paperclip&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UriAdapter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;register&lt;/span&gt;
  &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;URI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;download_url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="c1"&gt;# [...]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second approach is custom because we need to fake Paperclip’s internals so that it builds valid paths. Paperclip uses &lt;a href="https://github.com/kreeti/kt-paperclip/blob/master/lib/paperclip/interpolations.rb"&gt;interpolations&lt;/a&gt; based on &lt;em&gt;:path&lt;/em&gt; setting. Each interpolation is based on a record’s attribute or attached file metadata, so that we have to ensure that all of them are pre-filled before calling the path builder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;“file_name”, “file_size”, “content_type” and “updated_at” are standard attributes brought by Paperclip when you follow the installation guidelines, whereas “fingerprint” is only applicable if you have enabled it explicitly.&lt;/li&gt;
&lt;li&gt;The sequence related to the primary key is only applicable if it is part of &lt;em&gt;:path&lt;/em&gt; or &lt;em&gt;:hash_data&lt;/em&gt; settings.&lt;/li&gt;
&lt;li&gt;“file_name” is inferred directly from &lt;em&gt;upload_path&lt;/em&gt;. We have made it possible at step 1.&lt;/li&gt;
&lt;li&gt;“file_size” and “content_type” are obtained from object’s headers.&lt;/li&gt;
&lt;li&gt;“updated_at” is an arbitrary timestamp, expected to be the current time.&lt;/li&gt;
&lt;li&gt;“fingerprint” is obtained from &lt;em&gt;ETag&lt;/em&gt; header (MD5 digest of the content)&lt;/li&gt;
&lt;li&gt;The value of the primary key of the record (which is not yet saved at this stage) is obtained using “nextval()” on the given sequence (PostgreSQL only). If you are using UUIDs, you would have certainly implemented a custom interpolation and so you are required to generate it manually at this stage. If you are using MySQL, I suggest to follow workarounds such as &lt;a href="http://www.microshell.com/database/mysql/emulating-nextval-function-to-get-sequence-in-mysql/"&gt;this one&lt;/a&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;REQUIRES_DOWNLOAD&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;STORAGE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;head_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upload_path&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="ss"&gt;:headers&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_file_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;upload_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;last&lt;/span&gt;
  &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_file_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Length'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_content_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_updated_at&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;current&lt;/span&gt;
  &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload_fingerprint&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'ETag'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/"/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;primary_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;primary_key&lt;/span&gt;
  &lt;span class="n"&gt;primary_key_sequence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"
      SELECT nextval(pg_get_serial_sequence(
        '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;', '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'
      ))
    "&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;primary_key_nextval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;primary_key_sequence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'nextval'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;public_send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;primary_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;="&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;primary_key_nextval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;### STEP 5 ###&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Move uploaded file to the right location
&lt;/h4&gt;

&lt;p&gt;When the first approach is chosen (REQUIRES_DOWNLOAD), the file is automatically uploaded to the right location by Paperclip, among with the post processed images, while saving the file at step 6.&lt;/p&gt;

&lt;p&gt;When the second approach is chosen (!REQUIRES_DOWNLOAD), this operation must be done manually. We have previously assigned all required attributes for &lt;em&gt;PaperclipAttachment#path&lt;/em&gt; to return the correct path of the file, so the operation simply consists in moving the file to that final destination. Thus, S3-compatible storage does not support “moving” files, therefore we have to make a “copy” using &lt;em&gt;copy_object&lt;/em&gt;. This request is a simple API request that does not require any data transfer between the application and the storage, the copy of the file is processed on S3 side.&lt;/p&gt;

&lt;p&gt;Finally, both approaches result in a duplicate file (the original one uploaded by the client at step 2) that remains on S3 with no use case except debug or history. I suggest to delete it using &lt;em&gt;delete_object&lt;/em&gt;, so that your bucket size does not grow at double speed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;REQUIRES_DOWNLOAD&lt;/span&gt;
  &lt;span class="c1"&gt;# [...]&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="c1"&gt;# [...]&lt;/span&gt;

  &lt;span class="n"&gt;final_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;path&lt;/span&gt;

  &lt;span class="no"&gt;STORAGE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upload_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;final_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;STORAGE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upload_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going a bit further is still required if you have enabled the versioning on your storage, and deletion is indeed a simple delete marker. To permanently delete the file, we have to perform a specific request using &lt;em&gt;get_bucket_object_versions&lt;/em&gt; and retrieve the version identifier of the object to append it to the &lt;em&gt;delete_object&lt;/em&gt; request:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;STORAGE_VERSIONING_ENABLED&lt;/span&gt;
  &lt;span class="n"&gt;versions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;STORAGE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_bucket_object_versions&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;prefix: &lt;/span&gt;&lt;span class="n"&gt;upload_path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;versions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;body&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Versions'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;first&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Version'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s1"&gt;'versionId'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'VersionId'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="no"&gt;STORAGE&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;upload_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  6. Save record and return status
&lt;/h4&gt;

&lt;p&gt;We are finally ready to save the record and return the status to the client, as we would do with any kind of ActiveRecord objects or if we were using simple file upload:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
  &lt;span class="c1"&gt;# [...]&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: :created&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@attachment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: :unprocessable_entity&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Code source
&lt;/h3&gt;

&lt;p&gt;You will find a working example in this &lt;a href="https://github.com/perangusta/direct-upload-with-paperclip-sample-app"&gt;sample app&lt;/a&gt; that covers all mentioned use cases, with a bit more logic.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Interested in joining an enthusiastic engineering team? We are recruiting talented people! &lt;a href="https://www.per-angusta.com/en/our-engineering-team/"&gt;Learn more about the team and our open positions here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>webdev</category>
      <category>s3</category>
    </item>
    <item>
      <title>Common Mistakes With Guard Clause Pattern</title>
      <dc:creator>Jean-Michel Gigault</dc:creator>
      <pubDate>Mon, 11 Jan 2021 10:47:05 +0000</pubDate>
      <link>https://dev.to/jgigault/common-mistakes-with-guard-clause-pattern-473k</link>
      <guid>https://dev.to/jgigault/common-mistakes-with-guard-clause-pattern-473k</guid>
      <description>&lt;p&gt;My name is Jean-Michel and I am a committed engineer at &lt;a href="https://www.per-angusta.com/"&gt;Per Angusta&lt;/a&gt;. I have tried to summarise my thoughts and experience about good and bad practices of the Guard Clause pattern, starting by common assumptions to applicable examples with code samples.&lt;/p&gt;

&lt;p&gt;Basically, a common mistake with Guard Clauses is to think that they are simple substitute for “if…else” statements. Of course they consist in “if…else” statements, but it’s not a simple musical game of chairs and it actually involves a design pattern with special meanings and consequences on code quality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EypuRm30--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ALTd5fh3yETed6B0s" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EypuRm30--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ALTd5fh3yETed6B0s" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@kaylaspeid?utm_source=medium&amp;amp;utm_medium=referral"&gt;Kayla Speid&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Guard Clause?
&lt;/h3&gt;

&lt;p&gt;A &lt;a href="https://en.m.wikipedia.org/wiki/Guard_(computer_science)"&gt;Guard Clause&lt;/a&gt;, also known as Early Return or Bouncer Pattern, is a common practice in programming, consisting in an early exit of a function based on preconditions check.&lt;/p&gt;

&lt;p&gt;It is nothing other than an “if…else” statement, but it provides with two benefits: It makes the code flatter by reducing number of indentation levels, and it allows exceptions handling to be placed at the beginning, making subroutines clearer to read.&lt;/p&gt;

&lt;p&gt;It is not limited to a specific programming language, however practices are more or less common across communities. For instance, in C programming, their usage is very common due to the basic need to handle null-pointers, but also due to strong Unix conventions that involves restriction of functions’ lengths in width and height (to facilitate edition within a terminal) and in order to optimise compilation time.&lt;/p&gt;

&lt;h3&gt;
  
  
  When to use a Guard Clause?
&lt;/h3&gt;

&lt;p&gt;I would summarise the answer into 3 fundamental assumptions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It helps with readability&lt;/li&gt;
&lt;li&gt;It has a strong and obvious link with the scope of the method&lt;/li&gt;
&lt;li&gt;It solves a significant problem (performance, stability, business issue)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If a guard clause does not verify at least 2 of those 3 assumptions, I would consider there probably is a bad design somewhere, and you should consider to split your algorithm into multiple subroutines (or simply not to use Guard Clause).&lt;/p&gt;

&lt;p&gt;I would add a tip: &lt;strong&gt;If&lt;/strong&gt;  &lt;strong&gt;a guard clause is not present at the beginning of a method, there are serious chances that you have a bad design somewhere.&lt;/strong&gt; But, be aware it’s not systematic.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. It helps with readability
&lt;/h4&gt;

&lt;p&gt;Implementing Guard Clauses while losing readability is almost a non-sense. Their existence is an answer to the lack of readability of nested “if…else” statements and high levels of indentation.&lt;/p&gt;

&lt;p&gt;I would say a Guard Clause that reduces the readability must have strong other reasons, such as stability or performance benefit. And if you feel not comfortable with a convention that forces you to use a Guard Clause rather than something more readable, ask your team if it would better be to adjust the convention instead of the code.&lt;/p&gt;

&lt;p&gt;(Note that in this article, I chose the Ruby language to give examples, because it is my natural programming language. But each example applies to all languages)&lt;/p&gt;

&lt;p&gt;❌ The following example shows a method that includes two conditional actions, but the Guard Clause in there results in different indentations for both conditions’ and actions’ contents, reading is made difficult:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;do_multiple_things&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;valid_context_for_first_action?&lt;/span&gt;
    &lt;span class="c1"&gt;# action 1&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;valid_context_for_second_action?&lt;/span&gt;
  &lt;span class="c1"&gt;# action 2&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. It has a strong and obvious link with the scope of the method
&lt;/h4&gt;

&lt;p&gt;The ideal use case of a Guard Clause is when it highlights a reason for not having called the given context at all. I mean, when a given context as a whole does not even make sense with current subject.&lt;/p&gt;

&lt;p&gt;This point is particularly involved by inheritance and shared logic. For instance, a set of shared validations can require exceptions with certain models. Or a class inheriting of parent’s methods can require additional conditions of applicability.&lt;/p&gt;

&lt;p&gt;In other words: A guard clause should allow a developer to quickly understand that even the method’s name is a non-sense for the current subject.&lt;/p&gt;

&lt;p&gt;✅ The following example shows a method that early exits due to a missing piece of critical information for the purpose:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_welcome_email&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank&lt;/span&gt; 

  &lt;span class="no"&gt;UserMailer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user: &lt;/span&gt;&lt;span class="vi"&gt;@user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;welcome_email&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. It solves a significant problem
&lt;/h4&gt;

&lt;p&gt;Third point is about pragmatism and efficiency. In certain circumstances, you would think about implementing a Guard Clause to solve an issue in relationship with the global context, whose scope is larger than the local context.&lt;/p&gt;

&lt;p&gt;Exiting a method, or skipping an element in a loop, due to external factors or attempted limits, is a good use case for Guard Clauses because they actually highlight a major concern of applicability.&lt;/p&gt;

&lt;p&gt;✅ The following example shows a method that exits from a nested level due to a major limit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify_many_third_parties_with_many_records&lt;/span&gt;
  &lt;span class="vi"&gt;@notifiable_records&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;API&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;daily_limit_reached?&lt;/span&gt;

    &lt;span class="no"&gt;API&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify_third_parties_with_record&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vrYHUnOi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ArHRKJIeGsR8GLt_5" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vrYHUnOi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ArHRKJIeGsR8GLt_5" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@jessemartini?utm_source=medium&amp;amp;utm_medium=referral"&gt;Jesse Martini&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Don’t be dogmatic, don’t forget to think
&lt;/h3&gt;

&lt;p&gt;Every language has its own set of coding style and conventions. Your team may also have its own: max number of lines per file, naming conventions, order of inclusion, etc.&lt;/p&gt;

&lt;p&gt;Static code analysers such as &lt;a href="https://github.com/rubocop-hq/rubocop"&gt;Rubocop&lt;/a&gt;, for Ruby programming, or &lt;a href="https://github.com/42Paris/norminette"&gt;norminette&lt;/a&gt; for &lt;a href="https://www.42.fr/"&gt;42 School&lt;/a&gt;’s exercices, provide packaged rules to help developers to follow conventions by highlighting where in the code base some are not respected. Rules are usually configurable to comply with the needs, and there are often default settings issued by the community.&lt;/p&gt;

&lt;p&gt;As a result, a community with such popular tools like Ruby’s can see a lot of projects and libraries following similar code styles, whoever has coded them, whatever their level of coding skill is, whatever the maturity of the project is. But not to follow a convention can make sense in many cases, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This method is too largely inspired by an open source algorithm: &lt;strong&gt;prefer to keep the spirit of its origin&lt;/strong&gt; so that it is easier to compare when updates or bugs occur.&lt;/li&gt;
&lt;li&gt;This file is legacy, well tested, and not supposed to change so many times: &lt;strong&gt;no need to invest time in rewriting it&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;This project is small and not intended to grow: &lt;strong&gt;keep code readable as it deserves and that’s fine!&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Therefore, there is a lot of situations where developers should better beside a static convention. Especially when pros and cons are not mastered, &lt;strong&gt;when intentions behind rules&lt;/strong&gt; are not explained and cristal clear. As an example of that, the following static rule often brings me some headaches in code reviews:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://www.rubydoc.info/gems/rubocop/RuboCop/Cop/Style/GuardClause"&gt;Style/GuardClause&lt;/a&gt;: Use a guard clause instead of wrapping the code inside a conditional expression.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our static code analyser does obviously not trigger this warning on every «if» statement of the application, but does warn all «if» statements placed at the end of methods when they have no «else» statement. In most of the cases, fixing that warning by writing a Guard Clause is counter-productive because of a root cause largely unrelated with the concern of the pattern: a lack of separation of concerns. Often, the solution I request is to disable warning, not to rearrange the code. Below examples may help you understand which solutions to choose.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examples with code samples
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Methods with single concern
&lt;/h4&gt;

&lt;p&gt;✅ The following example looks fine because it is clearly designed: One method with single role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_dates_consistency&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_on&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;end_on&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_on&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;end_on&lt;/span&gt;

  &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:end_on&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'must be greater than Start Date'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Methods with multiple concerns
&lt;/h4&gt;

&lt;p&gt;❌ The following example is ambiguous, it is a mix of conditional statement and Guard Clause, without any hierarchy or special meaning:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_complex_situation&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;something_wrong?&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'You must correct something'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;something_else_wrong?&lt;/span&gt;

  &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'You must correct something else'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ Think readability and solve it by using either simple “if” statements…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_complex_situation&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;something_wrong?&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'You must correct something'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;something_else_wrong?&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'You must correct something else'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…or split into multiple components:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_complex_situation&lt;/span&gt;
  &lt;span class="n"&gt;handle_errors_about_something&lt;/span&gt;
  &lt;span class="n"&gt;handle_errors_about_something_else&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_errors_about_something&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;everything_valid?&lt;/span&gt;

  &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'You must correct something'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;handle_errors_about_something_else&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;everything_else_valid?&lt;/span&gt;

  &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="ss"&gt;:base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'You must correct something else'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Loops with multiple transformations
&lt;/h4&gt;

&lt;p&gt;✅ The following example involves a sequential algorithm, where the role of guard clauses is directly linked to the context of the method (a sequential list of similar actions to be performed on each record), and readability is also present:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark_as_read!&lt;/span&gt;
  &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;completed?&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark_as_pending!&lt;/span&gt;
  &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;almost_completed?&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark_as_quickwin!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ The following example falls into a previous one, where a loop has multiple roles and the guard clause’s role is to handle a specific case. It is hard to read, it has a distant link with the context and it does not solve any problem:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;very_important_tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

&lt;span class="n"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark_as_read!&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;completed?&lt;/span&gt;  
    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mark_as_pending!&lt;/span&gt;  
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;owner&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;current_user&lt;/span&gt;  
    &lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;notify_owner_of_read_event_by_current_user&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;  

  &lt;span class="k"&gt;next&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;involves_administrator?&lt;/span&gt;
  &lt;span class="n"&gt;very_important_tasks&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;task&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Significant problem solved
&lt;/h4&gt;

&lt;p&gt;✅ The following example involves an expensive call to a huge service called “SyncTaskWithThirdParties”, and a performance profiling of the application has highlighted that it was the root cause of significant useless memory allocations with particular conditions. Readability is ensured through comments and test suite, whereas the link between the role of the method and the content of the guard clause can be hard to understand:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;sync_with_third_parties&lt;/span&gt;
  &lt;span class="c1"&gt;# avoid an expensive call to the sync service (15% of use cases)&lt;/span&gt;
  &lt;span class="c1"&gt;# please refer to the documented specs in task_spec.rb&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;start_on&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_a?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;AdminUser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Services&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;SyncTaskWithThirdParties&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ The following example involves a global context of maintenance window, which is making the role of the method not efficient or even not applicable, so that exiting the method is made necessary and understandable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;invalid_cache!&lt;/span&gt;
 &lt;span class="c1"&gt;# we have some issues with cache during maintenance windows &lt;/span&gt;
 &lt;span class="c1"&gt;# we prefer to save performance of display with obsolete data&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;CacheProvider&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;maintenance_window?&lt;/span&gt;

  &lt;span class="n"&gt;update_columns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;cached_at: &lt;/span&gt;&lt;span class="no"&gt;Time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Inherited methods
&lt;/h4&gt;

&lt;p&gt;✅ The following example involves an overridden method with a subroutine that does not make sense in a subclass’ context and should be skipped:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clean_parameters&lt;/span&gt;
  &lt;span class="c1"&gt;# skip whole process with action not requiring parameters at all&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;action_name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'toggle_visibility'&lt;/span&gt;

  &lt;span class="k"&gt;super&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;❌ The following example is ambiguous and malformed because the Guard Clause does not comply with any rule: The method “clean_parameters” is still applicable, it does still make sense with children class’ subject. We only want to handle a specific case, which is not a significant problem. Plus, we lost ease of maintainability:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clean_parameters&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:send_notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="vi"&gt;@send_notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:send_notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✅ As a solution, forget Guard Clause pattern. Keep the ability to implement additional logic after the conditional statement…&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clean_parameters&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:send_notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
    &lt;span class="vi"&gt;@send_notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:send_notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="c1"&gt;# additional logic here&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;…or extract the specific case into a separate context, where a Guard Clause actually makes sense. Plus, additional logic can later be easily appended:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clean_parameters&lt;/span&gt;
  &lt;span class="k"&gt;super&lt;/span&gt;
  &lt;span class="n"&gt;clean_parameter_send_notification&lt;/span&gt;
  &lt;span class="c1"&gt;# additional logic here&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clean_parameter_send_notification&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;key?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:send_notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="vi"&gt;@send_notification&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:send_notification&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'true'&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Guard Clause is a design pattern, with meanings and consequences on a code base for the long-term. It is not a code style rule as you would follow with indentation (“2 spaces” or “1 tab”, applicable everywhere, mechanically).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Guard Clauses are related to code structuring and separation of concerns&lt;/strong&gt;. Be pragmatic with their usage!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Interested in joining an enthusiastic engineering team? We are recruiting talented people! &lt;a href="https://www.per-angusta.com/en/our-engineering-team/"&gt;Learn more about the team and our open positions here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>development</category>
      <category>ruby</category>
      <category>codestructure</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>What’s Happening Behind The Scene of Rails Applications</title>
      <dc:creator>Jean-Michel Gigault</dc:creator>
      <pubDate>Wed, 21 Oct 2020 09:47:15 +0000</pubDate>
      <link>https://dev.to/jgigault/what-s-happening-behind-the-scene-of-rails-applications-406c</link>
      <guid>https://dev.to/jgigault/what-s-happening-behind-the-scene-of-rails-applications-406c</guid>
      <description>&lt;h3&gt;
  
  
  What’s Happening Behind The Scene of a Rails Application
&lt;/h3&gt;

&lt;p&gt;My name is Jean-Michel and I am a committed engineer at &lt;a href="https://www.per-angusta.com/"&gt;Per Angusta&lt;/a&gt;. I have a continuous challenge in my job: put developers in the right conditions to understand what they are building and where their realisations stand in the Product. First and foremost the technical side.&lt;/p&gt;

&lt;p&gt;Being an actual Web developer requires to be conscious at all times about where the code stands in the components’ architecture. Indeed, Rails is made for building final products without having to care about that and developers usually keep confused about how user’s requests are actually handled.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c7X_Mmg5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A4_jd2aHB6Nfyr_VHOz_G7w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c7X_Mmg5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A4_jd2aHB6Nfyr_VHOz_G7w.png" alt="Diagram of a common Rails Application’s architecture and components’ stack"&gt;&lt;/a&gt;Diagram of a common Rails Application’s architecture and components’ stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Main components of the architecture
&lt;/h3&gt;

&lt;p&gt;Let’s have a look at all levels of the components’ stack and define their role. At first, let’s forget the Rails framework and focus on the surrounding environment.&lt;/p&gt;

&lt;h4&gt;
  
  
  Web server
&lt;/h4&gt;

&lt;p&gt;The role of a Web server is to orchestrate the Unix-side of your Web Application. It keeps alive until you stop it and it cares about how to scale in terms of memory and CPU usage. It is the front office of all HTTP requests before they actually interact with Rails.&lt;/p&gt;

&lt;p&gt;Its configuration answers those kinds of question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many visitors are supposed to be handled at the same time by a single instance of your application?&lt;/li&gt;
&lt;li&gt;How the application is supposed to handle signals of the host machine (start, stop, rage quit, etc)?&lt;/li&gt;
&lt;li&gt;Which HTTP ports the application is supposed to listen to?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://github.com/puma/puma"&gt;Puma&lt;/a&gt; is the default Web server of a Rails app. It’s standing behind the command «rails server» until you change the configuration. Therefore it is one of the most flexible Web servers for Ruby and Rack applications because it scales in two different manners called “threads pool” and “clustered mode”, allowing you to get the advantage of both available memory and CPU cores of the environment.&lt;/p&gt;

&lt;p&gt;It’s worth noticing that when you deploy your Web Application, what we call here a “Web server” may in fact takes the role of an &lt;strong&gt;Application server&lt;/strong&gt;. For instance, Heroku handles requests through its own Web servers and then forwards them to your application. &lt;a href="https://www.justinweiss.com/articles/a-web-server-vs-an-app-server/"&gt;This is best explained by such article&lt;/a&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Background jobs
&lt;/h4&gt;

&lt;p&gt;Because the Web is asynchronous, background jobs are optional but usually required to build a scalable Product. Their role is to handle all processes that are not supposed to render End-User’s content such as HTML pages. For instance: export data into Excel files, send mails or synchronise data with external services.&lt;/p&gt;

&lt;p&gt;In Rails, background jobs are handled through &lt;a href="https://guides.rubyonrails.org/active_job_basics.html"&gt;Active Job&lt;/a&gt; framework, and depending on the use cases you would like to plug a dedicated backend like &lt;a href="https://github.com/mperham/sidekiq"&gt;Sidekiq&lt;/a&gt; or &lt;a href="https://github.com/resque/resque"&gt;Resque&lt;/a&gt;. The choice of a backend mainly depends on the running environment (available databases, memory usage, etc.) and the way you want to handle queuing and concurrency.&lt;/p&gt;

&lt;p&gt;I suggest you to read this brief article written by my colleague: &lt;a href="https://medium.com/committed-engineers/benchmarking-in-ruby-and-how-to-avoid-background-jobs-memory-explosion-7ef226287fd5"&gt;Benchmarking Excel Generation In Ruby And How To Avoid Background Jobs Memory Explosion!&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Databases
&lt;/h4&gt;

&lt;p&gt;Except if your Web Application is a simple Landing Page that displays static information, the role of databases is to build advanced stories. It allows you to store user’s input and create something else with it that can later be rendered to the same user or even other users. Indeed, databases are made for all features that need to go further than the scope of a single user’s session: Keeping a shopping cart into memory for multiple days or sharing user’s data with others.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.postgresql.org"&gt;PostgreSQL&lt;/a&gt; is an advanced open-source relational database with a large set of SQL-compliant capabilities and extensions built by the community. You would build applications on top of a relational database like PostgreSQL when you need to store multiple scheme of structured data and build features based on top of their relationships. For instance linking articles, prices, clients and invoices within an e-commerce solution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://redis.io"&gt;Redis&lt;/a&gt; is more likely a “dictionary” or a “hash table” based on the &lt;a href="https://en.wikipedia.org/wiki/Key%E2%80%93value_database"&gt;key-value storage paradigm&lt;/a&gt;. It allows you to store a set of data structures with an optional durability. It fits perfectly with caching purposes because of its expiry capabilities and fast data retrieval performance. In Rails, you would also use this kind of database to handle advanced features based on user’s session like a history of navigation, filtering ans search options, different modes of navigation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Web services
&lt;/h4&gt;

&lt;p&gt;Today, a common way of building applications is to rely on a Cloud environment. The role of Web services is to help you building final products by focusing on your added value. It brings your Web Application the components that you are not efficient to deliver by yourself.&lt;/p&gt;

&lt;p&gt;For instance, when you build an e-commerce you would choose an external Web services to handle the payment means. Because you’re not a banking service. When you deploy on PaaS solutions like Heroku, you would choose to forward your access logs to an addon like Sumo-Logic. Because you’re not efficient in digesting a log trace.&lt;/p&gt;

&lt;p&gt;Most of the popular Web services provide you with libraries packaged in Gems, in order to quickly and easily interact with their systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rack Middleware
&lt;/h3&gt;

&lt;p&gt;It’s important to understand that &lt;strong&gt;what makes Rails a Web framework is Rack&lt;/strong&gt;. Indeed, Rails is built on top of the &lt;a href="https://github.com/rack/rack"&gt;Rack framework&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The role of Rack is to handle the HTTP protocol on which Web Applications are based. HTTP describes how to share octets between two machines and Rack translates them into comprehensive structured Ruby objects for Rails: The request and the response, headers and parameters, settings of cookies and session, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aKkgHaIc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Ax-FZFKI2tDCHlDxQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aKkgHaIc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Ax-FZFKI2tDCHlDxQ" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@juliakadel?utm_source=medium&amp;amp;utm_medium=referral"&gt;Julia Kadel&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A Rack middleware is a component that handles one specific part of the user’s request and/or Rails’ response.&lt;/p&gt;

&lt;p&gt;They are stacked in a given order, determined at the initialisation step of the application and they are linked together like &lt;strong&gt;Russian dolls.&lt;/strong&gt; Each middleware is supposed to do one single thing, call the next middleware of the stack and then return its result to its parent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyMiddleware&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;app&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;app&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# do something before calling the next middleware  &lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"My name is Rack middleware"&lt;/span&gt;

    &lt;span class="c1"&gt;# then call the next middleware and return its response&lt;/span&gt;
    &lt;span class="vi"&gt;@app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;  
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the end of the stack comes the router of the Web Application (explained in the next section), as you can see by running the command “rails middleware”:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;rails middleware

use Webpacker::DevServerProxy
use Rack::MiniProfiler
use Rack::Cors
use Rack::Sendfile
use ActionDispatch::Static
use ActionDispatch::Executor
use Rack::Runtime
use Rack::MethodOverride
&lt;span class="c"&gt;# [...]&lt;/span&gt;
use Rack::ConditionalGet
use Rack::ETag
use Rack::TempfileReaper
use Rack::Attack
use Warden::Manager
run MyRailsApplication.routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One of a great middleware is &lt;a href="https://github.com/rack/rack-attack"&gt;Rack::Attack&lt;/a&gt;. Its role is to block abusive requests to avoid your application from being overloaded during a DoS attack, for instance. When the IP address of a request is recognised as being abusing (based on number of requests per period of time), it decides not to call the next middleware but to render immediately an error response. It breaks the chain and consequently increases the performance to handle such abusive requests.&lt;/p&gt;

&lt;p&gt;Other examples of use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/cyu/rack-cors"&gt;Rack::Cors&lt;/a&gt; handles Cross-Origin Resource Sharing settings in the response to tell the browser about the authorized AJAX calls on cross domains.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/influitive/apartment#switching-tenants-per-request"&gt;Apartment’s Elevators&lt;/a&gt; handle the strategy to determine which tenant is concerned by the user’s request within a multi-tenancy application.&lt;/li&gt;
&lt;li&gt;A custom middleware that blocks requests and renders a proper message when the application is put in maintenance mode.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Some of you may ask the difference between Rack middleware and &lt;a href="https://api.rubyonrails.org/classes/AbstractController/Callbacks/ClassMethods.html"&gt;Rails controllers’ callbacks&lt;/a&gt; like “before_action” because both allow you to build logic around an action. The main difference stands in their position in the components’ stack regarding the router: Rack middleware takes place before the route is determined, so that it is always involved whenever the requested route is not supposed to be handled by an internal controller. For instance, when routes are handled by Rails Engines like &lt;a href="https://github.com/heartcombo/devise"&gt;Devise&lt;/a&gt;, &lt;a href="https://github.com/ruby-grape/grape"&gt;Grape&lt;/a&gt; or &lt;a href="https://github.com/mperham/sidekiq/wiki/Monitoring"&gt;Sidekiq Web UI&lt;/a&gt;. The scope of Rack middleware is always “greater” than Rails’ controllers.&lt;/p&gt;

&lt;h3&gt;
  
  
  The router
&lt;/h3&gt;

&lt;p&gt;The role of the router is to declare which URLs and HTTP request methods are available in your Web Application, and map them with controllers’ actions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vj6v6H1J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AfsPxsiqHJEkbWtiN" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vj6v6H1J--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AfsPxsiqHJEkbWtiN" alt=""&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@barkiple?utm_source=medium&amp;amp;utm_medium=referral"&gt;John Barkiple&lt;/a&gt; on &lt;a href="https://unsplash.com?utm_source=medium&amp;amp;utm_medium=referral"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For instance, it determines which action is involved when making a GET request to the URL “&lt;em&gt;/users&lt;/em&gt;”. And even if the convention implies “&lt;em&gt;UsersController#index”,&lt;/em&gt; you must explicitly declare your routes in the configuration file “&lt;em&gt;router.rb&lt;/em&gt;”, either by using helpers or manual declarations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# using helper&lt;/span&gt;
&lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:index&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# manual declaration&lt;/span&gt;
&lt;span class="n"&gt;get&lt;/span&gt; &lt;span class="s1"&gt;'/users'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'users#index'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;as: &lt;/span&gt;&lt;span class="s1"&gt;'users'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is also the place where to declare the &lt;a href="https://guides.rubyonrails.org/engines.html"&gt;Rails Engines&lt;/a&gt;. A Rails Engine is an embedded Rack application that extends the capabilities of your application. One of the most popular one comes with &lt;a href="https://github.com/heartcombo/devise"&gt;Devise&lt;/a&gt; as a complete MVC solution to handle user’s registration and sessions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# mounting Devise's Engine in router.rb&lt;/span&gt;
&lt;span class="n"&gt;devise_for&lt;/span&gt; &lt;span class="ss"&gt;:users&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Controllers and MVC pattern
&lt;/h3&gt;

&lt;p&gt;It’s well known, Rails framework is based on the architectural pattern called &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller"&gt;model-view-controller&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Controllers&lt;/strong&gt; handle user’s requests (for instance “get the list of active users”), interact with &lt;strong&gt;Models&lt;/strong&gt; (for instance “retrieve User records with an active flag from database”) and respond to the user by rendering &lt;strong&gt;Views&lt;/strong&gt; (for instance “build an HTML content with a title and a table of users”).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Contrary to what’s shown in the diagram at the beginning of the article, views are not the final point before going back to the Rack middleware’s stack. They stand in the scope of controllers, and controllers can still perform a lot of things after rendering them. For instance, when you declare “after” and “around” action callbacks.&lt;/p&gt;

&lt;p&gt;A great use case comes with &lt;a href="https://github.com/varvet/pundit#ensuring-policies-and-scopes-are-used"&gt;Pundit’s verification callbacks&lt;/a&gt; that aim at adding a security layer regarding the permissions of the current user. Those verification run after the view is rendered. Also think about controllers’ actions that do not even interact with proper views from the folder “app/views/”. For instance when you render a JSON object in API contexts or even when you render &lt;a href="https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#2xx_success"&gt;No Content&lt;/a&gt; HTTP request.&lt;/p&gt;

&lt;p&gt;Therefore, the role of controllers is to build and return a &lt;a href="https://guides.rubyonrails.org/action_controller_overview.html#the-response-object"&gt;response Object&lt;/a&gt; that can then be handled by Rack middleware’s stack, in the reverse order (think Russian dolls). At the end of the stack, when each middleware has returned the response Object to its parent caller, the response is formatted in raw HTTP-compliant octets by Rack and sent back to the user through the Web server.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Objects, libraries and more
&lt;/h3&gt;

&lt;p&gt;There are many different design patterns to orchestrate what’s happening inside controllers and help you organise your code into maintainable sub-components, in opposition to writing the whole logic right into controllers’ actions.&lt;/p&gt;

&lt;p&gt;A popular approach is to use the Service Objects design pattern, consisting in embedding the logic of a given action into a dedicated Ruby object. By building a collection of Service Objects with their own responsibilities and interactions, you can then build advanced features shared across the application through multiple controllers or even other layers (as shown in the diagram with the API Server).&lt;/p&gt;

&lt;p&gt;Service Objects or what else you use to embed your logic may also interact with libraries such as &lt;a href="https://github.com/slack-ruby/slack-ruby-client"&gt;Slack Ruby Client&lt;/a&gt; whose you don’t own the code. A good approach while using external libraries is to recreate your own local interface that embeds the specific pieces of code. For instance having a generic object called “Notifier” that embeds Slack-specifics will help you migrating your Web Application if you plan to change Slack by MS Teams using &lt;a href="https://github.com/oooooooo/msteams-ruby-client"&gt;MS Teams Ruby Client&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Server
&lt;/h3&gt;

&lt;p&gt;The Rails framework is made for building Web Applications and API servers in a reversible way. Controllers have builtin features to handle multiple formats at once in the same place and you can render HTML content for real users or JSON content for machines within the same controller’s action.&lt;/p&gt;

&lt;p&gt;But in some circumstances, you may choose to extract the API context into a separate layer of the application such as in a Rails Engine like &lt;a href="https://github.com/ruby-grape/grape"&gt;Grape&lt;/a&gt;. The router is therefore in charge of forwarding requests to the relevant layer. For instance, you can mount a Grape API in a namespace “/api” and consider all sub-URLs to be in handled by it.&lt;/p&gt;

&lt;p&gt;Depending on the scale of your Product, you would better consider having dedicated Web servers for each Web and API context, so that you can adapt hardware and software components to best comply with their specific usage.&lt;/p&gt;

&lt;h4&gt;
  
  
  Formatters and presenters
&lt;/h4&gt;

&lt;p&gt;As referred above, your Web Application may have to handle multiple formats of requests and responses depending on the caller. This is the role of formatters, also known as “presenters” in some design patterns.&lt;/p&gt;

&lt;p&gt;Depending on the &lt;a href="https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Standard_request_fields"&gt;Accept&lt;/a&gt; header of a request, your Web Application can format the response’s content using different formats like JSON, JSONAPI, CSV, XML, and of course HTML.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Client
&lt;/h3&gt;

&lt;p&gt;API Client is the layer of your application that aims at requesting external Web services. For instance to retrieve the weather forecast for a tourism website or to send scheduled notifications through a mailer service.&lt;/p&gt;

&lt;p&gt;An API Client is not supposed to know about your internal database schema, your models or even any business rule, its single role is to know how to authenticate and communicate with external web services and fetch/pull data for your service objects.&lt;/p&gt;

&lt;p&gt;A good approach is to wrap them all into a common interface object, so that you can implement shared logic such as logging, monitoring, switch on/off during maintenance periods, etc…&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Interested in joining an enthusiastic engineering team? We are recruiting talented people! &lt;a href="https://www.per-angusta.com/en/our-engineering-team/"&gt;Learn more about the team and our open positions here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>rails</category>
      <category>webdev</category>
      <category>framework</category>
    </item>
    <item>
      <title>Why I Don’t Use Any Aliases</title>
      <dc:creator>Jean-Michel Gigault</dc:creator>
      <pubDate>Tue, 28 Apr 2020 09:01:00 +0000</pubDate>
      <link>https://dev.to/jgigault/why-i-don-t-use-any-aliases-1bjm</link>
      <guid>https://dev.to/jgigault/why-i-don-t-use-any-aliases-1bjm</guid>
      <description>&lt;p&gt;My name is Jean-Michel and I am a committed engineer at &lt;a href="https://www.per-angusta.com"&gt;Per Angusta&lt;/a&gt;. Here is my point of view about using shortened words to describe complex intentions.&lt;/p&gt;

&lt;p&gt;I am used to challenge the benefits of aliases in a Shell environment with my peers. I rarely hear mastered reasons but rather a pretended gain of efficiency. I personally chose to unset them all and keep being explicit with my machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TsMhDTB9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALliV5rcp-aurrUYWTToA-Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TsMhDTB9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ALliV5rcp-aurrUYWTToA-Q.png" alt=""&gt;&lt;/a&gt;Figure 1: Artist view of an alias deploying application to production&lt;/p&gt;

&lt;h4&gt;
  
  
  The Shell environment
&lt;/h4&gt;

&lt;p&gt;A shell is a &lt;a href="https://en.wikipedia.org/wiki/Unix_shell"&gt;command line interpreter for Unix-like operating systems&lt;/a&gt;. A place where developers (users) get control of their machine.&lt;/p&gt;

&lt;p&gt;It has wide capabilities (depending on the OS and the version of the distribution) such as browsing directories, managing files, running scripts and installing dependencies. Its usage is a must-known for all developers. Like knives for cooks and saws for carpenters, it shapes the main toolkit for developers.&lt;/p&gt;

&lt;p&gt;That’s why best programming training programs always start with Unix learning and practising sessions. In the best case they invite students to create their own Shell program to deeper understand what’s going on behind the scene.&lt;/p&gt;

&lt;p&gt;Once the learning step is reached, a developer is much more autonomous in its daily issues and he starts not to depend on each others. His machine stays forever his only one working environment (until coding with LEGOs is made possible!) and mastering it is a must-have skill. That’s the purpose of a command line interpreter.&lt;/p&gt;

&lt;h4&gt;
  
  
  Are aliases a standard practice over the world?
&lt;/h4&gt;

&lt;p&gt;They are to an extent, but their usage is not. Like Web and API protocols/frameworks, the way they work is common but there is no guarantee it is implemented the same way.&lt;/p&gt;

&lt;p&gt;An alias is a string to be substituted for a word when it is used as the first argument of a command. It is usually a shorter word than what it is supposed to be substituted for, and is commonly composed of the first letters of the command and its first arguments. For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# set an alias for staging files (git add) using patch option&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gapa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git add --patch"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now user can type “gapa” instead of the original command, and it’s now pretty easy to understand the first benefit of aliases: less typing, quicker control of the machine!&lt;/p&gt;

&lt;p&gt;Aliases are set at the user session level in a Shell when the profile is loaded (for example on Bash from file “&lt;em&gt;~/.bashrc&lt;/em&gt;”). It is then clearly identified as a User setup not related to the environment. That’s why there is no guarantee that an other user, including one on the same machine, decides that “gapa” means something else, for instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# set an alias to grant all permissions to all&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;&lt;span class="nv"&gt;gapa&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"chmod 777"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OF COURSE DON’T! 😱&lt;/p&gt;

&lt;p&gt;However in this case, user decides not to use the first letters of the command and its first argument (that would have resulted in “c7”), but the ones from its human meaning, which make more sense to him because he doesn’t care about versioning files with Git but is an Access Control List manager.&lt;/p&gt;

&lt;h4&gt;
  
  
  Not a good approach for abstract
&lt;/h4&gt;

&lt;p&gt;I can hear from my peers that aliases are one of the large set of programming abstracts: objects, methods, variables, and so on, including DRY principle (“Don’t repeat yourself”). However, the common usage of aliases sounds more like short-linking, as if you would create shortcuts on your Desktop folder to quicker access your favourites.&lt;/p&gt;

&lt;p&gt;To me, a justified approach of abstract would be to use them as a human readable substitute for technical commands, for instances:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# deploying current branch on staging remote server&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;x-deploy-staging&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"git push staging &lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;git rev-parse &lt;span class="nt"&gt;--abbrev-ref&lt;/span&gt; HEAD&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:master"&lt;/span&gt;

&lt;span class="c"&gt;# archiving directory recursively&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;x-archive-directory&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"tar -zcvf"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case, user decides to abstract its common technical commands into human readable links. A prefix “x-” allows to differentiate when typing custom commands in favour of builtins and binaries. Now it is not only shortcuts for repeatable commands but &lt;strong&gt;it actually becomes an abstract tool&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Explicit over implicit
&lt;/h4&gt;

&lt;p&gt;The more explicit a code or a library is, the easiest it is used and maintained. That’s one of the main principle developers apply: choosing appropriated variable, method and class names, especially when they work on a product that is supposed to be maintained by others.&lt;/p&gt;

&lt;p&gt;Every developer has experienced at least once in his life (if not once a day) a peer challenging the naming of a variable after a code review. For example, given a model named “ThirdPartyClient” and a code that iterates on each of its records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;ThirdPartyClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;tpc&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;tpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deactivate!&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a matter of fact at &lt;a href="https://www.per-angusta.com/en/recrutement/senior-backend-developer/"&gt;Per Angusta&lt;/a&gt;, a code reviewer would invite the requester to rename “tpc” by “third_party_client”. Wouldn’t you? No one would invite the opposite by asking to type less characters to gain efficiency. &lt;strong&gt;The readability always comes first.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For the same reason and when available, I personally prefer to use the longer version of builtins or binaries’ options. When I am running commands against an “application”, I choose to use “ — app” over “-a”. It makes more sense to me and that’s how I would write it in a Shell script before asking for a script review to my peers.&lt;/p&gt;

&lt;p&gt;Let’s go further with the famous “git push” command, which is commonly used without any arguments because it perfectly fallbacks to defaults. When my intention is to push my work from my current branch onto its remote counterpart, I am explicitly typing the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# telling exactly on which server, what to push in which branch&lt;/span&gt;
git push origin HEAD:feature-branch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;The remote: &lt;strong&gt;origin&lt;/strong&gt; is the default remote, until it is configured another way&lt;/li&gt;
&lt;li&gt;The source: &lt;strong&gt;HEAD&lt;/strong&gt; is the current ref, which is by default the last commit of the branch until you checkout a different one&lt;/li&gt;
&lt;li&gt;The destination: &lt;strong&gt;feature-branch&lt;/strong&gt; is the default, until the remote one is named differently than the local branch&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This way, before pushing my work I am asking myself what I exactly want my machine to do for me, giving myself more chances to not do mistakes. It invites me to ensure I know what remote, source and destination are in my current context.&lt;/p&gt;

&lt;p&gt;Thus, the explicit version of a command is the only one I expect to find in a documentation (like articles, posts or wiki pages). Why losing those benefits while controlling my machine? I get the control of it while documenting my intention, and my Shell history is tracking it.&lt;/p&gt;

&lt;h4&gt;
  
  
  Let your peers know what you are really doing
&lt;/h4&gt;

&lt;p&gt;When you’re riding a bike on a road and you reach a crossroad, you probably know what to do: tell the environment what your intention is. As a matter of fact, you’re aware of your own intention and your local machine (the bike) doesn’t care about it because it is controlled by you. So, why to explain your intention?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6oYW4WI6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A4qJ_TRXxHn-mCZzubXUxHw.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6oYW4WI6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A4qJ_TRXxHn-mCZzubXUxHw.jpeg" alt=""&gt;&lt;/a&gt;Bicycle Safety (&lt;a href="https://www.azdps.gov/safety/bicycle"&gt;&lt;/a&gt;&lt;a href="https://www.azdps.gov/safety/bicycle"&gt;https://www.azdps.gov/safety/bicycle&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Of course you want to prevent the other users of the road from hitting you, even if your intention seems obvious. &lt;strong&gt;More generally you would try to make things happen in a smooth way and try to minimise the doubt&lt;/strong&gt;. So what about applying this purpose to your Shell environment: your teammates would probably be more comfortable if you told them what your intention exactly was before running command lines in public.&lt;/p&gt;

&lt;p&gt;It is relevant with the history: browsing a Shell session history is smoother when command lines are explicit, especially in case of a mistake analysis. As a rider, you would be more comfortable to remind a driver that you told him you would turn on the right before he hit you.&lt;/p&gt;

&lt;p&gt;When you are working with peers with different skills level and setup, using aliases is disturbing and inefficient at all. Beginners won’t follow you and you probably will pass more time to retrieve what your aliased command actually does rather than typing its original. That is similar circumstance as if you had to explain what the variable “tpc” is whereas you could have directly named it “third_party_client”.&lt;/p&gt;

&lt;h4&gt;
  
  
  Efficiency gain is not obvious
&lt;/h4&gt;

&lt;p&gt;Aliases are nothing more than embedded Shell scripts, except they are stored in the user session instead of script files. It can help you running repeated operations without typing them again and again. That’s why it is, and must be, considered as a good manner to gain efficiency and doing less mistakes. It is especially the case when the substituted commands require a lot of obfuscated options like “tar -zcsv”.&lt;/p&gt;

&lt;p&gt;But, assuming you are working in a given environment (with tools and workflows in place), if you, or your team, want to gain efficiency in a Shell environment, my opinion is that you should better first ensure to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ask yourself if you’re really controlling the purpose of your personal set of aliases, especially when they come from external tools (like &lt;a href="https://ohmyz.sh"&gt;Oh My ZSH!&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Ask yourself if your peers can understand the rules you’ve setup in your own session, their purpose and their impact.&lt;/li&gt;
&lt;li&gt;Ask yourself if you would better try to setup common guidelines instead of standing apart. Bring your tools to the team and ensure every one adopt them and is trained for. For example: share a versioned and documented set of aliases or scripts through a Git repository.&lt;/li&gt;
&lt;li&gt;Being conscious of the impacts an obscure command line can have, starting by yourself, like issues with history analysis or pedagogical purposes while peering. It does not only apply to aliases.&lt;/li&gt;
&lt;li&gt;Being conscious that a Shell environment is not a programming interface. You need to know more than ever what you are actually doing and what your context is. Killing processes afterward with “Ctrl+C” has no guarantee to be reversible, whereas coding in a versioned code base is.&lt;/li&gt;
&lt;li&gt;Not to ask for this blog post’s author if aliases have more benefits than issues until they are implemented as a team workflow and become an actual standard 😜&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Interested in joining an enthusiastic engineering team? We are recruiting talented people! &lt;a href="https://www.per-angusta.com/en/our-engineering-team/"&gt;Learn more about the team and our open positions here&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>unix</category>
      <category>shell</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
