<?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: Ivan Iliukhin</title>
    <description>The latest articles on DEV Community by Ivan Iliukhin (@evanilukhin).</description>
    <link>https://dev.to/evanilukhin</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%2F258368%2F0c1b8e86-3e0f-4f4d-b1aa-f77fe9321058.jpeg</url>
      <title>DEV Community: Ivan Iliukhin</title>
      <link>https://dev.to/evanilukhin</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/evanilukhin"/>
    <language>en</language>
    <item>
      <title>Overcoming complexity of service objects with dry libraries</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Thu, 02 Sep 2021 19:35:47 +0000</pubDate>
      <link>https://dev.to/evanilukhin/leveraging-complexity-of-service-objects-with-dry-libraries-3750</link>
      <guid>https://dev.to/evanilukhin/leveraging-complexity-of-service-objects-with-dry-libraries-3750</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Almost everyone in the rails community(and not only) talks about the slim controllers: "Let's move everything to the service objects and functions, keep controllers as simple as possible". It's a great concept, and I fully support it. Service objects and functions for controllers' methods(not only but mainly for them) usually have two additional parts besides business logic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;input validation;&lt;/li&gt;
&lt;li&gt;errors passing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They aren't a big problem if your function does not call other functions and does not have nested objects as the input arguments. The problem that they are love to grow and mysteriously interact with each other. &lt;/p&gt;

&lt;p&gt;In this post, I want to share the way how you can overcome these problems. Grab yourself a cup of your favourite beverage ☕ and join this journey.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Time for experiments
&lt;/h2&gt;

&lt;p&gt;Imagine that you are designing internal software for a laboratory. It should run experiments from the passed arguments. Arguments should be validated to get a sensible response instead of meaningless 500 errors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Without dry libraries
&lt;/h3&gt;

&lt;p&gt;➡️ Let's start from the controller for the experiment. The controller should only run the function and render results or errors:&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;ExperimentsController&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConductExperiment&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;experiment_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:success&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="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:result&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;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:errors&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;status: :bad_request&lt;/span&gt;
    &lt;span class="k"&gt;end&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;experiment_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;:experiment&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;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:power_consumption&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;➡️ Next, add the service object. It is a good practice to move the repeated part to the base object:&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;ApplicationService&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="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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
    &lt;span class="vi"&gt;@block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&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="n"&gt;validation_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validate_params&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;validation_result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;execute&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;validation_result&lt;/span&gt;
    &lt;span class="k"&gt;end&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;validate_params&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&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;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&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;span class="k"&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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;ConductExperiment&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationService&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;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&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;validate_params&lt;/span&gt;
    &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&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="ss"&gt;:duration&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;blank?&lt;/span&gt;
      &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'Duration should be present'&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="n"&gt;errors&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;if&lt;/span&gt; &lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:duration&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
      &lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s1"&gt;'Duration should be positive number'&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="n"&gt;errors&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;true&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;def&lt;/span&gt; &lt;span class="nf"&gt;execute&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &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;result: &lt;/span&gt;&lt;span class="s1"&gt;'Success!'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Definitely not success.'&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="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;It already looks cumbersome, don't ya?😕 But all of a sudden, users of our API requested to add the type validation to all fields and a new entity - research, that will accept an array of experiments and checks that summary power consumption is less than a defined limit. Sounds scary 😲. Doing this will be really hard with the current configuration, so let's add some dry libraries and look at how easy it will be.&lt;/p&gt;

&lt;p&gt;The full version is &lt;a href="https://github.com/evanilukhin/dry_validations_monads_example"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Update validations
&lt;/h3&gt;

&lt;p&gt;➡️ First, we need to upgrade the validation process. For this will be used the gem &lt;a href="https://dry-rb.org/gems/dry-validation"&gt;dry-validation&lt;/a&gt;. It adds validations that are expressed through contract objects. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A contract specifies a schema with basic type checks and any additional rules that should be applied. Contract rules are applied only once the values they rely on have been successfully verified by the schema.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;➡️ Begin by updating the &lt;code&gt;ApplicationService&lt;/code&gt;. We replace &lt;code&gt;validate_params&lt;/code&gt; method with &lt;code&gt;validator&lt;/code&gt;, where can be defined either class name of the contract or contract itself. In the &lt;code&gt;call&lt;/code&gt;, add the call of the &lt;code&gt;validator&lt;/code&gt; and change the &lt;code&gt;validation_result&lt;/code&gt; check, respectively.&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;ApplicationService&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="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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
    &lt;span class="vi"&gt;@block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&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="n"&gt;validation_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;validator&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="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;validation_result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success?&lt;/span&gt;
      &lt;span class="n"&gt;execute&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="n"&gt;validation_result&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="nf"&gt;to_h&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;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validator&lt;/span&gt;
    &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&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;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;➡️ Next, add the class where will be defined validations. Contracts have two parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://dry-rb.org/gems/dry-validation/1.6/schemas/"&gt;schema(or params)&lt;/a&gt; where are defined basic type checks
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dry-rb.org/gems/dry-validation/1.6/rules/"&gt;rules&lt;/a&gt; for complex checks which are applied after schema validations. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;⚠️ Be careful with optional values. You should check that value is passed before the checking.&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;ConductExperimentContract&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dry&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Validation&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Contract&lt;/span&gt;
  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:duration&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:integer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# in seconds&lt;/span&gt;
    &lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:power_consumption&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:integer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# in MW&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:duration&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'should be positive'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;positive?&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:power_consumption&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'should be positive'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;positive?&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;➡️ In the &lt;code&gt;ConductExperiment&lt;/code&gt; class, just replace the validation with the previously defined validator class.&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;ConductExperiment&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationService&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;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&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;validator&lt;/span&gt;
    &lt;span class="no"&gt;ConductExperimentContract&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;execute&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &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;result: &lt;/span&gt;&lt;span class="s1"&gt;'Success!'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;errors: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'Definitely not success.'&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="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;Looks great! Time to add functionality for the research process. &lt;/p&gt;

&lt;p&gt;This class will be finished successfully if all experiments are finished successfully or will return an error message from the first failed experiment.&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;ConductResearch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationService&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;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&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;validator&lt;/span&gt;
    &lt;span class="no"&gt;ConductResearchContract&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;execute&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:experiments&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;experiment_params&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;experiment_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConductExperiment&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;experiment_params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;experiment_result&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;experiment_result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:success&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

      &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;experiment_result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:result&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;success: &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;result: &lt;/span&gt;&lt;span class="n"&gt;result&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;➡️ The most interesting part is the &lt;code&gt;ConductResearchContract&lt;/code&gt;. It validates each element of the experiments array for compliance with the schema defined in the &lt;code&gt;ConductExperimentContract&lt;/code&gt;. Sadly, &lt;a href="https://github.com/dry-rb/dry-validation/issues/593"&gt;now&lt;/a&gt;, to run rules for each experiment, you must run them manually like in the &lt;code&gt;rule(:experiments)&lt;/code&gt;.&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;ConductResearchContract&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Dry&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Validation&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Contract&lt;/span&gt;
  &lt;span class="no"&gt;MAX_POWER_CONSUMPTION&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;

  &lt;span class="n"&gt;schema&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:title&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:experiments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;ConductExperimentContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schema&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;min_size?: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;rule&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:experiments&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="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConductExperimentContract&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="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success?&lt;/span&gt;
      &lt;span class="n"&gt;meta_hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;text: &lt;/span&gt;&lt;span class="s1"&gt;'contain bad example'&lt;/span&gt; &lt;span class="p"&gt;}.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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="nf"&gt;to_h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meta_hash&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;span class="n"&gt;rule&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;total_power_consumption&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:experiments&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&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;sum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;experiment&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;experiment&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:power_consumption&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;experiment&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:power_consumption&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;if&lt;/span&gt; &lt;span class="n"&gt;total_power_consumption&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="no"&gt;MAX_POWER_CONSUMPTION&lt;/span&gt;
      &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:experiments&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"total energy consumption &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;total_power_consumption&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; MW exceeded limit &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;MAX_POWER_CONSUMPTION&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; MW"&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;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;✨ We did it! It validates everything and works great. But we can make it even better.&lt;/p&gt;

&lt;p&gt;The result version of this example is &lt;a href="https://github.com/evanilukhin/dry_validations_monads_example/tree/add_dry_validation"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Make it simpler with monads
&lt;/h3&gt;

&lt;p&gt;In this part I won't explain what are monads and how this library works, thats very good explained in the &lt;a href="https://dry-rb.org/gems/dry-monads/1.3/"&gt;documentation&lt;/a&gt; and in thesecool posts: &lt;a href="https://humanreadablemag.com/issues/0/articles/functional-ruby-with-dry-monads/"&gt;Functional Ruby with &lt;code&gt;dry-monad&lt;/code&gt;s&lt;/a&gt;,  &lt;a href="https://www.netguru.com/blog/improve-your-services-using-dry-rb"&gt;Improve Your Services Using Dry-rb Stack&lt;/a&gt; and &lt;a href="https://www.davydovanton.com/2020/05/19/five-common-issues-with-services-and-dry-monads/"&gt;Five common issues with services and dry-monads&lt;/a&gt;. Here I will just demonstrate how it can improve the existing code. &lt;/p&gt;

&lt;p&gt;➡️ Firstly add &lt;code&gt;dry-monads&lt;/code&gt; gem to the Gemset.&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;# ...&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'dry-monads'&lt;/span&gt;
&lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;➡️ After this add the add &lt;a href="https://dry-rb.org/gems/dry-validation/1.5/extensions/#monads"&gt;the behaviour of monads&lt;/a&gt; to contracts. For this, you should run the command &lt;code&gt;Dry::Validation.load_extensions(:monads)&lt;/code&gt;. For rails applications I usually create file &lt;code&gt;config/initializers/dry.rb&lt;/code&gt; where store all global configs for dry gems.&lt;/p&gt;

&lt;p&gt;➡️ Next update service objects. Replace these ifs with the &lt;a href="https://dry-rb.org/gems/dry-monads/1.3/do-notation/"&gt;do notation&lt;/a&gt; syntax.&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;ApplicationService&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Dry&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Monads&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:do&lt;/span&gt;&lt;span class="p"&gt;]&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="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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;
    &lt;span class="vi"&gt;@block&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;block&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="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;validator&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="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;validator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;nil?&lt;/span&gt;
    &lt;span class="n"&gt;execute&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;validator&lt;/span&gt;
    &lt;span class="kp"&gt;nil&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;call&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&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="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;block&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;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;➡️  In the &lt;code&gt;ConductExperiment&lt;/code&gt;, wrap results to the &lt;code&gt;Dry::Monads::Result&lt;/code&gt; monads&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;ConductExperiment&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationService&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;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&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;validator&lt;/span&gt;
    &lt;span class="no"&gt;ConductExperimentContract&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;execute&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="no"&gt;Random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rand&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;
      &lt;span class="no"&gt;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Success!'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="no"&gt;Failure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Definitely not success.'&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;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and replace that ugly construction with temporary variables with this neat form in the &lt;code&gt;ConductResearch&lt;/code&gt; service.&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;ConductResearch&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationService&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;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;
    &lt;span class="vi"&gt;@params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&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;validator&lt;/span&gt;
    &lt;span class="no"&gt;ConductResearchContract&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;execute&lt;/span&gt;
    &lt;span class="n"&gt;result&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="ss"&gt;:experiments&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;map&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;experiment_params&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="no"&gt;ConductExperiment&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;experiment_params&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;Success&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&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;➡️ Because failure objects are different, result messages should also be handled differently.&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;ExperimentsController&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ConductExperiment&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;experiment_params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_h&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;success?&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;value!&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;error_object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&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;Dry&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Validation&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&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;full: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;to_h&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
          &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;failure&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;

      &lt;span class="n"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="n"&gt;error_object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: :bad_request&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;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;experiment_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;:experiment&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;:name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:duration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;:power_consumption&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;That's all!🎆 Compare it with the previous version. I think you will agree - it looks more readable.&lt;/p&gt;

&lt;p&gt;Result version is available &lt;a href="https://github.com/evanilukhin/dry_validations_monads_example/tree/add_dry_monads"&gt;here&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;I hope this post was helpful for you. Have a nice day!&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Small tips that will help you to use ActiveRecord callbacks more efficiently</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Fri, 28 May 2021 20:06:09 +0000</pubDate>
      <link>https://dev.to/evanilukhin/small-tips-that-will-help-you-to-use-activerecord-callbacks-more-efficiently-4i91</link>
      <guid>https://dev.to/evanilukhin/small-tips-that-will-help-you-to-use-activerecord-callbacks-more-efficiently-4i91</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Everything there is related the Rails 6 but also actual for 5 and 4.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt; &lt;strong&gt;Do not use callbacks if you can&lt;/strong&gt; -  callbacks are incredibly helpful when you need to add a function that should run before/after/around specific lifecycle events. If they do not depend from the context it is possible the best choice. But if the model is used almost everywhere and there are a lot of create/update/destroy events adding new callbacks can drastically reduce the application performance. So I recommend to add them only if you absolutely confident and aware about consequences.&lt;/li&gt;
&lt;/ul&gt;




&lt;blockquote&gt;
&lt;p&gt;Despite the upper warning, you are decided to add a callback to your model. There are a few things that I recommend to keep in mind.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;ul&gt;
&lt;li&gt;Use &lt;a href="https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Dirty.html#method-i-saved_change_to_attribute-3F"&gt;saved_change_to_attribute?&lt;/a&gt; in &lt;code&gt;after_save&lt;/code&gt;/&lt;code&gt;after_update&lt;/code&gt; to except unnecessary calls. - If your callback should be called only after changes in a limited set of attributes, this method can help with it. For example, you have the model User with fields: email, password, first_name and last_name. The goal is to update related certificates only when the &lt;em&gt;first_name&lt;/em&gt; or &lt;em&gt;last_name&lt;/em&gt; changed.
&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;User&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;after_update&lt;/span&gt; &lt;span class="ss"&gt;:update_certifcates&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="ss"&gt;if: &lt;/span&gt;&lt;span class="no"&gt;Proc&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;saved_change_to_first_name?&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="n"&gt;saved_change_to_last_name?&lt;/span&gt; &lt;span class="p"&gt;}&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;update_certificates&lt;/span&gt;
    &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;UpdateCertificates&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="nb"&gt;self&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;ul&gt;
&lt;li&gt;&lt;p&gt;Use more suitable methods whenever possible - instead of using common methods like: &lt;code&gt;*_save&lt;/code&gt;, &lt;code&gt;*_commit&lt;/code&gt;, &lt;code&gt;*_validate&lt;/code&gt; is better to use more specific: &lt;code&gt;*_update&lt;/code&gt; or &lt;code&gt;*_create&lt;/code&gt;. It will also reduce the count of calls.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use &lt;code&gt;after_commit&lt;/code&gt; instead of &lt;code&gt;after_save&lt;/code&gt; when you want to complete the action - If something went wrong in the &lt;code&gt;after_commit&lt;/code&gt; callback there will be an error but the action will be finished because it is called when changes are already flushed to the database. Other callbacks will rollback changes, sometimes it can be useful.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do not run expensive operations in callbacks - better to move them into &lt;a href="https://guides.rubyonrails.org/active_job_basics.html"&gt;ActiveJobs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you know other problems with callbacks or know how to make live easier with them, please share in comments.&lt;/p&gt;




&lt;h3&gt;
  
  
  Some useful links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Rails guide about callbacks — &lt;a href="https://guides.rubyonrails.org/active_record_callbacks.html"&gt;Active Record Callbacks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Rails 6 Callbacks API - &lt;a href="https://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html"&gt;ActiveRecord::Callbacks&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Kelly Sutton  — &lt;a href="https://engineering.gusto.com/the-rails-callbacks-best-practices-used-at-gusto/"&gt;5 Rails Callbacks Best Practices Used at Gusto&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
    </item>
    <item>
      <title>CircleCI + AWS How to create CI/CD pipeline from scratch Part 2 - Setup and update servers</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Sat, 25 Jul 2020 09:35:48 +0000</pubDate>
      <link>https://dev.to/evanilukhin/circleci-aws-how-to-create-ci-cd-pipeline-from-scratch-part-2-setup-and-update-servers-47bl</link>
      <guid>https://dev.to/evanilukhin/circleci-aws-how-to-create-ci-cd-pipeline-from-scratch-part-2-setup-and-update-servers-47bl</guid>
      <description>&lt;p&gt;After all previous steps, you've got the images that are stored inside the ECR and the script that automatically build&lt;br&gt;
them. In this part of the tutorial we will: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;setup ECS clusters for development and production environments;&lt;/li&gt;
&lt;li&gt;add deployment commands to the CircleCI script.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's do it!&lt;/p&gt;
&lt;h2&gt;
  
  
  Initialize ECS cluster
&lt;/h2&gt;

&lt;p&gt;Creating of cluster consists of three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create an empty cluster with a VPC&lt;/li&gt;
&lt;li&gt;Define the task that will launch the selected container&lt;/li&gt;
&lt;li&gt;Add service that will launch and maintain the desired count of ec2 instances with the previously defined task&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Create cluster
&lt;/h3&gt;

&lt;p&gt;Let's start with the definition of &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/clusters.html" rel="noopener noreferrer"&gt;cluster&lt;/a&gt;: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;An Amazon ECS cluster is a logical grouping of tasks or services. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Roughly saying, clusters define the scope and set of rules for the launched tasks. To create one, follow the steps below:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select EC2 Linux + Networking you need two clusters one for development and one for master branches&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select 1 &lt;code&gt;On Demand&lt;/code&gt; t2.micro instance(or other types of ec2 instances), other configurations by default&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fk7mqxf1g01ymaoi0t2pf.png"&gt;Create cluster
  
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For the networking section, I recommend to use the default parameters too. It will create a new VPC with&lt;br&gt;
&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html" rel="noopener noreferrer"&gt;security group&lt;/a&gt; allowing income traffic&lt;br&gt;
to the 80 PORT.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fynh1k3ba8tuyl3xkznkk.png"&gt;Configure network during creation
  


&lt;p&gt;Yes, that's all, you should create one for the development and one for the production. &lt;/p&gt;
&lt;h3&gt;
  
  
  Define task
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html" rel="noopener noreferrer"&gt;Tasks&lt;/a&gt; are used to run Docker containers in Amazon ECS. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select EC2 launch type compatibility&lt;/li&gt;
&lt;li&gt;Choose the name for the task definition(or family, like sometimes it's called)&lt;/li&gt;
&lt;li&gt;For the as the task role choose the role with the &lt;code&gt;AmazonECSTaskExecutionRolePolicy&lt;/code&gt; policy that we  previously created &lt;/li&gt;
&lt;li&gt;Select the memory limit, for example, 128 MB if your server is not going to handle a lot of complex requests&lt;/li&gt;
&lt;li&gt;And finally, add a container. On this tab we are interested in the following fields:

&lt;ul&gt;
&lt;li&gt;Standard -&amp;gt; Image - initial image for the task should be copied from the ECR looks like 845992245040.dkr.ecr.us-west-2.amazonaws.com/simple_plug_server:master_latest&lt;/li&gt;
&lt;li&gt;Standard -&amp;gt; Port mappings - associate host 80 with the port which is using our application and will be defined next

&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flnqwg6i59irnpzis8ed2.png"&gt;Add container to a task and configure the port mapping

 &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;Advanced container configuration -&amp;gt; ENVIRONMENT -&amp;gt; Environment variables - define the variable with the name &lt;code&gt;PORT&lt;/code&gt; and desired value for example - 4100. This value must be used in the port mapping as the container port

&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fhtqejj8nruz7azy328iv.png"&gt;Set up environment variables

&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Great! You've created the first revision of the task definition. Of course, these tasks can be launched right inside the cluster, but we will use services to simplify updating tasks revisions. Let's add them. &lt;/p&gt;
&lt;h3&gt;
  
  
  Add service
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;An Amazon ECS service enables you to run and maintain a specified number of instances of a task definition simultaneously in an Amazon ECS cluster. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To create a &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs_services.html" rel="noopener noreferrer"&gt;service&lt;/a&gt; just click on the &lt;code&gt;Create&lt;/code&gt; button on the &lt;code&gt;Services&lt;/code&gt; and fill the form:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Select EC2 in the &lt;code&gt;Launch type&lt;/code&gt; selector, because we are deploying our tasks on EC2 instances&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;Task Definition&lt;/code&gt; select the task and revision that you are created earlier&lt;/li&gt;
&lt;li&gt;In the &lt;code&gt;Cluster&lt;/code&gt; select the cluster where you want to define a service. When you are creating service from a cluster this field will be already selected&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Service type&lt;/code&gt; - REPLICA&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Number of tasks&lt;/code&gt; - 1 because we do not care about scaling for now.&lt;/li&gt;
&lt;li&gt;Other setting set by default&lt;/li&gt;
&lt;/ol&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyoeullialw88olce81sf.png"&gt;Service creation
  


&lt;p&gt;After repeating all steps for the development and production cluster, you've got two EC2 instances with running applications. They are available by Public DNS or IP.&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6pzerqn1gn7iq6dacnrt.png"&gt;Service creation
  


&lt;p&gt;Now let's go to the final part of this tutorial. 🚀&lt;/p&gt;
&lt;h2&gt;
  
  
  Add deployment scripts
&lt;/h2&gt;

&lt;p&gt;With an official orb &lt;a href="https://circleci.com/orbs/registry/orb/circleci/aws-ecs" rel="noopener noreferrer"&gt;aws-ecs&lt;/a&gt; you can make this very easy. We already added all necessary environment variables in the second part of this tutorial so you should only modify the circleci config. &lt;/p&gt;

&lt;p&gt;Result version of the &lt;code&gt;.circleci/config.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;aws-ecr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/aws-ecr@6.9.1&lt;/span&gt;
  &lt;span class="na"&gt;aws-ecs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/aws-ecs@1.2.0&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;elixir:1.10&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;MIX_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;working_directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/repo&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix local.hex --force&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix local.rebar --force&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix deps.get&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix deps.compile&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_test_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;_build/test/lib/simple_plug_server&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;test-build-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;aws-ecr/build-and-push-image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;simple_plug_server"&lt;/span&gt;
          &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${CIRCLE_BRANCH}_${CIRCLE_SHA1},${CIRCLE_BRANCH}_latest"&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
          &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;development&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;aws-ecs/deploy-service-update&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy-development&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;aws-ecr/build-and-push-image&lt;/span&gt; 
          &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;simple-plug-server-development"&lt;/span&gt;
          &lt;span class="na"&gt;cluster-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SimplePlugServer-development"&lt;/span&gt;
          &lt;span class="na"&gt;service-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sps-dev-serv"&lt;/span&gt;
          &lt;span class="na"&gt;container-image-name-updates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;container=simple-plug-server-development,tag=${CIRCLE_BRANCH}_${CIRCLE_SHA1}"&lt;/span&gt;
          &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;development&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;approve-deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;approval&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;aws-ecr/build-and-push-image&lt;/span&gt;
          &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;aws-ecs/deploy-service-update&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deploy-production&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;approve-deploy&lt;/span&gt;
          &lt;span class="na"&gt;family&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;simple-plug-server-production"&lt;/span&gt;
          &lt;span class="na"&gt;cluster-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SimplePlugServer-production"&lt;/span&gt;
          &lt;span class="na"&gt;service-name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;simple-plug-server-production"&lt;/span&gt;
          &lt;span class="na"&gt;container-image-name-updates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;container=simple-plug-server-production,tag=${CIRCLE_BRANCH}_${CIRCLE_SHA1}"&lt;/span&gt;
          &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this file was added three new jobs. Two &lt;code&gt;aws-ecs/deploy-service-update&lt;/code&gt; respond for the updating respective services in the clusters and &lt;code&gt;approve-deploy&lt;/code&gt; that's waiting for confirmation before the last step for the master branch. For different branches, flows will be a little different. It can be achieved by using parameter &lt;code&gt;filters&lt;/code&gt; in job definitions, where you can specify for which branches or git tags launch jobs.&lt;/p&gt;

&lt;h3&gt;
  
  
  aws-ecs/deploy-service-update job configuration
&lt;/h3&gt;

&lt;p&gt;I would like to tell you about the parameters for the job &lt;code&gt;aws-ecs/deploy-service-update&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt; - the name is used to make jobs in a workflow more human-readable. I am sure you would agree that's &lt;code&gt;deploy-production&lt;/code&gt;
looks much more clearer than &lt;code&gt;aws-ecs/deploy-service-update&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;requires&lt;/strong&gt; - used to define the order of jobs execution, namely the previous job that must be finished successfully.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;family&lt;/strong&gt; - there you should write the name of the task definition(&lt;a href="https://dev.todefine-task"&gt;Define task&lt;/a&gt;) that you used when you 
created the task&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;cluster-name&lt;/strong&gt; - it's pretty obvious - the name of the desired cluster where all magic happens&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;service-name&lt;/strong&gt; - the name of the service that's managing tasks inside the previously mentioned cluster&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;container-image-name-updates&lt;/strong&gt; - updates the Docker image names and/or tag names of existing containers 
                             that had been defined in the previous task definition

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;container&lt;/strong&gt; - the name of the container that you used when you added the container to the task(circled in blue on the screenshot &lt;code&gt;Add container to a task and configure the port mapping&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;tag&lt;/strong&gt; - one of the tags that you are defined in the &lt;code&gt;aws-ecr/build-and-push-image&lt;/code&gt; job, in this example it's a &lt;code&gt;${CIRCLE_BRANCH}_${CIRCLE_SHA1}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;And that's all 🎉. When you push your branch with the new circleci config and start to work you will see something like that.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff7efsjc1ws5slo40k0mx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff7efsjc1ws5slo40k0mx.png"&gt;&lt;/a&gt;&lt;br&gt;Service creation
  &lt;/p&gt;

&lt;p&gt;I hope that this tutorial was helpful and was not wasted your time. If you have any question and problems feel free to ask me about it in the comments. 👋&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
    </item>
    <item>
      <title>CircleCI + AWS How to create CI/CD pipeline from scratch Part 1 - Build and push images</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Sat, 25 Jul 2020 09:35:34 +0000</pubDate>
      <link>https://dev.to/evanilukhin/circleci-aws-how-to-create-ci-cd-pipeline-from-scratch-part-1-build-and-push-images-511d</link>
      <guid>https://dev.to/evanilukhin/circleci-aws-how-to-create-ci-cd-pipeline-from-scratch-part-1-build-and-push-images-511d</guid>
      <description>&lt;h2&gt;
  
  
  Prepare environment for containers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create an IAM user
&lt;/h3&gt;

&lt;p&gt;Right after the creation of an AWS account, you are logging in under the root user. You have full access to every service and the billing management console. To secure interaction with AWS it is a good practice to create a new user inside the group that has only required permissions. &lt;/p&gt;

&lt;p&gt;A few words about managing permissions. There are two main ways to add them to users through &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_groups.html" rel="noopener noreferrer"&gt;groups&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html" rel="noopener noreferrer"&gt;roles&lt;/a&gt;. The main difference is in that groups are a collection of users with the same policies. Roles, in turn, can be used to delegate access not only to users but also to other services and applications, we will use both. Let's create them.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu820ir2b0h6d17w0nt3h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu820ir2b0h6d17w0nt3h.png"&gt;&lt;/a&gt;&lt;br&gt;Create group window
  &lt;/p&gt;

&lt;p&gt;On the second step select the next policies&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AmazonEC2ContainerRegistryFullAccess &lt;/li&gt;
&lt;li&gt;AWSCodeDeployRoleForECS &lt;/li&gt;
&lt;li&gt;AmazonEC2ContainerServiceFullAccess &lt;/li&gt;
&lt;li&gt;AmazonECSTaskExecutionRolePolicy &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpnsb3cbigw9y6aph2bzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpnsb3cbigw9y6aph2bzd.png"&gt;&lt;/a&gt;&lt;br&gt;Group after creation
  &lt;/p&gt;

&lt;p&gt;Then create the role that we will give to ECS to deploy our containers to EC2 instances.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxnhhkaoebhl469ay2rl3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxnhhkaoebhl469ay2rl3.png"&gt;&lt;/a&gt;&lt;br&gt;Create role
  &lt;/p&gt;

&lt;p&gt;and on the second step select in policies &lt;code&gt;AmazonEC2ContainerServiceforEC2Role&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbbh6q9gjcmjwnuyxcyhs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fbbh6q9gjcmjwnuyxcyhs.png"&gt;&lt;/a&gt;&lt;br&gt;Result
  &lt;/p&gt;

&lt;p&gt;More about it is showed &lt;a href="https://docs.aws.amazon.com/AmazonECS/latest/developerguide/instance_IAM_role.html" rel="noopener noreferrer"&gt;there&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And finally, let's add a new user and add to the previously created group:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fayi69xqennnmfk0kw6a7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fayi69xqennnmfk0kw6a7.png"&gt;&lt;/a&gt;&lt;br&gt;New user
  &lt;/p&gt;

&lt;p&gt;This user should have only programmatic access because you will use it only from the circleci. After it, generate access keys and save them, they will need you later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create ECR
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/AmazonECR/latest/userguide/what-is-ecr.html" rel="noopener noreferrer"&gt;ECR&lt;/a&gt; a place where you will store containers from they will be deployed. Just go to the ECR and click on the "Create repository" button. You will see the window where you should select the name for the repository. Other &lt;br&gt;
settings use by default&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6kx7227c33esz22b3w28.png"&gt;ECR Create
  


&lt;p&gt;Great! You have a repository and all required credentials to build and push images. Time to automatize it.&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyvbzmmqqgfcw4ixfycs0.png"&gt;ECR After creation
  

&lt;h2&gt;
  
  
  Configuring Circle CI
&lt;/h2&gt;

&lt;p&gt;The main idea is to run tests after each commit for all branches and deploy after changes in the development and master.&lt;/p&gt;

&lt;p&gt;Before you start to configure the pipeline, you will need to prepare the application&lt;br&gt;
following this fantastic &lt;a href="https://circleci.com/docs/2.0/getting-started/#section=getting-started" rel="noopener noreferrer"&gt;getting started&lt;/a&gt; page.&lt;/p&gt;
&lt;h3&gt;
  
  
  Tests
&lt;/h3&gt;

&lt;p&gt;The most popular use case of the Circle CI that I've seen is running tests (not all developers trust to external&lt;br&gt;
services to deploy applications). To run them you should define &lt;a href="https://circleci.com/docs/2.0/jobs-steps/#jobs-overview" rel="noopener noreferrer"&gt;a job&lt;/a&gt;&lt;br&gt;
and add it as a step to &lt;a href="https://circleci.com/docs/2.0/workflows/" rel="noopener noreferrer"&gt;a workflow&lt;/a&gt;. There is an example of &lt;code&gt;test&lt;/code&gt; workflow&lt;br&gt;
for the &lt;code&gt;simple_plug_server&lt;/code&gt; application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;elixir:1.10&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;MIX_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;working_directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/repo&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix local.hex --force&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix local.rebar --force&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix deps.get&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix deps.compile&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_test_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;_build/test/lib/simple_plug_server&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It has only the one workflow &lt;code&gt;test&lt;/code&gt; with the one job &lt;code&gt;test&lt;/code&gt;. This job has three parts: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;docker - where is defined as a container inside which you will deploy test environment and run tests&lt;/li&gt;
&lt;li&gt;working_directory - the name of the folder where everything is happening&lt;/li&gt;
&lt;li&gt;steps - the set of commands where you download code, setup dependencies and finally run tests. 
You can also &lt;a href="https://circleci.com/docs/2.0/caching/" rel="noopener noreferrer"&gt;cache dependencies&lt;/a&gt; on this step.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can also improve the representing of the failed tests, for it you should add a JUnit formatter for test results&lt;br&gt;
(for elixir it is the hex package &lt;a href="https://github.com/victorolinasc/junit-formatter" rel="noopener noreferrer"&gt;JUnitFormatter&lt;/a&gt;) and specify&lt;br&gt;
the directory containing subdirectories of JUnit XML or Cucumber JSON test metadata files. &lt;br&gt;
More information about it and how to add support for other languages and test frameworks look &lt;a href="https://circleci.com/docs/2.0/collect-test-data/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Build and push containers
&lt;/h3&gt;

&lt;p&gt;On the previous steps we created the ECR repository and the user that can push images, time to setup CircleCI config.&lt;/p&gt;

&lt;p&gt;For work with images we will use the official orb for ECR &lt;a href="https://circleci.com/orbs/registry/orb/circleci/aws-ecr" rel="noopener noreferrer"&gt;circleci/aws-ecr@6.9.1&lt;/a&gt;&lt;br&gt;
It significantly simplifies building and pushing images, let's add the new step to our config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2.1&lt;/span&gt;
&lt;span class="na"&gt;orbs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;aws-ecr&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/aws-ecr@6.9.1&lt;/span&gt;
  &lt;span class="na"&gt;aws-ecs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;circleci/aws-ecs@1.2.0&lt;/span&gt;
&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;docker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;elixir:1.10&lt;/span&gt;
        &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;MIX_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;working_directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;~/repo&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;checkout&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix local.hex --force&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix local.rebar --force&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix deps.get&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix deps.compile&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mix test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;store_test_results&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;_build/test/lib/simple_plug_server&lt;/span&gt;
&lt;span class="na"&gt;workflows&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;test-and-build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;aws-ecr/build-and-push-image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;simple_plug_server"&lt;/span&gt;
          &lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;${CIRCLE_BRANCH}_${CIRCLE_SHA1},${CIRCLE_BRANCH}_latest"&lt;/span&gt;
          &lt;span class="na"&gt;requires&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
          &lt;span class="na"&gt;filters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;
                &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;development&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Briefly about the steps of this job:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;repo - the name of the repository (last part of the &lt;code&gt;815991645042.dkr.ecr.us-west-2.amazonaws.com/simple_plug_server&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;tag - tags that we apply to the built container, for the master branch it will add two tags: 
master_02dacfb07f7c09107e2d8da9955461f025f7f443 and master_latest&lt;/li&gt;
&lt;li&gt;requires - there you should describe the previous necessary steps, in this example we build an image only 
if all tests pass&lt;/li&gt;
&lt;li&gt;filters - describe for which branches this job should execute. There are a lot of other &lt;a href="https://circleci.com/docs/2.0/configuration-reference/#filters-1" rel="noopener noreferrer"&gt;filters&lt;/a&gt;
that you can use to customize a workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But before you start to run this workflow you should add the next environment variables:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AWS_ACCESS_KEY_ID - access key for &lt;code&gt;circleci&lt;/code&gt; that you obtained on &lt;a href=""&gt;this step&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS_SECRET_ACCESS_KEY - secret key for &lt;code&gt;circleci&lt;/code&gt; that you obtained on &lt;a href=""&gt;this step&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;AWS_REGION - region where placed your ECR instance&lt;/li&gt;
&lt;li&gt;AWS_ECR_ACCOUNT_URL - url of the ECR(looks like 815991645042.dkr.ecr.us-west-2.amazonaws.com)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcyb0myv33xnqv93a2rqv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fcyb0myv33xnqv93a2rqv.png"&gt;&lt;/a&gt;&lt;br&gt;CircleCI ENV Settings example
  &lt;/p&gt;

&lt;p&gt;After successful build of the development and master branches you will see something like there: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffrjverkv167wd4qcquu2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ffrjverkv167wd4qcquu2.png"&gt;&lt;/a&gt;&lt;br&gt;ECR after the successful push
  &lt;/p&gt;

&lt;p&gt;Great! You automatized process of running tests and building images in the next chapter you will see how to&lt;br&gt;
setup servers on the AWS infrastructure and redeploy them after successfully passed tests.&lt;/p&gt;

</description>
      <category>devops</category>
      <category>aws</category>
    </item>
    <item>
      <title>CircleCI + AWS How to create CI/CD pipeline from scratch Part 0 - Preparation</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Sat, 25 Jul 2020 09:35:20 +0000</pubDate>
      <link>https://dev.to/evanilukhin/circleci-aws-how-to-create-ci-cd-pipeline-from-scratch-part-0-preparation-59ni</link>
      <guid>https://dev.to/evanilukhin/circleci-aws-how-to-create-ci-cd-pipeline-from-scratch-part-0-preparation-59ni</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this series of posts, I'm going to show how to set up the CI/CD environment using AWS and CircleCI.&lt;br&gt;
As a final result, you will get the pipeline that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;runs tests after each commit;&lt;/li&gt;
&lt;li&gt;builds containers from development and master branches;&lt;/li&gt;
&lt;li&gt;pushes them into the ECR;&lt;/li&gt;
&lt;li&gt;redeploys development and production EC2 instances from the development and master containers respectively.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This guide consists of three parts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;➡️ &lt;strong&gt;Preparation&lt;/strong&gt; - where I'll explain this workflow, and show how to prepare an application for it &lt;/li&gt;
&lt;li&gt;AWS - this chart is about how to set up the AWS environment from scratch;&lt;/li&gt;
&lt;li&gt;CircleCI - here I'll demonstrate how to automatize deployment process using &lt;a href="//circleci.com"&gt;circleci.com&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Workflow
&lt;/h3&gt;

&lt;p&gt;When you developing applications in "real life" you usually(but not always), sooner or later, found that you need to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🤖 run automatic tests;&lt;/li&gt;
&lt;li&gt;🔍 run different checks(code coverage, security audit, code style, etc.);&lt;/li&gt;
&lt;li&gt;🧪 test how a feature works before you deploy it to the production;&lt;/li&gt;
&lt;li&gt;💸 deliver results as fast as possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There is an example of a workflow that was used in many projects where I've participated. It works very well in small(3-8 person) teams:&lt;/p&gt;

&lt;p&gt;1) Create a branch for a feature from master&lt;br&gt;
2) Work&lt;br&gt;
3) Push this feature&lt;br&gt;
4) &lt;strong&gt;Optionally&lt;/strong&gt; Run tests, checks, etc. for this branch &lt;br&gt;
5) In case of success merge this branch to the development branch&lt;br&gt;
6) Run everything again and redeploy the development server&lt;br&gt;
7) Test it manually&lt;br&gt;
8) Merge feature to the production branch&lt;br&gt;
9) Redeploy production&lt;/p&gt;


  &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Fsb%2Fu5%2Fyl%2Fsbu5ylcp45dfnza5b8__lnoboye.png"&gt;Workflow example
  


&lt;p&gt;I'm going to show how it can work on the workflow with two main branches: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;master - has tested, production-ready code(deploys on a production server after approving)&lt;/li&gt;
&lt;li&gt;development - based on the master and also has changes that being tested now(deploys on a development server right after changes on the github)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Prepare the application
&lt;/h2&gt;

&lt;p&gt;As an example let's take a simple API server with one route written on the Elixir. I will not explain here how to create it, there is a fantastic &lt;a href="https://dev.to/jonlunsford/elixir-building-a-small-json-endpoint-with-plug-cowboy-and-poison-1826"&gt;post&lt;/a&gt; about. Or you can use &lt;a href="https://github.com/evanilukhin/simple_plug_server" rel="noopener noreferrer"&gt;my application&lt;/a&gt;, it is already configured and prepared. &lt;br&gt;
There I'll focus only on the specific moments that are needed to prepare the server for work in this environment. &lt;/p&gt;
&lt;h3&gt;
  
  
  Prepare release application
&lt;/h3&gt;

&lt;p&gt;This Elixir application I am going to deploy using mechanism of &lt;a href="https://hexdocs.pm/mix/Mix.Tasks.Release.html" rel="noopener noreferrer"&gt;releases&lt;/a&gt;.&lt;br&gt;
Briefly, it generates an artefact that contains the Erlang VM and its runtime, compiled source code and launch scripts.&lt;/p&gt;



&lt;p&gt;Let me make a little digress to tell about the methodology I'm trying to follow for designing microservices. &lt;br&gt;
I'm talking about &lt;a href="https://12factor.net" rel="noopener noreferrer"&gt;12 factor app manifest&lt;/a&gt;. It's a set of recommendations for building software-as-a-service apps that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use declarative formats for setup automation, to minimize time and cost for new developers joining the project.
&lt;/li&gt;
&lt;li&gt;Have a clean contract with the underlying operating system, offering maximum portability between execution environments.
&lt;/li&gt;
&lt;li&gt;Are suitable for deployment on modern cloud platforms, obviating the need for servers and systems administration.
&lt;/li&gt;
&lt;li&gt; Minimize divergence between development and production, enabling continuous deployment for maximum agility.
&lt;/li&gt;
&lt;li&gt;And can scale up without significant changes to tooling, architecture, or development practices.&lt;/li&gt;
&lt;/ul&gt;



&lt;p&gt;&lt;a href="https://12factor.net/config" rel="noopener noreferrer"&gt;One of these principles&lt;/a&gt; recommends us to store configurable parameters(ports, API keys, services addresses, etc.) in system environment variables. To configure our release application using them you should create the file &lt;code&gt;config/releases.exs&lt;/code&gt; and describe these variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight elixir"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="no"&gt;Config&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt; &lt;span class="ss"&gt;:simple_plug_server&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;port:&lt;/span&gt; &lt;span class="no"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_env&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"PORT"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;More about different config files in Elixir applications you can find &lt;a href="https://elixir-lang.org/getting-started/mix-otp/config-and-releases.html#configuring-releases" rel="noopener noreferrer"&gt;here&lt;/a&gt; &lt;br&gt;
and &lt;a href="https://hexdocs.pm/mix/Mix.Tasks.Release.html#module-application-configuration" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Launch script
&lt;/h3&gt;

&lt;p&gt;Next thing I would like to cover is starting an application. The most common way is to use a special shell script&lt;br&gt;
for it that contains different preparation steps like waiting for a database, initializing system variables, etc. Also,&lt;br&gt;
it makes your Docker file more expressive. I think you will agree that &lt;code&gt;CMD ["bash", "./simple_plug_server/entrypoint.sh"]&lt;/code&gt; looks better than &lt;code&gt;CMD ["bash", "cmd1", "arg1", "arg2", ";" "cmd2", "arg1", "arg2", "arg3"]&lt;/code&gt;. The entrypoint script for this server is very simple:&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;#!/bin/sh&lt;/span&gt;

bin/simple_plug_server start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This application works in the docker container so the last command &lt;code&gt;bin/simple_plug_server start&lt;/code&gt; starts&lt;br&gt;
app without daemonizing it and writes logs right into the stdout. That allows us to &lt;a href="https://12factor.net/logs" rel="noopener noreferrer"&gt;gather logs&lt;/a&gt; simpler(AWS Cloudwatch gathers these data without additional configs).&lt;/p&gt;
&lt;h3&gt;
  
  
  Dockerization
&lt;/h3&gt;

&lt;p&gt;And on the last step, you should create the &lt;a href="https://dev.toDockerfile"&gt;Dockerfile&lt;/a&gt; that builds result container. I prefer to use two steps builds for Elixir applications because result containers are very thin(approx. 50-70MB).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;elixir:1.10.0-alpine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;build&lt;/span&gt;

&lt;span class="c"&gt;# install build dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--update&lt;/span&gt; git build-base

&lt;span class="c"&gt;# prepare build dir&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /app
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="c"&gt;# install hex + rebar&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mix local.hex &lt;span class="nt"&gt;--force&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    mix local.rebar &lt;span class="nt"&gt;--force&lt;/span&gt;

&lt;span class="c"&gt;# set build ENV&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; MIX_ENV=prod&lt;/span&gt;

&lt;span class="c"&gt;# install mix dependencies&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; mix.exs mix.lock ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; config config&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mix deps.get
&lt;span class="k"&gt;RUN &lt;/span&gt;mix deps.compile

&lt;span class="c"&gt;# build project&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; lib lib&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mix compile

&lt;span class="c"&gt;# build release&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;mix release

&lt;span class="c"&gt;# prepare release image&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;alpine:3.12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;app&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apk add &lt;span class="nt"&gt;--update&lt;/span&gt; bash openssl

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; /app
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/_build/prod/rel/simple_plug_server ./&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/lib/simple_plug_server/entrypoint.sh ./simple_plug_server/entrypoint.sh&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;chown&lt;/span&gt; &lt;span class="nt"&gt;-R&lt;/span&gt; nobody: /app
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; nobody&lt;/span&gt;

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; HOME=/app&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["bash", "./simple_plug_server/entrypoint.sh"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally you can build it using &lt;code&gt;docker build .&lt;/code&gt;, and  run &lt;code&gt;docker run -it -p 4000:4000 -e PORT=4000 {IMAGE_ID}&lt;/code&gt;. &lt;br&gt;
The server will be available on the &lt;code&gt;localhost:4000&lt;/code&gt; and will write logs to the stdout. 🎉&lt;/p&gt;

&lt;p&gt;On the next part of this tutorial, I'll show how to automatically build images using CircleCI and push them to the Amazon ECR.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>elixir</category>
    </item>
    <item>
      <title>Rails API + React SPA authentication problem — Authentication by cookies</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Tue, 24 Dec 2019 17:28:34 +0000</pubDate>
      <link>https://dev.to/evanilukhin/rails-api-react-spa-authentication-problem-authentication-by-cookies-4449</link>
      <guid>https://dev.to/evanilukhin/rails-api-react-spa-authentication-problem-authentication-by-cookies-4449</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;In this series of articles, I’ll cover different ways for a user authentification in systems with separated frontend and backend. As an example, I took my lovely programming language Ruby with RoR, with which I’ve been working already four years, for API and React application, based on CRA template, for separated frontend.&lt;/p&gt;

&lt;p&gt;Source code for SPA you can find &lt;a href="https://github.com/evanilukhin/auth_playground_react_spa" rel="noopener noreferrer"&gt;here&lt;/a&gt;. For API — &lt;a href="https://github.com/evanilukhin/auth_playground_rails_api" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Problem
&lt;/h3&gt;

&lt;p&gt;Imagine that some people request to develop a system for storing the most valuable thing for them — their names. Besides, users love to admire their treasure only personally. For it, they wish that the system must show name only after logging in and must not ask it for one week. Moreover, they are planning to develop GUI and API by different teams, so these parts must be independent applications.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fevanilukhin%2Farticles%2Fblob%2Fmaster%2Fposts%2FRails%2520API%2520%2B%2520React%2520SPA%2520authentication%2FHigh%2520level%2520view.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fevanilukhin%2Farticles%2Fblob%2Fmaster%2Fposts%2FRails%2520API%2520%2B%2520React%2520SPA%2520authentication%2FHigh%2520level%2520view.jpg%3Fraw%3Dtrue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Design — API
&lt;/h3&gt;

&lt;p&gt;A core entity of the API has a model User that contains only three fields:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;login&lt;/strong&gt; — string which users do not scare to show;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;password&lt;/strong&gt; — stored as a password digest;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;name&lt;/strong&gt; — sacred for every user information that we only show when they are authorized.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Design — SPA
&lt;/h3&gt;

&lt;p&gt;The page has only one block, that is show login form if user not authorized and not blank field “Name” above in case of successful authentication.&lt;/p&gt;

&lt;p&gt;Let’s go further and consider how to authenticate our users by cookies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication by cookies
&lt;/h2&gt;

&lt;p&gt;The most common and obvious approach is to use HTTP cookies for storing auth information. Ruby on Rails has two similar mechanisms for working with cookies, it’s cookies themselves and sessions. For cookies, we can set an httponly flag, that protects from xss attacks, domain, and expiration date. Sessions are stored in cookies inside an encrypted string, where an httponly flag is set by default. For this example, I took sessions because the SPA does not read from cookies.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;SPA sends a POST request with login and password&lt;/li&gt;
&lt;li&gt;API write user.id in the session cookie&lt;/li&gt;
&lt;li&gt;Component try to get the name of the user sending a request with the session&lt;/li&gt;
&lt;li&gt;API find a user by user id and if all right return name of this user&lt;/li&gt;
&lt;li&gt;Component is updated

&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fevanilukhin%2Farticles%2Fblob%2Fmaster%2Fposts%2FRails%2520API%2520%2B%2520React%2520SPA%2520authentication%2Fcookies_sequence_1.jpg%3Fraw%3Dtrue"&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let’s dive deeper.&lt;/p&gt;

&lt;p&gt;Usually, SPA and API are deployed on different hosts, hence there appears the next problem — how to pass and modify cookies. By default browser does not set cookies from another origin by javascript. But we can easily enable it.&lt;/p&gt;

&lt;h3&gt;
  
  
  SPA side.
&lt;/h3&gt;

&lt;p&gt;For communicating with a server SPA uses the Fetch API that is provided in a global window scope. For enabling a possibility to send and receive cookies from resources with a different origin. We must set the next option:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;credentials: ‘include’ — it enables sending cookies for cross-origin requests by default it is set for the same origin;&lt;/li&gt;
&lt;li&gt;mode: ‘cors’ — allows to work with all headers related to CORS. By default, it allows only for same-origin requests.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples you will find further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Server side.
&lt;/h2&gt;

&lt;p&gt;To enable the supporting of cross-origin requests in RoR, you must add gem rack-cors that provides support for CORS for a Rack middleware. When you create rails application from a generator with API you need only uncomment string &lt;em&gt;“gem ‘rack-cors’”&lt;/em&gt; in Gemfile and content of the config file &lt;code&gt;config/initializers/cors.rb&lt;/code&gt;. For setting cookies you must set parameter credentials as true. Important notice, it works only if the origin is not a wildcard. For security reason and flexibility I usually set it from environment variables like there:&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;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;insert_before&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Rack&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cors&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;origins&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'SPA_ORIGIN'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;resource&lt;/span&gt; &lt;span class="s1"&gt;'*'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;headers: :any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="ss"&gt;methods: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:get&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:put&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:patch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:delete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:head&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="ss"&gt;credentials: &lt;/span&gt;&lt;span class="kp"&gt;true&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;
  
  
  Sending and handling requests
&lt;/h3&gt;

&lt;p&gt;After the setting our projects for work with cookies let’s look at how are requests handled.&lt;/p&gt;

&lt;p&gt;Post request contains data and cors friendly settings, about I mentioned above.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;authUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apiUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&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;data&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;login&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;password&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&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;Content-Type&lt;/span&gt;&lt;span class="dl"&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;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;authUrl&lt;/span&gt;&lt;span class="p"&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="s1"&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;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;follow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-referrer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;include&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Request handled by standard Rails controller. API finds a user and if all right writes user’s id in a session.&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;AuthController&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="kp"&gt;include&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cookies&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;login&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;login: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;authenticate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'data'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'password'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
        &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&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="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s1"&gt;'Wrong login or password'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;
      &lt;span class="k"&gt;end&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="p"&gt;{},&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;
    &lt;span class="k"&gt;end&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;Next requests for getting the name send this session and controller just read it and sends name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;username_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;apiUrl&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;if&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="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;username_url&lt;/span&gt;&lt;span class="p"&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="s1"&gt;GET&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;cors&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;cache&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-cache&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;follow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;referrer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;no-referrer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;include&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&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="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&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="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myJson&lt;/span&gt; &lt;span class="o"&gt;=&amp;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="nf"&gt;setState&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;myJson&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&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="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;..and related controller:&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;UsersController&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="kp"&gt;include&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cookies&lt;/span&gt;
      &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:find_user&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="vi"&gt;@current_user&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;User&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;name: &lt;/span&gt;&lt;span class="vi"&gt;@current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&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;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;message: &lt;/span&gt;&lt;span class="s1"&gt;'Bad user'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;
        &lt;span class="k"&gt;end&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;find_user&lt;/span&gt;
        &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="vi"&gt;@current_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;user_id&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;Pretty simple!&lt;/p&gt;

&lt;h3&gt;
  
  
  Pros
&lt;/h3&gt;

&lt;p&gt;Security — httponly flag prevents cookies from stealing your auth data by XSS attacks. (I hope that you use https by default).&lt;/p&gt;

&lt;p&gt;Simplicity — mechanisms for working with cookies and sessions are proven and exist almost in all frameworks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Cons
&lt;/h3&gt;

&lt;p&gt;Works only inside with web-browsers.&lt;/p&gt;

</description>
      <category>rails</category>
      <category>react</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Ruby Interview Tasks - Simple word calculator</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Mon, 23 Dec 2019 16:17:46 +0000</pubDate>
      <link>https://dev.to/evanilukhin/ruby-interview-tasks-simple-word-calculator-445d</link>
      <guid>https://dev.to/evanilukhin/ruby-interview-tasks-simple-word-calculator-445d</guid>
      <description>&lt;p&gt;Recently during an interview live coding session, I got a pretty interesting task:&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;# Make this code working&lt;/span&gt;
&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;two&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt;&amp;gt; 3&lt;/span&gt;
&lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;three&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; -2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I was tired and tried to solve it by adding some method to a String instance methods like there:&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;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'1'&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;one&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plus&lt;/span&gt;
  &lt;span class="n"&gt;temp_plus&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="nb"&gt;self&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;+"&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;temp_plus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;two&lt;/span&gt;
    &lt;span class="n"&gt;temp_plus_two&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="nb"&gt;self&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;2"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;temp_plus_two&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;
      &lt;span class="nb"&gt;eval&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="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;temp_plus_two&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;temp_plus&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;one&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minus&lt;/span&gt;
  &lt;span class="n"&gt;temp_minus&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="nb"&gt;self&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;-"&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;temp_minus&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;three&lt;/span&gt;
    &lt;span class="n"&gt;temp_minus_three&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="nb"&gt;self&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;3"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;temp_minus_three&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt;
      &lt;span class="nb"&gt;eval&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="k"&gt;end&lt;/span&gt;

    &lt;span class="n"&gt;temp_minus_three&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;temp_minus&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="c1"&gt;# Yes, it works&lt;/span&gt;
&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;two&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 3&lt;/span&gt;
&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;three&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks bulky and terrible. Yes, Ruby allows to do this, but it is natural monkey patching, and I would not be used similar construction in real projects.&lt;br&gt;
Six hours later, when I woke up, I realized that there is exist a significantly more straightforward and elegant solution. It’s just a realization of the method chaining pattern:&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;Evaluator&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="nb"&gt;self&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expression_part&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;define_method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
        &lt;span class="n"&gt;return_new_instance&lt;/span&gt; &lt;span class="n"&gt;expression_part&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="ss"&gt;:plus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="s1"&gt;'+'&lt;/span&gt;
  &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="ss"&gt;:minus&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'-'&lt;/span&gt;
  &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="ss"&gt;:two&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   &lt;span class="s1"&gt;'2'&lt;/span&gt;
  &lt;span class="n"&gt;operation&lt;/span&gt; &lt;span class="ss"&gt;:three&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'3'&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;expression&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@expression&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;expression&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;equal&lt;/span&gt;
    &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@expression&lt;/span&gt;&lt;span class="p"&gt;)&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;return_new_instance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expression_part&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@expression&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="vi"&gt;@expression&lt;/span&gt;&lt;span class="si"&gt;}#{&lt;/span&gt;&lt;span class="n"&gt;expression_part&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&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;class&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="vi"&gt;@expression&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;span class="n"&gt;one&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Evaluator&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="s1"&gt;'1'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;two&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; 3&lt;/span&gt;
&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="n"&gt;one&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;minus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;three&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; -2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pretty neat!&lt;br&gt;
This task is well for estimating the level of a developer. Specifically, the knowledge of method chaining pattern(interviewee mentioned it or just used it), how to use metaprogramming and awareness about monkey patching and bad solutions.&lt;/p&gt;

</description>
      <category>ruby</category>
    </item>
    <item>
      <title>Guide to install PyTorch with CUDA on Ubuntu 18.04</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Fri, 20 Dec 2019 18:40:28 +0000</pubDate>
      <link>https://dev.to/evanilukhin/guide-to-install-pytorch-with-cuda-on-ubuntu-18-04-5217</link>
      <guid>https://dev.to/evanilukhin/guide-to-install-pytorch-with-cuda-on-ubuntu-18-04-5217</guid>
      <description>&lt;h1&gt;
  
  
  Guide to install PyTorch with CUDA on Ubuntu 18.04
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fukv2ncfhz9jwrcmla6at.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fukv2ncfhz9jwrcmla6at.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yesterday I was installing PyTorch and encountered with different difficulties during the installation process. Let me share the resulting path, that brought me to the successful installation. I hope this little instruction will save you time and show further direction. &lt;/p&gt;

&lt;h3&gt;
  
  
  Install Python3.8
&lt;/h3&gt;

&lt;p&gt;PyTorch requires Python version 3.7 or above, so I decided to install the latest stable version on this moment Python 3.8. Standard Ubuntu repository has maximum 3.6, so I added repository from the “deadsnakes” team &lt;a href="https://launchpad.net/~deadsnakes/+archive/ubuntu/ppa" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&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="nb"&gt;sudo &lt;/span&gt;add-apt-repository ppa:deadsnakes/ppa
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;python3.8 python3.8-dev python3.8-venv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;python3.8-dev&lt;/code&gt; - requires for building C extensions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;python3.8-venv&lt;/code&gt; - provides support for creating lightweight “virtual environments” with their own site directories&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Install CUDA
&lt;/h3&gt;

&lt;p&gt;My graphic card supports CUDA, so why not take advantage of this.&lt;br&gt;
Just choose one of the type of installation &lt;a href="https://developer.nvidia.com/cuda-downloads?target_os=Linux&amp;amp;target_arch=x86_64&amp;amp;target_distro=Ubuntu&amp;amp;target_version=1804" rel="noopener noreferrer"&gt;there&lt;/a&gt;. I selected &lt;code&gt;deb(network)&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;wget https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/cuda-ubuntu1804.pinsudo 
&lt;span class="nb"&gt;mv &lt;/span&gt;cuda-ubuntu1804.pin /etc/apt/preferences.d/cuda-repository-pin-600
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-key adv &lt;span class="nt"&gt;--fetch-keys&lt;/span&gt; https://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/7fa2af80.pub
&lt;span class="nb"&gt;sudo &lt;/span&gt;add-apt-repository &lt;span class="s2"&gt;"deb http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1804/x86_64/ /"&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get update
&lt;span class="nb"&gt;sudo &lt;/span&gt;apt-get &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="nb"&gt;install &lt;/span&gt;cuda
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install pip
&lt;/h3&gt;

&lt;p&gt;Before pip installation, you should create a new &lt;a href="https://packaging.python.org/tutorials/installing-packages/#creating-virtual-environments" rel="noopener noreferrer"&gt;virtual environment&lt;/a&gt; for Python. On the first step, we installed &lt;code&gt;python3.8-venv&lt;/code&gt; exactly for this purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3.8 &lt;span class="nt"&gt;-m&lt;/span&gt; venv ~/python_env/my_env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command creates a new local environment in your local folder. After the directory has been created "activate" this environment by the next command. (Works only for bash/zsh, for other shells look &lt;a href="https://docs.python.org/3/library/venv.html" rel="noopener noreferrer"&gt;there&lt;/a&gt;)&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="nb"&gt;source&lt;/span&gt; ~/python_env/my_env/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install &lt;code&gt;pip&lt;/code&gt; following by the (instruction)[&lt;a href="https://pip.pypa.io/en/stable/installing/" rel="noopener noreferrer"&gt;https://pip.pypa.io/en/stable/installing/&lt;/a&gt;]&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://bootstrap.pypa.io/get-pip.py &lt;span class="nt"&gt;-o&lt;/span&gt; get-pip.py
python get-pip.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Perfect! Let's go to the finish. 🏁&lt;/p&gt;

&lt;h3&gt;
  
  
  And the final step - Get, compile and install PyTorch
&lt;/h3&gt;

&lt;p&gt;Firstly install &lt;code&gt;cmake&lt;/code&gt; and clone the necessary version of the PyTorch. Don't be afraid, repository really big, so it takes a lot of time:&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="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;cmake
git clone &lt;span class="nt"&gt;--recursive&lt;/span&gt; https://github.com/pytorch/pytorch.git
git submodule &lt;span class="nb"&gt;sync
&lt;/span&gt;git submodule update &lt;span class="nt"&gt;--init&lt;/span&gt; &lt;span class="nt"&gt;--recursive&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Than install all required Python packages using pip:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Ensure that you use right Python virtual environment&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3.8 &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install &lt;/span&gt;numpy ninja pyyaml mkl mkl-include setuptools cmake cffi typing
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ensure that you are in the cloned directory and run the next commands:&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="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CMAKE_PREFIX_PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CONDA_PREFIX&lt;/span&gt;&lt;span class="k"&gt;:-&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;which conda&lt;span class="si"&gt;))&lt;/span&gt;&lt;span class="s2"&gt;/../"&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;
python setup.py &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;🎉 Congratulations, you are installed the PyTorch in your local virtual environment. Time to check it!&lt;/p&gt;

&lt;h3&gt;
  
  
  Running
&lt;/h3&gt;

&lt;p&gt;Create the file &lt;code&gt;torch_program.py&lt;/code&gt; and add the next lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;__future__&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;print_function&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;

&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ones&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;device&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cuda&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# a CUDA device object
&lt;/span&gt;    &lt;span class="n"&gt;y&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ones_like&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# directly create a tensor on GPU
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;                       &lt;span class="c1"&gt;# or just use strings ``.to("cuda")``
&lt;/span&gt;    &lt;span class="n"&gt;z&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;double&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If all installed correctly there will be the followed resuls:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tensor([[1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1.],
        [1., 1., 1., 1., 1.]])
tensor([[2., 2., 2., 2., 2.],
        [2., 2., 2., 2., 2.],
        [2., 2., 2., 2., 2.],
        [2., 2., 2., 2., 2.],
        [2., 2., 2., 2., 2.]], device='cuda:0')
tensor([[2., 2., 2., 2., 2.],
        [2., 2., 2., 2., 2.],
        [2., 2., 2., 2., 2.],
        [2., 2., 2., 2., 2.],
        [2., 2., 2., 2., 2.]], dtype=torch.float64)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you get stuck following this manual feel free to write in comments about it, I'll be sure to expand this post with the new information.&lt;/p&gt;

&lt;p&gt;Happy Machine Learning! 🤖📖&lt;/p&gt;

</description>
      <category>python</category>
      <category>beginners</category>
      <category>pytorch</category>
      <category>ubuntu</category>
    </item>
    <item>
      <title>Rails API + SPA authorization — Authorization by JWT</title>
      <dc:creator>Ivan Iliukhin</dc:creator>
      <pubDate>Tue, 29 Oct 2019 08:55:45 +0000</pubDate>
      <link>https://dev.to/evanilukhin/rails-api-spa-authorization-authorization-by-jwt-19cm</link>
      <guid>https://dev.to/evanilukhin/rails-api-spa-authorization-authorization-by-jwt-19cm</guid>
      <description>&lt;p&gt;One of the ways to provide authorization is to use JSON Web Tokens or JWT. It is a popular way to implement authorization between different services by logging in only once. In this blog post, I’ll briefly explain what is it, tell about some pitfalls and show how to add in an application.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is it, and why is it so popular?
&lt;/h1&gt;

&lt;p&gt;Briefly, it’s a signed string that contains some information in a not ciphered form and a verification signature, that proves that information was not changed. JWTs &lt;strong&gt;doesn’t protect data from stealing&lt;/strong&gt;. They are only &lt;strong&gt;protected from changing&lt;/strong&gt;. The closest analogy from the real world is an RFID ID card with the printed on it information. Everyone can see what is written on a card, but only who know secret can change it. Furthermore, someone can steal your card and freely use one. I will not explain in detail about the structure of JWTs, it very clear and short described on the official site.&lt;/p&gt;

&lt;h2&gt;
  
  
  And why is this approach so popular today?
&lt;/h2&gt;

&lt;p&gt;Most of the modern applications consist of a bunch of microservices developing by different teams. First returns frontend, second provides an API, third gathers statistics of usage, etc., and they communicate with each other. We want to know some information about a request (who made it, user type and etc.) and that this information has not tampered.&lt;/p&gt;

&lt;p&gt;There are listed the most popular cases of usage JWTs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;authorization between independent SPA and API;&lt;/li&gt;
&lt;li&gt;providing authorization for different web-applications using only one for an authentification;&lt;/li&gt;
&lt;li&gt;secured information exchange between services, tokens guarantees that information was not changed during transmission.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;JWT is a good solution for authorization but not without some controversies. &lt;/p&gt;

&lt;p&gt;Let’s go to nuances of usage and caveats.&lt;/p&gt;

&lt;h3&gt;
  
  
  Confidential information exchange
&lt;/h3&gt;

&lt;p&gt;This mentioned in almost all posts about JWTs, and I will remind too.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DO NOT USE JSON WEB TOKENS FOR STORING AND PASSING CONFIDENTIAL DATA!&lt;/strong&gt; &lt;br&gt;
Like passwords, information from official documents and etc. Everyone who has a token sees the content.&lt;/p&gt;
&lt;h3&gt;
  
  
  Stateless requests
&lt;/h3&gt;

&lt;p&gt;In many articles are spoked of the next advantage of JWTs— stateless. It means that we store all necessary information inside the token, though we can reduce the amount of connection to a central database. It makes sense in the environment with dozens of microservices. But, what if a token was compromised. Yes usually it has an expiration date, but what if we must cancel it right now.&lt;/p&gt;

&lt;p&gt;There is a simple solution, unfortunately, it violates the mentioned above advantage. We can store blacklisted tokens in a database (Redis for example) to deny access by using an invalid token. Another good idea is to save user sessions(user id + valid token + token expiration date). It will be a little bit slow, but we can always get the information about how much users are logged in. Furthermore, the application must go to a database every time processing a request, as a consequence recommended to use for a blacklist/session storage an in-memory database with O(1) access time.&lt;/p&gt;

&lt;p&gt;In many cases, it is not necessary, however, keep it in mind when you decide to use JWTs for users authentication/authorization.&lt;/p&gt;
&lt;h2&gt;
  
  
  Time to practice
&lt;/h2&gt;

&lt;p&gt;For this service, I used the most popular authentification solution for the Ruby on Rails — &lt;a href="https://github.com/nsarno/knock" rel="noopener noreferrer"&gt;Knock&lt;/a&gt;. This gem leverages efforts for creating and decoding tokens. Let’s look at how it easy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add gem to the project &lt;a href="https://github.com/nsarno/knock#installation" rel="noopener noreferrer"&gt;link&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;add finding user by the login to the User model(by default Knock uses email field);
&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;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_token_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# Returns a valid user, `nil` or raise `Knock.not_found_exception_class_name`&lt;/span&gt;
  &lt;span class="n"&gt;login&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'auth'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'auth'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s1"&gt;'login'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;login: &lt;/span&gt;&lt;span class="n"&gt;login&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;user&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;Knock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;not_found_exception_class_name&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;Create UserTokenController to generate token and UsersController, that returns user’s name, when token is correct and user still exists&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;module&lt;/span&gt; &lt;span class="nn"&gt;Api&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Jwt&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UsersController&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="kp"&gt;include&lt;/span&gt; &lt;span class="no"&gt;Knock&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Authenticable&lt;/span&gt;

      &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:authenticate_user&lt;/span&gt;

      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&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;name: &lt;/span&gt;&lt;span class="n"&gt;current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&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;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;and controller, that generates tokens for the User.&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;module&lt;/span&gt; &lt;span class="nn"&gt;Api&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Jwt&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UserTokenController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Knock&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;AuthTokenController&lt;/span&gt;
      &lt;span class="n"&gt;skip_before_action&lt;/span&gt; &lt;span class="ss"&gt;:verify_authenticity_token&lt;/span&gt;
    &lt;span class="k"&gt;end&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;Pretty simple!&lt;/p&gt;

&lt;p&gt;On this scheme is depicted how it works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffu%2Fnb%2Fnn%2Ffunbnn0l-z0tglywc9yyugwc8am.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffu%2Fnb%2Fnn%2Ffunbnn0l-z0tglywc9yyugwc8am.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We make POST request with the form-data(login and password in our case) and get token in response. This token can be attached as &lt;a href="https://tools.ietf.org/html/rfc6750" rel="noopener noreferrer"&gt;the bearer authentification token&lt;/a&gt; in headers, or just transferred in a request body.&lt;/p&gt;

&lt;p&gt;Yes, it looks like a simple and working solution, but what can happen if you decide to use it in a web application(SPA, for example) that works from a browser. A gotten token can be stored by javascript to next usage in headers to local storage or normal cookies(not HTTP only), it means that anyone(third-party javascript libraries, browser extensions, etc.) has access to this token. What is wrong with it? Correct! The token is vulnerable to &lt;a href="https://www.owasp.org/index.php/Cross-site_Scripting_(XSS)" rel="noopener noreferrer"&gt;XSS attacks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But there is a way to avoid it — cookies with &lt;a href="https://www.owasp.org/index.php/HttpOnly" rel="noopener noreferrer"&gt;HttpOnly flag&lt;/a&gt;. In Rails you can use or sessions (special encrypted cookies, httponly by default) or just cookie with this flag. The main difference between them is next. A session cookie is encrypted by default, a usual cookie you must encrypt manually. I’ll show how to realize it on sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  JWT inside session
&lt;/h3&gt;

&lt;p&gt;By default sessions are destroyed right after closing a browser, though if you want to increase their expiration date add this parameter to the session initializer config/initializers/session_store.rb:&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;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;session_store&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:cookie_store&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;expire_after: &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or to the middleware in config/application.rb when you use api-only application:&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt; &lt;span class="no"&gt;ActionDispatch&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Session&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;CookieStore&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;expire_after: &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;days&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case, when you want to store and configure it separately from session use encrypted, httponly cookie.&lt;/p&gt;

&lt;p&gt;Next, you should redefine current knock behaviour for creating token:&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;UserTokenController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Knock&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;AuthTokenController&lt;/span&gt;
  &lt;span class="kp"&gt;include&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cookies&lt;/span&gt;
  &lt;span class="n"&gt;skip_before_action&lt;/span&gt; &lt;span class="ss"&gt;:verify_authenticity_token&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;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:jwt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth_token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_json&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;body: &lt;/span&gt;&lt;span class="kp"&gt;nil&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;p&gt;As you can see, I skipped &lt;a href="https://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection.html" rel="noopener noreferrer"&gt;CSRF verification&lt;/a&gt;, because this API works with SPA with another origin and Knock::AuthToken depends from AuthController::Base, where it enabled by default. In the redefined method create I add token to the session and render nothing with the status code 201.&lt;/p&gt;

&lt;p&gt;UsersController will be a little bit more complicated:&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;UsersController&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="kp"&gt;include&lt;/span&gt; &lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Cookies&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:find_user&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;name&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@current_user&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&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;User&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;name: &lt;/span&gt;&lt;span class="vi"&gt;@current_user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&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;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;message: &lt;/span&gt;&lt;span class="s1"&gt;'Bad user'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;
    &lt;span class="k"&gt;end&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;find_user&lt;/span&gt;
    &lt;span class="n"&gt;jwt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:jwt&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;present?&lt;/span&gt;
      &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jwt&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="s1"&gt;'jwt'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Knock&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;AuthToken&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;token: &lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'sub'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
      &lt;span class="vi"&gt;@current_user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;user_id&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;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;message: &lt;/span&gt;&lt;span class="s1"&gt;'Token not found'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: &lt;/span&gt;&lt;span class="mi"&gt;401&lt;/span&gt;
    &lt;span class="k"&gt;end&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;In find_user I try to find the token in the session and decipher it. How it looks on scheme:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffa%2Fhq%2F6j%2Ffahq6jfy02j01o0mgyg8dfg9khs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fhabrastorage.org%2Fwebt%2Ffa%2Fhq%2F6j%2Ffahq6jfy02j01o0mgyg8dfg9khs.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s all. We saw how to authenticate a user by using JWT itself and with combination with cookies using Knock.&lt;/p&gt;




&lt;p&gt;P.S. Some useful articles that helped me to understand this topic&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Flavio Copes - &lt;a href="https://blog.logrocket.com/jwt-authentication-best-practices/" rel="noopener noreferrer"&gt;JWT authentication: When and how to use it&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Jan Brennenstuhl— &lt;a href="https://www.jbspeakr.cc/purpose-jwt-stateless-authentication/" rel="noopener noreferrer"&gt;Stateless JWT authentification&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Sophie DeBenedetto — &lt;a href="https://www.thegreatcodeadventure.com/jwt-storage-in-rails-the-right-way/" rel="noopener noreferrer"&gt;Great short article about adding JWT to Rails&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>jwt</category>
      <category>authorization</category>
    </item>
  </channel>
</rss>
