<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>iridakos</title>
    <description>Lazarus Lazaridis' personal blog with posts mostly related to programming and opensource. And cats.</description>
    <link>https://iridakos.com/</link>
    <image>
      <url>https://iridakos.com/assets/images/site.png</url>
      <link>https://iridakos.com/</link>
      <title>iridakos</title>
    </image>
    <atom:link href="https://iridakos.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 13 May 2020 08:59:17 +0300</pubDate>
    <lastBuildDate>Wed, 13 May 2020 08:59:17 +0300</lastBuildDate>
    <generator>Jekyll v3.8.6</generator>

    

    
      <item>
        <title>stup - Daily notes in the terminal</title>
        <description>&lt;p&gt;Over the past few years I have been participating in &lt;a href=&quot;https://en.wikipedia.org/wiki/Stand-up_meeting&quot;&gt;Stand-up meetings&lt;/a&gt; and it took me some time to find a convenient and effective way for keeping notes about what I was doing every day.&lt;/p&gt;

&lt;p&gt;I needed to be able to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;keep notes on the issues I worked on, the meetings I participated in and stuff that blocked my work&lt;/li&gt;
  &lt;li&gt;easily access these notes based on their date&lt;/li&gt;
  &lt;li&gt;have an overview of what I did for example the last week&lt;/li&gt;
  &lt;li&gt;all of the above from inside a terminal &lt;strong&gt;without&lt;/strong&gt;
    &lt;ul&gt;
      &lt;li&gt;having to manually structure and update a single document&lt;/li&gt;
      &lt;li&gt;having to manually create a document for each day&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;stup&quot;&gt;stup&lt;/h2&gt;

&lt;p&gt;I created &lt;a href=&quot;https://github.com/iridakos/stup&quot;&gt;stup&lt;/a&gt; (the name derives from &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;st&lt;/code&gt;&lt;/strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;and-&lt;/code&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;up&lt;/code&gt;&lt;/strong&gt;), an opensource CLI tool that deals with these issues and allows to easily save, access and organize my notes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://github.com/iridakos/stup/blob/master/assets/stup-0-1-9.gif?raw=true&quot; alt=&quot;stup demo gif&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The source code of the project is available on &lt;a href=&quot;https://github.com/iridakos/stup&quot; target=&quot;_blank&quot;&gt;GitHub here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;usage-examples&quot;&gt;Usage examples&lt;/h3&gt;

&lt;p&gt;Find below some examples showing the most important usage of &lt;code class=&quot;highlighter-rouge&quot;&gt;stup&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;adding-notes&quot;&gt;Adding notes&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Adding a note to the default category at current date&lt;/span&gt;
stup add &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Worked on issue #ABC123&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Adding a note to the default category setting the current date explicitly&lt;/span&gt;
stup add today &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Worked on issue #ABC123&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Adding a note to the meetings category&lt;/span&gt;
stup add today &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;meetings&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2 hours with @phoebe for the project kick off&quot;&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Adding a note to the blocking category for April 10th, 2020&lt;/span&gt;
stup add @ 2020-04-10 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;blocking&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;connectivity issues&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;showing-notes&quot;&gt;Showing notes&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Showing yesterday's notes&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;stup

&lt;span class=&quot;c&quot;&gt;# Showing yesterday's notes explicitly setting the date&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;stup yesterday

&lt;span class=&quot;c&quot;&gt;# Showing today's notes&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;stup today

&lt;span class=&quot;c&quot;&gt;# Showing notes on a specific date&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;stup show @ 2020-04-18

&lt;span class=&quot;c&quot;&gt;# Showing notes on a specific date for the meetings category&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;stup show @ 2020-04-18 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;meetings&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;retrieving-all-notes-for-a-period-of-time&quot;&gt;Retrieving all notes for a period of time&lt;/h4&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# List current week's notes&lt;/span&gt;
stup log week

&lt;span class=&quot;c&quot;&gt;# List previous week's notes&lt;/span&gt;
stup log previous-week

&lt;span class=&quot;c&quot;&gt;# List notes between January 20th, 2020 and March 2nd, 2020&lt;/span&gt;
stup log &lt;span class=&quot;nt&quot;&gt;--from&lt;/span&gt; 2020-01-20 &lt;span class=&quot;nt&quot;&gt;--to&lt;/span&gt; 2020-03-02

&lt;span class=&quot;c&quot;&gt;# List meeting notes between January 20th, 2020 and March 2nd, 2020&lt;/span&gt;
stup log &lt;span class=&quot;nt&quot;&gt;--from&lt;/span&gt; 2020-01-20 &lt;span class=&quot;nt&quot;&gt;--to&lt;/span&gt; 2020-03-02 &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;meetings&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;behind-the-scenes&quot;&gt;Behind the scenes&lt;/h3&gt;

&lt;p&gt;Notes are organized in categories.&lt;/p&gt;

&lt;p&gt;When a new note is added, &lt;code class=&quot;highlighter-rouge&quot;&gt;stup&lt;/code&gt; creates a markdown file and places it under the category’s directory in a sub-directory with a path based on the date.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;CATEGORIES_ROOT_DIRECTORY/CATEGORY/YEAR/MONTH/YYYY-MM-DD.md

&lt;span class=&quot;c&quot;&gt;# For example, the notes of a category named &quot;programming&quot; April 18th, 2020 are saved under&lt;/span&gt;
CATEGORIES_ROOT_DIRECTORY/programming/2020/04/2020-04-18.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This allows users to retrieve any notes added on a specific date or in a specific period for a specific or for all categories.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Fetch notes for all categories&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;stup show @ 2020-04-18

&lt;span class=&quot;c&quot;&gt;# Fetch notes for a specific category for previous week&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;stup log previous-week &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; programming

&lt;span class=&quot;c&quot;&gt;# Fetch notes for all categories for a specific period&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;stup log &lt;span class=&quot;nt&quot;&gt;--from&lt;/span&gt; 2020-04-01 &lt;span class=&quot;nt&quot;&gt;--to&lt;/span&gt; 2020-04-15
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;more-information&quot;&gt;More information&lt;/h3&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;visit the project repository on Github &lt;a href=&quot;https://github.com/iridakos/stup&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;view the full documentation of &lt;code class=&quot;highlighter-rouge&quot;&gt;stup&lt;/code&gt; &lt;a href=&quot;https://github.com/iridakos/stup/blob/master/README.md&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;browse the project’s issues &lt;a href=&quot;https://github.com/iridakos/stup/issues&quot;&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all, thanks for reading! Cat photo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/stup-cli-notes/phoebe.png&quot; alt=&quot;Phoebe, my cat, keeping notes without stup&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 20 Apr 2020 12:00:00 +0300</pubDate>
        <link>https://iridakos.com/programming/2020/04/20/stup-cli-notes</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2020/04/20/stup-cli-notes</guid>
        
        <category>linux</category>
        
        <category>opensource</category>
        
        <category>bash</category>
        
        <category>scripts</category>
        
        <category>productivity</category>
        
        <category>tools</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Find palindrome dates in the Linux command line - explained</title>
        <description>&lt;p&gt;Yesterday I saw a &lt;a href=&quot;https://twitter.com/climagic/status/1225056662949650432&quot;&gt;great command&lt;/a&gt; that finds the palindrome dates between now and &lt;code class=&quot;highlighter-rouge&quot;&gt;x&lt;/code&gt; days ago.&lt;/p&gt;

&lt;p&gt;The command was posted on Twitter by &lt;a href=&quot;https://twitter.com/climagic&quot;&gt;@climagic&lt;/a&gt; (a great account to follow if you want to find awesome command line stuff).&lt;/p&gt;

&lt;p&gt;In this post we are going to break it down and explain how it works.&lt;/p&gt;

&lt;h2 id=&quot;what-is-a-palindrome&quot;&gt;What is a palindrome&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;Palindrome is a word/number/phrase or other sequence of characters that reads the same backward as forward.
&lt;cite&gt;– &lt;a href=&quot;https://en.wikipedia.org/wiki/Palindrome&quot;&gt;Palindrome - Wikipedia&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Few days ago, the date was &lt;strong&gt;02/02/2020&lt;/strong&gt; which was a palindrome:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/palindrome-shell/02022020.png&quot; alt=&quot;Image showing the palindrome 02022020&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-command&quot;&gt;The command&lt;/h2&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;now - %d days&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..332044&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; |date &lt;span class=&quot;nt&quot;&gt;-f-&lt;/span&gt; +%Y%_m%_d&lt;span class=&quot;s1&quot;&gt;$'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;%Y%m%d |tr &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; alldates.txt&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; rev alldates.txt &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;revdates.txt&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;paste &lt;/span&gt;alldates.txt revdates.txt |awk &lt;span class=&quot;s1&quot;&gt;'$1==$2{print $1}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And here’s a more readable version using new lines after each pipe.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;now - %d days&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..332044&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; |
&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f-&lt;/span&gt; +%Y%_m%_d&lt;span class=&quot;s1&quot;&gt;$'&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'&lt;/span&gt;%Y%m%d |
&lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;' '&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; alldates.txt&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; rev alldates.txt &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;revdates.txt&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;paste &lt;/span&gt;alldates.txt revdates.txt |
&lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$1==$2{print $1}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I am going to explain each part of the command separately.&lt;/p&gt;

&lt;p&gt;Note that the output of each part is the input of the next part (following the pipe &lt;code class=&quot;highlighter-rouge&quot;&gt;|&lt;/code&gt;).&lt;/p&gt;

&lt;h2 id=&quot;printf-now---d-daysn-1332044&quot;&gt;printf &quot;now - %d days\n&quot; {1..332044}&lt;/h2&gt;

&lt;p&gt;The first part seems pretty straight forward but it does have an interesting part, the &lt;strong&gt;brace expansion mechanism&lt;/strong&gt;, which I didn’t know of.&lt;/p&gt;

&lt;p&gt;Open a terminal and type the following commands:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# From 1 to 10&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..10&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
1 2 3 4 5 6 7 8 9 10

&lt;span class=&quot;c&quot;&gt;# From a to z&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;a..z&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
a b c d e f g h i j k l m n o p q r s t u v w x y z

&lt;span class=&quot;c&quot;&gt;# From 10 to 20&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo &lt;/span&gt;Before-&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;10..20&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-After&lt;/span&gt;
Before-10-After Before-11-After Before-12-After Before-13-After Before-14-After Before-15-After Before-16-After Before-17-After Before-18-After Before-19-After Before-20-After
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the brace expansion allows the generation of values based on a “sequence” we set.&lt;/p&gt;

&lt;p&gt;Learn more about the &lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html&quot;&gt;Brace expansion mechanism here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;part-explained&quot;&gt;Part explained&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;we print the phrase “now - x days” so many times as the number of values expanded from the sequence&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;{1..332044}&lt;/code&gt; will generate 332044 values starting from 1 and increasing by 1&lt;/li&gt;
  &lt;li&gt;we add a new line at the end of each produced string&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;output&quot;&gt;Output&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;now - 1 days
now - 2 days
now - 3 days
now - 4 days
now - 5 days
...
now - 332038 days
now - 332039 days
now - 332040 days
now - 332041 days
now - 332042 days
now - 332043 days
now - 332044 days
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;date--f--y_m_dnymd&quot;&gt;date -f- &lt;code class=&quot;highlighter-rouge&quot;&gt;+%Y%\_m%\_d$'\n'%Y%m%d&lt;/code&gt;&lt;/h2&gt;

&lt;p&gt;In this part we use the &lt;code class=&quot;highlighter-rouge&quot;&gt;date&lt;/code&gt; command to parse the previously piped output and print two lines for each date, one with padding zeros and one without zeros for single digit days and months.&lt;/p&gt;

&lt;p&gt;Familiarize yourself with the command in your terminal:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Show current date = now&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;date
&lt;/span&gt;Thu Feb  6 07:30:10 EET 2020

&lt;span class=&quot;c&quot;&gt;# Show yesterday&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;now - 1 days&quot;&lt;/span&gt;
Wed Feb  5 07:31:22 EET 2020

&lt;span class=&quot;c&quot;&gt;# Show yesterday as dd/mm/yyyy (zero padding)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;now - 1 days&quot;&lt;/span&gt; +%d/%m/%Y
05/02/2020

&lt;span class=&quot;c&quot;&gt;# Show yesterday as dd/mm/yyyy (space padded)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;now - 1 days&quot;&lt;/span&gt; +%_d/%_m/%Y
 5/ 2/2020

&lt;span class=&quot;c&quot;&gt;# Show yesterday as dd/mm/yyyy (without padding)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;date&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--date&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;now - 1 days&quot;&lt;/span&gt; +%-d/%-m/%Y
5/2/2020
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;part-explained-1&quot;&gt;Part explained&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;we use the &lt;code class=&quot;highlighter-rouge&quot;&gt;-f&lt;/code&gt; option to define the input of the &lt;code class=&quot;highlighter-rouge&quot;&gt;date&lt;/code&gt; to be the lines of a file, followed by a hyphen &lt;code class=&quot;highlighter-rouge&quot;&gt;-&lt;/code&gt; to &lt;a href=&quot;https://unix.stackexchange.com/questions/16357/usage-of-dash-in-place-of-a-filename&quot;&gt;set this file to be the &lt;code class=&quot;highlighter-rouge&quot;&gt;stdin&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;we set the output format (what follows the plus &lt;code class=&quot;highlighter-rouge&quot;&gt;+&lt;/code&gt; symbol) to be the numeric representation of the year (&lt;code class=&quot;highlighter-rouge&quot;&gt;%Y&lt;/code&gt;), the month (padded with spaces: &lt;code class=&quot;highlighter-rouge&quot;&gt;%_m&lt;/code&gt;, padded with zeros: &lt;code class=&quot;highlighter-rouge&quot;&gt;%m&lt;/code&gt;) and the day of the month (padded with spaces: &lt;code class=&quot;highlighter-rouge&quot;&gt;%_d&lt;/code&gt;, padded with zeros: &lt;code class=&quot;highlighter-rouge&quot;&gt;%d&lt;/code&gt;)&lt;/li&gt;
  &lt;li&gt;the space padded format is &lt;code class=&quot;highlighter-rouge&quot;&gt;%Y%\_m%\_d&lt;/code&gt; and the zero padded format is &lt;code class=&quot;highlighter-rouge&quot;&gt;%Y%m%d&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;we combine these &lt;strong&gt;two formats for each date&lt;/strong&gt; and we separate them with a new line &lt;code class=&quot;highlighter-rouge&quot;&gt;$'\n'&lt;/code&gt; thus, for each date we parse, we produce two lines, one padded with zeros and one padded with spaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: instead of padding with spaces (using the underscore &lt;code class=&quot;highlighter-rouge&quot;&gt;_&lt;/code&gt; in the format), we could use the hyphen &lt;code class=&quot;highlighter-rouge&quot;&gt;-&lt;/code&gt; instead which would &lt;strong&gt;skip the padding of the field&lt;/strong&gt;. This way wouldn’t have to remove the spaces as described in the next part.&lt;/p&gt;

&lt;h3 id=&quot;output-1&quot;&gt;Output&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;2020 2 5
20200205
2020 2 4
20200204
2020 2 3
20200203
2020 2 2
20200202
2020 2 1
20200201
2020 131
20200131
2020 130
20200130
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;tr--d----alldatestxt-rev-alldatestxt-revdatestxt-paste-alldatestxt-revdatestxt&quot;&gt;tr -d ' ' &amp;gt; alldates.txt; rev alldates.txt &amp;gt;revdates.txt; paste alldates.txt revdates.txt&lt;/h2&gt;

&lt;p&gt;In this part we remove the spaces produced in the previous step and we create two files, one with all the dates and one with all the dates reversed.&lt;/p&gt;

&lt;p&gt;Then we combine these two files by merging each line of the first file with the corresponding line of the second file separated with a tab.&lt;/p&gt;

&lt;p&gt;Familiarize yourself with the commands of this part in your terminal:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Remove empty spaces&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Good night &quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot; &quot;&lt;/span&gt;
Goodnight

&lt;span class=&quot;c&quot;&gt;# Remove hyphens&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Good-night&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;tr&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;-&quot;&lt;/span&gt;
Goodnight

&lt;span class=&quot;c&quot;&gt;# Print a-x-z where x is a number between 1 and 9&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a-%d-z&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..9&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
a-1-z
a-2-z
a-3-z
a-4-z
a-5-z
a-6-z
a-7-z
a-8-z
a-9-z

&lt;span class=&quot;c&quot;&gt;# and then reverse the order of the characters of each line&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a-%d-z&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1..9&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt; | rev
z-1-a
z-2-a
z-3-a
z-4-a
z-5-a
z-6-a
z-7-a
z-8-a
z-9-a
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;part-explained-2&quot;&gt;Part explained&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;tr -d ''&lt;/code&gt;: we remove the spaces of the input (which is the output of the previous part) and we save the output in a file named &lt;code class=&quot;highlighter-rouge&quot;&gt;alldates.txt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;rev&lt;/code&gt;: we reverse the order of the characters of each line of the &lt;code class=&quot;highlighter-rouge&quot;&gt;alldates.txt&lt;/code&gt; file and we save the output in a new file named &lt;code class=&quot;highlighter-rouge&quot;&gt;revdates.txt&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;paste&lt;/code&gt;: we merge the two files; each line of the &lt;code class=&quot;highlighter-rouge&quot;&gt;alldates.txt&lt;/code&gt; file is merged with the corresponding line of the file &lt;code class=&quot;highlighter-rouge&quot;&gt;revdates.txt&lt;/code&gt; separated by a tab (the two files have the exact number of lines).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;output-2&quot;&gt;Output&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;202025	520202
20200205	50200202
202024	420202
20200204	40200202
202023	320202
20200203	30200202
202022	220202
20200202	20200202
202021	120202
20200201	10200202
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;awk-12print-1&quot;&gt;awk '$1==$2{print $1}'&lt;/h2&gt;

&lt;p&gt;In this final part, we use &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; to print the palindromes.&lt;/p&gt;

&lt;p&gt;Familiarize yourself with the usage of awk related to this post, in your terminal:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Print the whole input (awk's default behavior) if the fields are equal&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a a&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$1==$2'&lt;/span&gt;
a a

&lt;span class=&quot;c&quot;&gt;# Print the whole input (awk's default behavior) if the fields are not equal&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a a&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$1!=$2'&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# nothing here&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Print the whole input (awk's default behavior) if the fields are not equal&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a b&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$1!=$2'&lt;/span&gt;
a b

&lt;span class=&quot;c&quot;&gt;# Print the first field if the fields are not equal&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a b&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$1!=$2 {print $1}'&lt;/span&gt;
a

&lt;span class=&quot;c&quot;&gt;# Print the second field if the fields are not equal&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;a b&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'$1!=$2 {print $2}'&lt;/span&gt;
b
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;part-explained-3&quot;&gt;Part explained&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;the previous output that is now the input of this part consists of lines and each line has two values separated by a TAB. With this kind of input, &lt;a href=&quot;https://www.gnu.org/software/gawk/manual/html_node/Fields.html&quot;&gt;awk resolves two fields&lt;/a&gt; in each line. We can access these two fields using the &lt;code class=&quot;highlighter-rouge&quot;&gt;$1&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;$2&lt;/code&gt; variables.&lt;/li&gt;
  &lt;li&gt;as described in a &lt;a href=&quot;https://iridakos.com/programming/2019/05/16/remove-duplicate-lines-preserving-order-linux#how-it-works&quot;&gt;previous post&lt;/a&gt;, awk statements consist of a pattern-expression and an associated action.
    &lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;lt;pattern/expression&amp;gt; { &amp;lt;action&amp;gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;If the pattern succeeds then the associated action is being executed. In this part the expression is translated as “if the two fields are equal” (&lt;code class=&quot;highlighter-rouge&quot;&gt;$1==$2&lt;/code&gt;) and the action as “print the first field” (&lt;code class=&quot;highlighter-rouge&quot;&gt;printf $1&lt;/code&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;if the fields are equal we do have a palindrome since each pair of fields is actually a date and its reversed value.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;output-3&quot;&gt;Output&lt;/h3&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;20200202
2019102
2018102
2017102
2016102
2015102
2014102
2013102
2012102
...
11111111
11111111
1111111
1111111
111111
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;cat-photo&quot;&gt;Cat photo&lt;/h2&gt;

&lt;p&gt;That’s all, thanks for reading.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/palindrome-shell/post.jpg&quot; alt=&quot;Image with image reflection of my cat, Irida&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/climagic/status/1225056662949650432&quot;&gt;@climagic tweet this post is based on&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Palindrome&quot;&gt;Palindrome - Wikipedia&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/html_node/Brace-Expansion.html&quot;&gt;Bash brace expansion&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://unix.stackexchange.com/questions/16357/usage-of-dash-in-place-of-a-filename&quot;&gt;Using hyphen to set file input to stdin&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/gawk/manual/html_node/Fields.html&quot;&gt;Awk field resolution&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://iridakos.com/programming/2019/05/16/remove-duplicate-lines-preserving-order-linux#how-it-works&quot;&gt;Awkward awk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
        <pubDate>Thu, 06 Feb 2020 12:00:00 +0200</pubDate>
        <link>https://iridakos.com/programming/2020/02/06/shell-palindrome-dates</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2020/02/06/shell-palindrome-dates</guid>
        
        <category>how-to</category>
        
        <category>linux</category>
        
        <category>opensource</category>
        
        <category>bash</category>
        
        <category>scripts</category>
        
        <category>awk</category>
        
        <category>climagic</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Goodbye Irida</title>
        <description>&lt;p&gt;On Monday I had to put my beloved cat, Irida, to sleep.&lt;/p&gt;

&lt;h2 id=&quot;who-is-irida&quot;&gt;Who is Irida&lt;/h2&gt;

&lt;div class=&quot;row align-items-center&quot;&gt;
  &lt;div class=&quot;col-12 col-md-8&quot;&gt;
    &lt;p&gt;
      Twelve years ago, I wanted to get a pet. My friends helped me find one via a post about a stray young cat which was found under a truck in my area. After two days the cat was in my house and that's how one my most beloved beings came into my life.
    &lt;/p&gt;

    &lt;p&gt;
      I was thinking of names and I ended up naming her &quot;Irida&quot; (which is a variation of &lt;a href=&quot;https://en.wikipedia.org/wiki/Iris_(anatomy)&quot;&gt;Iris&lt;/a&gt;) after a server in my university. It worked well for me that everybody thought the name was given due to her &lt;a href=&quot;https://www.boredpanda.com/my-cat-is-incapable-of-looking-calm/&quot;&gt;special look&lt;/a&gt;.
    &lt;/p&gt;

    &lt;p&gt;
      This blog is named after her.
    &lt;/p&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-4&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/01.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;living-with-irida&quot;&gt;Living with Irida&lt;/h2&gt;

&lt;div class=&quot;row align-items-center&quot;&gt;
  &lt;div class=&quot;col-12 col-md-4&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/02.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-8&quot;&gt;
    &lt;p&gt;
      If you are a cat owner you must already know that you are the only person that really knows and understands his/her behavior. Cats are not as expressive as dogs are, but sooner or later we do feel their love and we can understand their mood and their needs.
    &lt;/p&gt;

    &lt;p&gt;
      In my case, living with Irida was as if I had another person in the house. We had conversations that always ended when her look was telling me &quot;You do know I can't speak, you're speaking alone&quot;.
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;row align-items-center&quot;&gt;
  &lt;div class=&quot;col-12 col-md-8&quot;&gt;
    &lt;p&gt;
      As the years were passing by, our relationship was changing and even more feelings were being expressed from both parts.
    &lt;/p&gt;

    &lt;p&gt;
      Every single post of this blog has been written with this thing on the side.
    &lt;/p&gt;

    &lt;p&gt;
      Whenever I was in the house, Irida was next to me. She was following me everywhere I was going.
    &lt;/p&gt;

    &lt;p&gt;
      After the first two or three years she started &quot;requesting&quot; my arm to sleep on it during the night.
    &lt;/p&gt;

    &lt;p&gt;
      In the winter, she was scratching the blankets to force me elevate my hand and create some kind of a nest for her to lay down.
    &lt;/p&gt;

    &lt;p&gt;
      So many more things to say in this section. View photos instead.
    &lt;/p&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-4&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/03.jpg&quot; alt=&quot;&quot; style=&quot;height: auto;&quot; /&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr class=&quot;my-4&quot; /&gt;

&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-00.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;
    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Hello.
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-01.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Very interesting.
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-02.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      I fits.
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-03.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Tddthhh
    &lt;/small&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-04.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;
    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Bye sweater
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-05.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Can't find Minerva
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-06.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Shopping
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-07.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Laundry
    &lt;/small&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-08.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;
    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Who's there
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-09.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Elastic
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-10.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Where's Phoebe
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-11.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Ehm
    &lt;/small&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;row&quot;&gt;
  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-12.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;
    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Kiss
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-13.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      I don't like reggae
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/programming-cat/movie-night.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      Watching a thriller
    &lt;/small&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-3 text-center mb-3&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/p-15.jpg&quot; alt=&quot;&quot; class=&quot;img-fluid grid-img&quot; /&gt;

    &lt;small class=&quot;text-small text-muted&quot;&gt;
      &amp;lt;3
    &lt;/small&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;hr class=&quot;my-4&quot; /&gt;

&lt;h2 id=&quot;the-sickness&quot;&gt;The sickness&lt;/h2&gt;

&lt;div class=&quot;row align-items-center&quot;&gt;
  &lt;div class=&quot;col-12 col-md-4&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/04.jpg&quot; alt=&quot;&quot; style=&quot;height: auto;&quot; /&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-8&quot;&gt;
    &lt;p&gt;
      In September, while I was petting her, I noticed something like a pimple outside her mouth. After a very stressful process of tests instructed by our vet, she was diagnosed with &lt;a href=&quot;https://vetspecialists.com/oral-squamous-cell-carcinoma-in-the-cat/&quot;&gt;Squamous cell Carcinoma&lt;/a&gt; on her jaw.
    &lt;/p&gt;

    &lt;p&gt;
      The cancer was really aggressive and we had to act fast. The doctors said that we can remove the bottom right part of the jaw which was the part that the tumor was located at. It was very hard to take a decision when you couldn't know how things would turn up. Would she be able to use her mouth afterwards? How much time would she gain? Would she be suffering after such a surgery?
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;row align-items-center&quot;&gt;
  &lt;div class=&quot;col-12 col-md-8&quot;&gt;
    &lt;p&gt;
      We decided to have the surgery. And everything went fine.
    &lt;/p&gt;

    &lt;p&gt;
      The first days she couldn't eat on her own and we used a tube in order to feed her.
    &lt;/p&gt;

    &lt;p&gt;
      I feared that this might be it, she might not be able to use her mouth.
    &lt;/p&gt;

    &lt;p&gt;
      After 3 days she started eating on her own. And not only canned food which was soft. She started eating her dry food as if nothing had happened. The surgery went fine, the doctors did a really good job.
    &lt;/p&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-4&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/05.png&quot; alt=&quot;&quot; style=&quot;height: auto;&quot; /&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;row align-items-center&quot;&gt;
  &lt;div class=&quot;col-12 col-md-4&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/06.png&quot; alt=&quot;&quot; style=&quot;height: auto;&quot; /&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-8&quot;&gt;
    &lt;p&gt;
      Everything was fine until recently. Irida was happy, she was playing with her toys, purring and doing her usual crazy moves when she was bored.
    &lt;/p&gt;

    &lt;p&gt;
      During Christmas though, she started keeping her mouth open. The scheduled tests (including scans) didn't show anything in her lungs or somewhere else. The doctors couldn't see anything developing in her mouth either. I was hoping that something else was the cause of this, like the feline asthma or the exposure to the heat of the radiators.
    &lt;/p&gt;

    &lt;p&gt;
      Few weeks ago though, she started having difficulties after eating: she was choking and she was heavily breathing. The doctors used general anesthesia and checked her larynx and that's where the problem was. There was a metastasis in her base of her tongue. The tumor was not huge but big enough to cause big discomfort.
    &lt;/p&gt;

    &lt;p&gt;
      Even if a surgery was doable, everyone was not convinced that it should be done. I didn't want her to suffer again with such a bad prognosis. When the moment came that even canned food diluted with water was hard to be consumed, putting her to sleep was what should be done.
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;h2 id=&quot;what-now&quot;&gt;What now&lt;/h2&gt;

&lt;div class=&quot;row align-items-center&quot;&gt;
  &lt;div class=&quot;col-12 col-md-8&quot;&gt;
    &lt;p&gt;
      I cried a lot, I am in pain but as the days pass by I'm feeling a bitter sweet better. We had some really good moments till the last days. The loss would hurt me the same if not more if she died in a few years from now. I feel better thinking that she didn't die too young or in pain.
    &lt;/p&gt;

    &lt;p&gt;
       When she was two, I got another cat, Phoebe, thinking that they both would make a good company the hours that I was away from home. This never happened, Irida was the boss and Phoebe was always afraid of her. But, in hard times (ex. when the vacuum cleaner is on or when about to visit the vet) they were hiding, one next to the other as if they were hugging, under the bed.
    &lt;/p&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-4&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/07.jpg&quot; alt=&quot;&quot; style=&quot;height: auto;&quot; /&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;row align-items-center&quot;&gt;
  &lt;div class=&quot;col-12 col-md-4&quot;&gt;
    &lt;img src=&quot;/assets/images/posts/goodbye-irida/08.jpg&quot; alt=&quot;&quot; style=&quot;height: auto;&quot; /&gt;
  &lt;/div&gt;

  &lt;div class=&quot;col-12 col-md-8&quot;&gt;
    &lt;p&gt;
      Phoebe is now the cat of the house, enjoying a full time care. She is a totally different character, more independent but very cute.
    &lt;/p&gt;

    &lt;p&gt;
      When I feel ready again, I will get another cat so that Phoebe can hug her under the bed.
    &lt;/p&gt;
  &lt;/div&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 23 Jan 2020 09:00:00 +0200</pubDate>
        <link>https://iridakos.com/cats/2020/01/23/goodbye-irida</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2020/01/23/goodbye-irida</guid>
        
        <category>cat</category>
        
        <category>cats</category>
        
        <category>Irida</category>
        
        
        <category>cats</category>
        
      </item>
    
      <item>
        <title>Vim</title>
        <description>&lt;pre&gt;
Roses are red
Violets are blue
I have stuck in &lt;span class=&quot;font-weight-bold&quot;&gt;vim&lt;/span&gt;
And so have you.

Vim ain't for newbies
But I'm a curious soul
So I went down
That shell rabbit hole.

I tried to edit &lt;code class=&quot;font-weight-bold&quot;&gt;hosts&lt;/code&gt;
Everything went wrong
The file remained open
For two hours long.

When I found the magic
&lt;span class=&quot;font-weight-bold&quot;&gt;Semicolon double-u q&lt;/span&gt;
The file was readonly
You've been there too.

The bells started ringing
As I &lt;span class=&quot;font-weight-bold&quot;&gt;control&lt;/span&gt;led&lt;span class=&quot;font-weight-bold&quot;&gt; + c&lt;/span&gt;
What was I thinking
I WANT TO BE FREE

I had to stop the panic
Said it'll all be fine
I will just kill the process
Using &lt;strong&gt;minus nine&lt;/strong&gt;.
&lt;div class=&quot;text-right text-muted font-italic&quot;&gt;&lt;small&gt;-- iridakos&lt;/small&gt;&lt;/div&gt;
&lt;/pre&gt;
</description>
        <pubDate>Fri, 20 Dec 2019 09:00:00 +0200</pubDate>
        <link>https://iridakos.com/programming/2019/12/20/thy-vim</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/12/20/thy-vim</guid>
        
        <category>humor</category>
        
        <category>devhumor</category>
        
        <category>poem</category>
        
        <category>linux</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Descriptive variable names</title>
        <description>&lt;p&gt;&lt;strong&gt;[others]:&lt;/strong&gt; Variable names must be descriptive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;[me]:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;help-help-help&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;#F1F1F1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Thu, 12 Dec 2019 09:00:00 +0200</pubDate>
        <link>https://iridakos.com/programming/2019/12/12/descriptive-variable-names</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/12/12/descriptive-variable-names</guid>
        
        <category>humor</category>
        
        <category>devhumor</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Movie night</title>
        <description>
</description>
        <pubDate>Fri, 06 Dec 2019 09:00:00 +0200</pubDate>
        <link>https://iridakos.com/cats/2019/12/06/movie-night</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2019/12/06/movie-night</guid>
        
        <category>photo</category>
        
        <category>cat</category>
        
        <category>cats</category>
        
        <category>movie</category>
        
        
        <category>cats</category>
        
      </item>
    
      <item>
        <title>Pizza commit</title>
        <description>&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Closes issue #13&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; Remove obsolete reference to core entity
  &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; Refactor module generating values
  &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; Log every ac...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Colleague:&lt;/strong&gt; “Hey, the pizza is heeeere”&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Me:&lt;/strong&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; backspaces &lt;span class=&quot;k&quot;&gt;*&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;git commit &lt;span class=&quot;nt&quot;&gt;-m&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Fixes&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
</description>
        <pubDate>Wed, 04 Dec 2019 11:00:00 +0200</pubDate>
        <link>https://iridakos.com/programming/2019/12/04/pizza-commit</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/12/04/pizza-commit</guid>
        
        <category>humor</category>
        
        <category>devhumor</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>What do you get after you lose your data from an SSD?</title>
        <description>&lt;h1 id=&quot;ptssd&quot;&gt;PTSSD&lt;/h1&gt;
</description>
        <pubDate>Wed, 04 Dec 2019 09:00:00 +0200</pubDate>
        <link>https://iridakos.com/programming/2019/12/04/ptssd</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/12/04/ptssd</guid>
        
        <category>humor</category>
        
        <category>devhumor</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>I am talking to my code</title>
        <description>&lt;p&gt;I am talking to my code but according to my cat, this is the least worrying.&lt;/p&gt;
</description>
        <pubDate>Tue, 03 Dec 2019 21:00:00 +0200</pubDate>
        <link>https://iridakos.com/programming/2019/12/03/talking-to-my-code</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/12/03/talking-to-my-code</guid>
        
        <category>humor</category>
        
        <category>devhumor</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>i</title>
        <description>&lt;pre&gt;
Roses are red
Violets are blue
I was looping forever
And then I found you.

&lt;span class=&quot;text-danger font-weight-bold&quot;&gt;i&lt;/span&gt; was your name
I think &lt;span class=&quot;text-danger font-weight-bold&quot;&gt;j&lt;/span&gt; was next to you
Born inside a &lt;span class=&quot;text-danger font-weight-bold&quot;&gt;for&lt;/span&gt;
Died in there too.

I saw you getting bigger
Loop over loop over loop
And &lt;span class=&quot;text-danger font-weight-bold&quot;&gt;j&lt;/span&gt; was getting smaller
You were a great group.

And then you just vanished
You left me there alone
Condition wasn't true
At least nothing was thrown.
&lt;/pre&gt;
</description>
        <pubDate>Fri, 22 Nov 2019 17:00:00 +0200</pubDate>
        <link>https://iridakos.com/programming/2019/11/22/i</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/11/22/i</guid>
        
        <category>humor</category>
        
        <category>devhumor</category>
        
        <category>poem</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Mongoid - Inheritance: change embedded document's type via nested attributes</title>
        <description>&lt;p&gt;I recently faced some issues when trying to update a &lt;strong&gt;nested document’s type&lt;/strong&gt; via &lt;a href=&quot;https://docs.mongodb.com/mongoid/current/tutorials/mongoid-nested-attributes/&quot;&gt;nested attributes&lt;/a&gt; using the &lt;a href=&quot;https://github.com/mongodb/mongoid&quot;&gt;&lt;strong&gt;mongoid&lt;/strong&gt;&lt;/a&gt; gem. Bare with me if this sentence doesn’t make any sense yet.&lt;/p&gt;

&lt;h2 id=&quot;use-case&quot;&gt;Use case&lt;/h2&gt;

&lt;p&gt;Suppose we have a document named &lt;code class=&quot;highlighter-rouge&quot;&gt;Person&lt;/code&gt; that embeds a document that can be any of the types &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt; which inherit from the class &lt;code class=&quot;highlighter-rouge&quot;&gt;Item&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;item&quot;&gt;Item&lt;/h3&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Item&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Mongoid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Document&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;embedded_in&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;inverse_of: :item&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;book&quot;&gt;Book&lt;/h3&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Book&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Item&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:authors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;boardgame&quot;&gt;BoardGame&lt;/h3&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BoardGame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Item&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:players&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Integer&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;person&quot;&gt;Person&lt;/h3&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Person&lt;/span&gt;
  &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Mongoid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Document&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;embeds_one&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;inverse_of: :person&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;accepts_nested_attributes_for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;allow_destroy: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;the-problems&quot;&gt;The problems&lt;/h2&gt;

&lt;p&gt;To simplify the post I won’t go with the scenario of building the forms and the controller actions to demonstrate the problems but instead I will simulate the behavior in the &lt;code class=&quot;highlighter-rouge&quot;&gt;rails console&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let’s create a &lt;code class=&quot;highlighter-rouge&quot;&gt;Person&lt;/code&gt; with a &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; as an &lt;code class=&quot;highlighter-rouge&quot;&gt;Item&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;item_attributes: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;_type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Book&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Jitterbug Perfume&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;authors: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Tom Robbins&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Person _id: 5dd7b01ec2889856ab8a619f, &amp;gt;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;item&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Book _id: 5dd7ae76c2889856ab8a619e, name: &quot;Jitterbug Perfume&quot;, _type: &quot;Book&quot;, authors: [&quot;Tom Robbins&quot;]&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;failing-attribute-assignments&quot;&gt;Failing attribute assignments&lt;/h3&gt;

&lt;p&gt;Let’s try to change the person’s item from &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt; with 5 players.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;item_attributes: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;_type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;BoardGame&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Ticket to Ride&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;players: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Traceback&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;most&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;recent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;
        &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;irb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;
&lt;span class=&quot;no&quot;&gt;Mongoid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;UnknownAttribute&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;message:
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Attempted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'players'&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;which&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;allowed&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nf&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Without&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;including&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Mongoid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Dynamic&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;your&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;model&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attribute&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;does&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;already&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exist&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attempting&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Book&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#players= for it is not allowed. This is also triggered by passing the attribute to any method that accepts an attributes hash, and is raised instead of getting a NoMethodError.&lt;/span&gt;
&lt;span class=&quot;ss&quot;&gt;resolution:
  &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;You&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;can&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;include&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Mongoid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Dynamic&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;you&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;be&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;writing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;values&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;undefined&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fields&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;often&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This didn’t work, the assignment of the nested attributes &lt;code class=&quot;highlighter-rouge&quot;&gt;item_attributes&lt;/code&gt; as you can see from the error message &lt;strong&gt;were applied in the model &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The fact that we changed the &lt;code class=&quot;highlighter-rouge&quot;&gt;_type&lt;/code&gt; attribute of the document doesn’t mean that the object in memory also was magically transformed from a &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; to a &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;document-attribute-leftovers&quot;&gt;Document attribute leftovers&lt;/h3&gt;

&lt;p&gt;Let’s try to change the person’s item from &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt; but this time without the players to see if this fixes the issue.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;item_attributes: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;_type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;BoardGame&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Ticket to Ride&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;item&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;Book _id: 5dd7b270c2889858a08a619e, name: &quot;Ticket to Ride&quot;, _type: &quot;BoardGame&quot;, authors: [&quot;Tom Robbins&quot;]&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This seems to have worked even though the result of the &lt;code class=&quot;highlighter-rouge&quot;&gt;person.item&lt;/code&gt; accessor gave a &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; document with &lt;code class=&quot;highlighter-rouge&quot;&gt;_type&lt;/code&gt; of a &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt; and with an attribute &lt;code class=&quot;highlighter-rouge&quot;&gt;authors&lt;/code&gt; present.&lt;/p&gt;

&lt;p&gt;Let’s reload to see if the document is going to be properly instantiated.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reload&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;item&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#&amp;lt;BoardGame _id: 5dd7b270c2889858a08a619e, name: &quot;Ticket to Ride&quot;, _type: &quot;BoardGame&quot;, players: nil&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Seems to be fine but what is going on with the actual document attributes?&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attributes&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;_id&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;BSON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ObjectId&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'5dd7b270c2889858a08a619e'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_type&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;BoardGame&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Ticket to Ride&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;authors&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Tom Robbins&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the &lt;code class=&quot;highlighter-rouge&quot;&gt;authors&lt;/code&gt; attribute (that we had initially set) hasn’t been removed when we changed the type of the &lt;code class=&quot;highlighter-rouge&quot;&gt;Item&lt;/code&gt; from &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;wrong-validators&quot;&gt;Wrong validators&lt;/h3&gt;

&lt;p&gt;Let’s change the &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt; document so that it validates the presence of &lt;code class=&quot;highlighter-rouge&quot;&gt;players&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BoardGame&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Item&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:players&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;type: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Integer&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;validates&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:players&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;presence: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Our &lt;code class=&quot;highlighter-rouge&quot;&gt;person&lt;/code&gt; now has an item of type &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt;. We will now try to change it to a &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;attributes&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;ss&quot;&gt;item_attributes: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;_type: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Book&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;name: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Jitterbug Perfume&quot;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;  
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:item_attributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:_type&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Book&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Jitterbug Perfume&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;valid?&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;full_messages&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Item is invalid&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;full_messages&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Players can't be blank&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;As described in the previous section, the fact that the &lt;code class=&quot;highlighter-rouge&quot;&gt;_type&lt;/code&gt; attribute changed doesn’t mean that the actual object in memory changed accordingly. Upon save of the parent document, the &lt;code class=&quot;highlighter-rouge&quot;&gt;item&lt;/code&gt; is still an instance of the previous &lt;code class=&quot;highlighter-rouge&quot;&gt;_type&lt;/code&gt; which was &lt;code class=&quot;highlighter-rouge&quot;&gt;BoadGame&lt;/code&gt; thus the validations that take place are not the ones defined in the new &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; class but those defined in the &lt;code class=&quot;highlighter-rouge&quot;&gt;BoardGame&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This also means that if we had validations in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Book&lt;/code&gt; class too, they wouldn’t execute in this scenario as well.&lt;/p&gt;

&lt;h2 id=&quot;investigation&quot;&gt;Investigation&lt;/h2&gt;

&lt;p&gt;I tried to google the issue (&lt;a href=&quot;https://twitter.com/lazaru_s/status/1197506095704612864&quot;&gt;I couldn’t even construct a proper query&lt;/a&gt;) to see how others dealt with this but I didn’t find anything helpful and I decided to dive in the source of &lt;a href=&quot;https://github.com/mongodb/mongoid&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;mongoid&lt;/code&gt;&lt;/a&gt; in order to locate the code that deals with the nested assignments and possibly create a &lt;code class=&quot;highlighter-rouge&quot;&gt;monkey patch&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First, I &lt;a href=&quot;https://github.com/mongodb/mongoid/search?q=%22def+accepts_nested_attributes_for%22&amp;amp;unscoped_q=%22def+accepts_nested_attributes_for%22&quot;&gt;searched for the file that defines the &lt;code class=&quot;highlighter-rouge&quot;&gt;accepts_nested_attributes_for&lt;/code&gt; method that we used in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Person&lt;/code&gt; class&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Found in &lt;a href=&quot;https://github.com/mongodb/mongoid/blob/v7.0.5/lib/mongoid/attributes/nested.rb&quot;&gt;mongoid/attributes/nested.rb&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;accepts_nested_attributes_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extract_options!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dup&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:autosave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:autosave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:reject_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;REJECT_ALL_BLANK_PROC&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:reject_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:all_blank&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;meth&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_attributes=&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nested_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_attributes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;meth&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;association&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relations&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Errors&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;NestedAttributesMetadataNotFound&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;unless&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;autosave_nested_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:autosave&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;n&quot;&gt;re_define_method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;meth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;_assigning&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;polymorphic?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inverse_type&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:class_name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inverse_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nested_builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The line that is mostly related to our issue from the above snippet is this:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nested_builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attrs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which is executed upon attribute assignment.&lt;/p&gt;

&lt;p&gt;Since the &lt;code class=&quot;highlighter-rouge&quot;&gt;item&lt;/code&gt; association defined in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Person&lt;/code&gt; document is of type &lt;code class=&quot;highlighter-rouge&quot;&gt;embeds_one&lt;/code&gt;, I located its code to find the &lt;code class=&quot;highlighter-rouge&quot;&gt;nested_builder&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Found it at &lt;a href=&quot;https://github.com/mongodb/mongoid/blob/2ad44f5ef464e8a291be3accc54b884560b9da48/lib/mongoid/association/embedded/embeds_one.rb#L138&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;mongoid/association/embedded/embeds_one.rb&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;nested_builder&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;no&quot;&gt;Nested&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;One&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Ok, now we have to see what is going on inside the &lt;code class=&quot;highlighter-rouge&quot;&gt;#build&lt;/code&gt; method of the &lt;a href=&quot;https://github.com/mongodb/mongoid/blob/master/lib/mongoid/association/nested/one.rb#L28&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;mongoid/association/nested/one.rb&lt;/code&gt;&lt;/a&gt; file.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reject?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@existing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete_id&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assign_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replace?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Factory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@class_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delete?&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;replace?&lt;/span&gt;
  &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyable?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;blank?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update?&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyable?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acceptable_id?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The part that is related to the behavior we want to alter is the one inside the &lt;code class=&quot;highlighter-rouge&quot;&gt;if update? .. elsif replace?&lt;/code&gt; block:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update?&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete_id&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assign_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replace?&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Factory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@class_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is where the attribute assignment in the existing embedded document takes place.&lt;/p&gt;

&lt;h2 id=&quot;desired-behavior&quot;&gt;Desired behavior&lt;/h2&gt;

&lt;p&gt;Since we are talking about embedded documents, when changing the type &lt;strong&gt;instead of updating the existing document’s attributes&lt;/strong&gt; we can easily &lt;strong&gt;replace it at once with a new instance of the proper class&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;From that point on, we won’t have to deal with&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;the invalid attribute assignments&lt;/li&gt;
  &lt;li&gt;removing the old attributes that are not present in the new document type&lt;/li&gt;
  &lt;li&gt;fixing the usage of wrong validators.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The replaced object will be properly instantiated and assigned to the parent.&lt;/p&gt;

&lt;h2 id=&quot;solution&quot;&gt;Solution&lt;/h2&gt;

&lt;p&gt;To change to the desired aforementioned behavior, I patched the &lt;code class=&quot;highlighter-rouge&quot;&gt;Mongoid::Association::Nested::One&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;I created a module (&lt;a href=&quot;https://www.justinweiss.com/articles/3-ways-to-monkey-patch-without-making-a-mess/&quot;&gt;I suggest you read this great article about monkey patching without making a mess&lt;/a&gt;) under &lt;code class=&quot;highlighter-rouge&quot;&gt;lib/core_extensions/mongoid/association/nested/one/embedded_one_change_type.rb&lt;/code&gt; with the following contents:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;CoreExtensions&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Mongoid&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Association&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Nested&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;One&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;EmbeddedOneChangeType&lt;/span&gt;
            &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:changing_type&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reject?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

              &lt;span class=&quot;vi&quot;&gt;@existing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;c1&quot;&gt;# Retrieve the new class&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;new_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;constantize&lt;/span&gt;
              &lt;span class=&quot;c1&quot;&gt;# Resolve whether we should be changing type or not&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@changing_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@existing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;embedded?&lt;/span&gt;

              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;update?&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete_id&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assign_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;replace?&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Mongoid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Factory&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@class_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;delete?&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;parent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;setter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;replace?&lt;/span&gt;
              &lt;span class=&quot;c1&quot;&gt;# Replace if the association hasn't been set or if we are changing type.&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;changing_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyable?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;blank?&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

            &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update?&lt;/span&gt;
              &lt;span class=&quot;c1&quot;&gt;# Don't update the document if we are changing type&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;changing_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyable?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acceptable_id?&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and inside an initializer I patched the proper &lt;code class=&quot;highlighter-rouge&quot;&gt;mongoid&lt;/code&gt; class with:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;Mongoid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Association&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Nested&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;One&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;prepend&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CoreExtensions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Mongoid&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Association&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Nested&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;One&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;EmbeddedOneChangeType&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;explanation&quot;&gt;Explanation&lt;/h3&gt;

&lt;p&gt;We override the build method in order to additionally resolve if we are changing type in an embedded association or not:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;vi&quot;&gt;@changing_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@existing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;association&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;embedded?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We are changing type if:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;there’s a &lt;code class=&quot;highlighter-rouge&quot;&gt;_type&lt;/code&gt; attribute present and&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;highlighter-rouge&quot;&gt;_type&lt;/code&gt;’s value is different than the existing object’s one and&lt;/li&gt;
  &lt;li&gt;the association is embedded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then we alter the methods that decide whether a document should be updated or replaced, so that they take in consideration if we are &lt;code class=&quot;highlighter-rouge&quot;&gt;@changing_type&lt;/code&gt; (as calculated above) or not:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update?&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Don't update the document if we are changing type&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;changing_type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyable?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;acceptable_id?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;replace?&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Replace if the association hasn't been set or if we are changing type.&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;existing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;changing_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;destroyable?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;blank?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;div class=&quot;alert alert-warning&quot;&gt;
  &lt;div class=&quot;alert-heading&quot;&gt;&lt;i class=&quot;fa fa-comments&quot;&gt;&lt;/i&gt; Feedback and comments&lt;/div&gt;

  &lt;p&gt;
    I am not very fond of monkey patching but this was my quick workaround. If you believe that the desired behavior as described here (for the `embedded_one` associations) is invalid or if you deal with this problem in any other way, I'd be glad to here about it.
  &lt;/p&gt;

  &lt;p&gt;
    For suggestions, feedback, comments, typos etc. please use &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/iridakos-posts/issues/5&quot;&gt;this issue&lt;/a&gt; on GitHub.
  &lt;/p&gt;

  &lt;hr /&gt;

  &lt;strong&gt;Thanks for visiting!&lt;/strong&gt;
&lt;/div&gt;

&lt;p&gt;Almost forgot, cat photo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/mongoid-nested-embedded/cat.jpg&quot; alt=&quot;Cat&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 22 Nov 2019 09:00:00 +0200</pubDate>
        <link>https://iridakos.com/programming/2019/11/22/mongoid-nested-attributes-embedded-type</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/11/22/mongoid-nested-attributes-embedded-type</guid>
        
        <category>ruby</category>
        
        <category>rails</category>
        
        <category>how-to</category>
        
        <category>mongoid</category>
        
        <category>mongodb</category>
        
        <category>tutorial</category>
        
        <category>opensource</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Two step authentication in Ubuntu</title>
        <description>&lt;p&gt;There are two cat beds, many chairs, a sofa but no. She will sit there.&lt;/p&gt;

&lt;p&gt;That’s how I have two step authentication for my Ubuntu.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/two-step-authentication/post.png&quot; alt=&quot;Two step authentication&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Mon, 04 Nov 2019 09:00:00 +0200</pubDate>
        <link>https://iridakos.com/cats/2019/11/04/two-step-authentication</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2019/11/04/two-step-authentication</guid>
        
        <category>photo</category>
        
        <category>cat</category>
        
        <category>cats</category>
        
        <category>two step authentication</category>
        
        <category>humor</category>
        
        <category>ubuntu</category>
        
        
        <category>cats</category>
        
      </item>
    
      <item>
        <title>Hug the cat</title>
        <description>&lt;p&gt;This cat has been in my life for 12 years now.&lt;/p&gt;

&lt;p&gt;Whenever I get back home and sit on the sofa, she jumps on my chest and starts licking my nose and my eyebrows.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/hanging-out/post.jpg&quot; alt=&quot;Hugging Irida&quot; /&gt;&lt;/p&gt;

&lt;p&gt;She stays there until the moment she realizes I could be feeding her instead of relaxing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/hanging-out/where-s-the-food.png&quot; alt=&quot;Where's the food&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Fri, 01 Nov 2019 10:00:00 +0200</pubDate>
        <link>https://iridakos.com/cats/2019/11/01/hug-the-cat</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2019/11/01/hug-the-cat</guid>
        
        <category>photo</category>
        
        <category>cat</category>
        
        <category>irida</category>
        
        <category>hanging-out</category>
        
        
        <category>cats</category>
        
      </item>
    
      <item>
        <title>Mountains</title>
        <description>&lt;p&gt;After painting the &lt;a href=&quot;/painting/2019/10/11/meadow&quot;&gt;meadow with acrylic colors&lt;/a&gt;, I bought oil colors which are the ones Bob Ross uses in “The joy of painting” show.
This time I followed the &lt;a href=&quot;https://www.youtube.com/watch?v=kasGRkfkiPM&quot;&gt;episode 10&lt;/a&gt; from season 13 of the show, called &lt;strong&gt;“Mountain Summit”&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I am very satisfied by the outcome but being a beginner, I faced a lot of difficulties and the painting has a number of errors.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/paintings/mountains/painting.jpg&quot; alt=&quot;Mountains - Painting&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;facts&quot;&gt;Facts&lt;/h2&gt;

&lt;p&gt;I used&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the wet-on-wet technique&lt;/li&gt;
  &lt;li&gt;oil colors&lt;/li&gt;
  &lt;li&gt;50x80 canvas&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;difficulties&quot;&gt;Difficulties&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;My paintbrushes were not the same as Bob Ross’ ones (size and material) and the paint didn’t apply the way I wanted (I will search for tips and tricks when it comes to buying paintbrushes for oil colors)&lt;/li&gt;
  &lt;li&gt;I couldn’t find all the colors listed in the episode and I had to mix mine many times to achieve something similar&lt;/li&gt;
  &lt;li&gt;I had such a huge difficulty creating the bushes. I am still not sure what the exact problem was but I believe it is a combination of the following three items:
    &lt;ul&gt;
      &lt;li&gt;wrong paintbrush&lt;/li&gt;
      &lt;li&gt;very thick paint (according to Bob Ross, thin paint sticks on thick)&lt;/li&gt;
      &lt;li&gt;wrong moves by me (maybe more/less pressure on the paintbrush)&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;The mountains, even though they look nice, were so hard to be created with the palette knife. It surely has to do with practice.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;errors&quot;&gt;Errors&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;The tallest mountain has an unnatural curve on its bottom side which doesn’t make sense&lt;/li&gt;
  &lt;li&gt;The left side of the mountains ends somewhere behind the trees without a logical explanation (in the episode the trees cover all the left part of the painting)&lt;/li&gt;
  &lt;li&gt;The path in the front right section of the painting is a failure. In case you don’t locate it (which is very reasonable), I am talking about the black and gray waterfall that starts at the root of a tree. Yes, that is supposed to be a path.&lt;/li&gt;
  &lt;li&gt;In the same part of the painting, the bushes didn’t want to stick at all. I cleaned and re-painted the section at least 3 times.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;dl&gt;
  &lt;dt&gt;
    Bob Ross - Mountain Summit (Season 13 Episode 10)
  &lt;/dt&gt;

  &lt;dd&gt;
    &lt;a href=&quot;https://www.youtube.com/watch?v=kasGRkfkiPM&quot;&gt;https://www.youtube.com/watch?v=kasGRkfkiPM&lt;/a&gt;
  &lt;/dd&gt;

  &lt;dt&gt;
    Bob Ross - Final Reflections (Season 1 Episode 13)
    &lt;br /&gt;
    &lt;small&gt;A &quot;must see&quot; episode because it's actually Q&amp;amp;A of what might go wrong.&lt;/small&gt;
  &lt;/dt&gt;

  &lt;dd&gt;
    &lt;a href=&quot;https://www.youtube.com/watch?v=IEQWfszfRlA&quot;&gt;https://www.youtube.com/watch?v=IEQWfszfRlA&lt;/a&gt;
  &lt;/dd&gt;
&lt;/dl&gt;
</description>
        <pubDate>Mon, 14 Oct 2019 17:00:00 +0300</pubDate>
        <link>https://iridakos.com/painting/2019/10/14/mountains</link>
        <guid isPermaLink="true">https://iridakos.com/painting/2019/10/14/mountains</guid>
        
        <category>painting</category>
        
        <category>Bob Ross</category>
        
        <category>mountains</category>
        
        
        <category>painting</category>
        
      </item>
    
      <item>
        <title>Meadow</title>
        <description>&lt;p&gt;I have always liked painting but I had never devoted any time to this hobby. I was painting once every 2 or more years but with dissappointing results.
Few days ago I tried to create a &lt;a href=&quot;/painting/2019/10/07/drawing-my-cat&quot;&gt;painting of my cat&lt;/a&gt; and I enjoyed both the process and the result.&lt;/p&gt;

&lt;p&gt;I decided to pursue this hobby and yesterday, I followed an episode of Bob Ross’ show “The joy of painting” (most if not all episodes are available on &lt;a href=&quot;https://www.youtube.com/user/BobRossInc/videos&quot;&gt;Youtube&lt;/a&gt;).
I surprised myself with the outcome even though it’s not perfect, it’s not professional and it’s very different compared to the one that Bob Ross created in the episode.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/paintings/meadow/painting.jpg&quot; alt=&quot;Meadow - Painting&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I really enjoyed painting this meadow. I was listening to some of my favorite music and I felt so focused and relaxed leaving every other thought on the side for about 5 hours (I didn’t realize the time passing by so fast).&lt;/p&gt;

&lt;h2 id=&quot;facts&quot;&gt;Facts&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;I followed the &lt;a href=&quot;https://www.youtube.com/watch?v=87MMbN1bQCs&quot;&gt;“Meadow Stream”&lt;/a&gt; episode which is the &lt;strong&gt;episode 13 from season 5&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;I used water colors (tempera) instead of oil colors (that are used in the episode)&lt;/li&gt;
  &lt;li&gt;I skipped the stream because I wasn’t brave enough, I felt that I would destroy the painting&lt;/li&gt;
  &lt;li&gt;The clouds are happy little accidents, I don’t have an answer if you ask me to tell you how I created them. They were not supposed to look like this but they turned out OK&lt;/li&gt;
  &lt;li&gt;I need to buy some equipment (angled palette knife and some paintbrushes) because the ones I had, couldn’t produce the same results as shown in the episode&lt;/li&gt;
  &lt;li&gt;If I was asked to paint a meadow, I would draw nothing looking like this. Having a guide, especially if you are a newbie like me is great and really helpful. I believe that practicing this way is essential before diving to custom creations (at least for me).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;resources&quot;&gt;Resources&lt;/h2&gt;

&lt;dl&gt;
  &lt;dt&gt;
    Bob Ross - Meadow Stream (Season 5 Episode 13)
  &lt;/dt&gt;

  &lt;dd&gt;
    &lt;a href=&quot;https://www.youtube.com/watch?v=87MMbN1bQCs&quot;&gt;https://www.youtube.com/watch?v=87MMbN1bQCs&lt;/a&gt;
  &lt;/dd&gt;
&lt;/dl&gt;
</description>
        <pubDate>Fri, 11 Oct 2019 10:00:00 +0300</pubDate>
        <link>https://iridakos.com/painting/2019/10/11/meadow</link>
        <guid isPermaLink="true">https://iridakos.com/painting/2019/10/11/meadow</guid>
        
        <category>painting</category>
        
        <category>Bob Ross</category>
        
        <category>meadow</category>
        
        
        <category>painting</category>
        
      </item>
    
      <item>
        <title>Drawing my cat</title>
        <description>&lt;p&gt;On Saturday I felt like drawing and (no surprises here) I decided to create a painting of my cat.&lt;/p&gt;

&lt;p&gt;Without further ado, this is the result.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/drawing-my-cat/painting.jpg&quot; alt=&quot;Picatso painting&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At the top center and right section of the photo you may notice the paws of my cat which was present during the whole process and which actually is responsible for some of the inconsistencies of the painting &lt;strong&gt;(blaming the cat)&lt;/strong&gt;. Imagine a cat having a moving paint brush in front of her and not touching it (never happens).&lt;/p&gt;

&lt;p&gt;I would have taken photos showing the progress of the painting but everything was a mess. There was paint everywhere: on my hands, on my clothes, on the cat, on the table I put the canvas on and on the floor too. Everything I touched was turning to blue, brown or white.&lt;/p&gt;

&lt;p&gt;I used a painting set that was given to me as a present which had many stuff inside. At some point I mixed acrylic with watercolor paints because they looked the same and I realized it only after bubbles started showing up. The victim was the sky in the window. I tried to remove the pimples but still the new paint didn’t apply well afterwards. I’m very curious to see if the sky will look like this as the days pass by.&lt;/p&gt;

&lt;p&gt;Given the outcome, it’s pretty obvious that I am a newbie and I’m missing a lot of basics. I have no technique. I paint rarely but this time I really enjoyed it and even though this looks nothing like Irida (my cat), at least it does look like a cat and I find it “presentable” as opposed to my previous painting attempts. That is a personal success.&lt;/p&gt;

&lt;p&gt;I decided to devote some time to learn at least the basics, view some tutorials and of course to practice on plain objects before moving to more complex scenes.&lt;/p&gt;

&lt;h2 id=&quot;post-scriptum&quot;&gt;Post Scriptum&lt;/h2&gt;

&lt;p&gt;You are allowed to laugh with the fact that I used the &lt;code class=&quot;highlighter-rouge&quot;&gt;art&lt;/code&gt; tag in this post.&lt;/p&gt;

&lt;p&gt;This is Irida on the table of art on a previous attempt.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/drawing-my-cat/irida-paint-companion.jpg&quot; alt=&quot;Picatso&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;interesting-painting-resources&quot;&gt;Interesting painting resources&lt;/h2&gt;

&lt;dl&gt;
  &lt;dt&gt;
    &lt;a href=&quot;https://www.youtube.com/watch?v=VufykZdkmZ0&quot;&gt;https://www.youtube.com/watch?v=VufykZdkmZ0&lt;/a&gt;
  &lt;/dt&gt;

  &lt;dd class=&quot;mb-4&quot;&gt;
    A really good video showing how to draw a cat (I watched the video today, level of personal disappointment: 100%).
  &lt;/dd&gt;

  &lt;dt&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=oWuwxSJTyeQ&quot;&gt;https://www.youtube.com/watch?v=oWuwxSJTyeQ&lt;/a&gt;&lt;/dt&gt;

  &lt;dd&gt;
    Another beautiful video showing how to easily create a painting with a very nice landscape with relatively simple steps.
  &lt;/dd&gt;
&lt;/dl&gt;
</description>
        <pubDate>Mon, 07 Oct 2019 10:00:00 +0300</pubDate>
        <link>https://iridakos.com/painting/2019/10/07/drawing-my-cat</link>
        <guid isPermaLink="true">https://iridakos.com/painting/2019/10/07/drawing-my-cat</guid>
        
        <category>painting</category>
        
        <category>cats</category>
        
        <category>art</category>
        
        <category>picatso</category>
        
        
        <category>painting</category>
        
      </item>
    
      <item>
        <title>Another Friday has arrived</title>
        <description>
</description>
        <pubDate>Fri, 13 Sep 2019 00:00:00 +0300</pubDate>
        <link>https://iridakos.com/cats/2019/09/13/another-friday</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2019/09/13/another-friday</guid>
        
        <category>friday</category>
        
        
      </item>
    
      <item>
        <title>How to write better emails</title>
        <description>&lt;p&gt;&lt;strong&gt;Email communication&lt;/strong&gt; is not my favorite but since I can’t avoid it, I am trying to compose messages in a way that I think it makes it easier for both me and the recipient:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;to &lt;strong&gt;quickly address what is being communicated&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;avoid misunderstandings&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;save time&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here are some tips. They don’t apply to all type of messages, I provide &lt;code class=&quot;highlighter-rouge&quot;&gt;before&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;after&lt;/code&gt; examples to better describe each case.&lt;/p&gt;

&lt;h2 id=&quot;emphasize-text-with-boldunderlined-font&quot;&gt;Emphasize text with bold/underlined font&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Emphasizing&lt;/strong&gt; the appropriate parts of a message, especially when it’s a long one, you help readers &lt;strong&gt;quickly get an idea&lt;/strong&gt; of what the email is about and easily &lt;strong&gt;locate the important stuff&lt;/strong&gt; after going back to it at some point in the future.&lt;/p&gt;

&lt;h3 id=&quot;examples&quot;&gt;Examples&lt;/h3&gt;

&lt;h4 id=&quot;before&quot;&gt;Before&lt;/h4&gt;

&lt;div class=&quot;border p-2 no-overflow&quot;&gt;
&lt;pre&gt;Hello all,

I noticed that there are many logs for blabla the last few days and I don't think that it is normal. I believe the problem is the updated version of gem blabla.

I have opened an issue describing the case in Redmine (&amp;#35;455) in the current version.
Feel free to change its priority in case blabla.

Thanks,
Lazarus
&lt;/pre&gt;
&lt;/div&gt;

&lt;h4 id=&quot;after&quot;&gt;After&lt;/h4&gt;

&lt;div class=&quot;border p-2 no-overflow&quot;&gt;
&lt;pre&gt;Hello all,

I noticed that there are &lt;b&gt;many logs for blabla the last few days&lt;/b&gt; and I don't think that it is normal. I believe the problem is the updated version of gem blabla.

I have opened &lt;b&gt;a Redmine issue (&amp;#35;455)&lt;/b&gt; describing the case in the current version.
Feel free to change its priority in case blabla.

Thanks,
Lazarus
&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;use-specific-dates-instead-of-yesterday-tomorrow-etc&quot;&gt;Use specific dates instead of &lt;code class=&quot;highlighter-rouge&quot;&gt;yesterday&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;tomorrow&lt;/code&gt; etc&lt;/h2&gt;

&lt;p&gt;The moment you send an email is not the moment that it will be read by its recipients. &lt;strong&gt;Avoid using only temporal adverbs/nouns&lt;/strong&gt; like &lt;code class=&quot;highlighter-rouge&quot;&gt;yesterday&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;today&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;tomorrow&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;two hours ago&lt;/code&gt; etc but &lt;strong&gt;include also the specific dates/times&lt;/strong&gt; otherwise they might be misunderstood or require from recipients to check the email’s sent date/time to calculate the actual time.&lt;/p&gt;

&lt;h3 id=&quot;examples-1&quot;&gt;Examples&lt;/h3&gt;

&lt;h4 id=&quot;before-1&quot;&gt;Before&lt;/h4&gt;

&lt;div class=&quot;p-2 border no-overflow&quot;&gt;
&lt;pre&gt;Dear QA,

Yesterday we released a fix for the bug 455 on staging and we plan to release it next Monday if you give us the green light by tomorrow end of day.

Thanks,
Lazarus&lt;/pre&gt;
&lt;/div&gt;

&lt;h4 id=&quot;after-1&quot;&gt;After&lt;/h4&gt;

&lt;div class=&quot;p-2 border no-overflow&quot;&gt;
&lt;pre&gt;Dear QA,

&lt;b&gt;Yesterday&lt;/b&gt;, June 25th, 2019 we released a fix for the &lt;b&gt;bug &amp;#35;455 on staging&lt;/b&gt; and we plan to release it on &lt;b&gt;production next Monday (July 1st, 2019)&lt;/b&gt; if you give us the &lt;b&gt;green light by tomorrow (June 27th, 2019)&lt;/b&gt; end of day.

Thanks,
Lazarus&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;use-links-for-references&quot;&gt;Use links for references&lt;/h2&gt;

&lt;p&gt;Use bookmarkable links when you refer to something that would eventually require from the recipient to search for in another platform.&lt;/p&gt;

&lt;p&gt;This has two benefits:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Save time&lt;/li&gt;
  &lt;li&gt;Eliminate ambiguous references&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;examples-2&quot;&gt;Examples&lt;/h3&gt;

&lt;h4 id=&quot;before-2&quot;&gt;Before&lt;/h4&gt;

&lt;div class=&quot;p-2 border no-overflow&quot;&gt;
&lt;pre&gt;Dear Phoebe,

I didn't understand the process described on the issue about the logging bug. Irida's comment was not very clear either. Can you please help me?

Thanks,
Lazarus&lt;/pre&gt;
&lt;/div&gt;

&lt;h4 id=&quot;after-2&quot;&gt;After&lt;/h4&gt;

&lt;div class=&quot;p-2 border no-overflow&quot;&gt;
&lt;pre&gt;Dear Phoebe,

I didn't understand the process described on the issue about the logging bug (&lt;a href=&quot;#redmine453&quot;&gt;Redmine #453&lt;/a&gt;). &lt;a href=&quot;#redmine453-comment&quot;&gt;This comment from Irida&lt;/a&gt; was not very clear either. Can you please help me?

Thanks,
Lazarus&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;structure-long-messages&quot;&gt;Structure long messages&lt;/h2&gt;

&lt;p&gt;Long messages are in general not very effective and parts of them are prone to be ignored.&lt;/p&gt;

&lt;p&gt;When I have to compose such a message I try to &lt;strong&gt;categorize the text in contextual sections&lt;/strong&gt; and then structure them &lt;strong&gt;using headers and paragraphs&lt;/strong&gt; allowing readers to navigate to them at a glance.&lt;/p&gt;

&lt;h3 id=&quot;examples-3&quot;&gt;Examples&lt;/h3&gt;

&lt;h4 id=&quot;before-3&quot;&gt;Before&lt;/h4&gt;

&lt;div class=&quot;p-2 border no-overflow&quot;&gt;
  &lt;pre&gt;Dear team,

Last week we had a problem with the logs in the production environment. I am talking about the Redmine issue &amp;#35;453. We noticed a huge increase in the log messages blabla leading to delayed responses because blah blah blah. At some point the server run out of disk and everything fell apart blah blah blah. Administrators backed up the logs and removed them from the server to blah blah blah. We started investigating what is going on immediately and after two days we managed to reproduce the error in the staging environment as well. The problem was the usage of an external library that had a bug which blah blah blah. We removed the library and the bug was no longer reproducable in the staging environment. The buggy library was blah blah blah. We released the fix yesterday and everything seems to be back to normal. We also added some scripts that will notify us immediately if such conditions start to emerge.

Thank you for your time,
Lazarus&lt;/pre&gt;
&lt;/div&gt;

&lt;h4 id=&quot;after-3&quot;&gt;After&lt;/h4&gt;

&lt;div class=&quot;p-2 border no-overflow&quot;&gt;
  &lt;pre&gt;Dear team,

&lt;strong&gt;&lt;u&gt;Background&lt;/u&gt;&lt;/strong&gt;
Last week we had a problem with the logs in the production environment. We noticed a huge increase in the log messages blabla.

&lt;strong&gt;&lt;u&gt;Consequences&lt;/u&gt;&lt;/strong&gt;
The increase led to delayed responses because blah blah blah. At some point the server run out of disk and everything fell apart blah blah blah.

&lt;strong&gt;&lt;u&gt;Cause of the problem&lt;/u&gt;&lt;/strong&gt;
We started investigating what is going on immediately and after two days we managed to reproduce the error in the staging environment as well.
The problem was the usage of an external library that had a bug which blah blah blah. The buggy library was blah blah blah.

&lt;strong&gt;&lt;u&gt;Actions taken&lt;/u&gt;&lt;/strong&gt;

1. Administrators &lt;strong&gt;backed up the logs&lt;/strong&gt; and removed them from the server to blah blah blah.
2. We &lt;strong&gt;removed the library&lt;/strong&gt; and the bug was no longer reproducible in the staging environment.
3. We &lt;strong&gt;released the fix&lt;/strong&gt; yesterday, June 26th, 2019.
4. We also &lt;strong&gt;added some scripts that will notify us on time&lt;/strong&gt; if such conditions start to emerge.

&lt;strong&gt;&lt;u&gt;Current status&lt;/u&gt;&lt;/strong&gt;
&lt;strong&gt;The server is up and running, everything seems to be back to normal.&lt;/strong&gt;

&lt;strong&gt;&lt;u&gt;More info&lt;/u&gt;&lt;/strong&gt;
&lt;a href=&quot;#redmine453&quot;&gt;Related Redmine issue &amp;#35;453&lt;/a&gt;
&lt;a href=&quot;#external-library&quot;&gt;External library - Official bug report&lt;/a&gt;

Thank you for your time,
Lazarus&lt;/pre&gt;
&lt;/div&gt;

&lt;h2 id=&quot;be-specific-on-what-you-request-from-whom&quot;&gt;Be specific on what you request from whom&lt;/h2&gt;

&lt;p&gt;I have seen many many many emails for which:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;the sender wanted &lt;strong&gt;something&lt;/strong&gt; by &lt;strong&gt;someone&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;the recipients
    &lt;ul&gt;
      &lt;li&gt;didn’t think they were the ones to provide it&lt;/li&gt;
      &lt;li&gt;understood something else than what the sender asked for&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I try to be very specific and provide details (when possible) on what I need and when there’s more than one recipients I refer to each one explicitly using &lt;code class=&quot;highlighter-rouge&quot;&gt;@&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;examples-4&quot;&gt;Examples&lt;/h3&gt;

&lt;h4 id=&quot;before-4&quot;&gt;Before&lt;/h4&gt;

&lt;div class=&quot;p-2 border no-overflow&quot;&gt;
&lt;pre&gt;Dear all,

I have pushed a commit that possibly fixes the bug with the logging in staging. I won't be here tomorrow so can you review and release if ok?

Bye.
&lt;/pre&gt;
&lt;/div&gt;

&lt;h4 id=&quot;after-4&quot;&gt;After&lt;/h4&gt;

&lt;div class=&quot;p-2 border no-overflow mb-4&quot;&gt;
&lt;pre&gt;Hey,

I have pushed a &lt;strong&gt;&lt;a href=&quot;#git-commit-reference&quot;&gt;commit&lt;/a&gt; that possibly fixes the bug &lt;a href=&quot;#redmine453&quot;&gt;(Redmine #453)&lt;/a&gt;&lt;/strong&gt; with the logging in staging.

Since &lt;strong&gt;I won't be here tomorrow, June 27th&lt;/strong&gt;, can you please:

&lt;strong&gt;&lt;u&gt;@captain:&lt;/u&gt;&lt;/strong&gt; &lt;strong&gt;review&lt;/strong&gt; the &lt;a href=&quot;#git-commit-reference&quot;&gt;commit&lt;/a&gt;
&lt;strong&gt;&lt;u&gt;@qa:&lt;/u&gt;&lt;/strong&gt; &lt;strong&gt;run the suite&lt;/strong&gt; to validate the fix
&lt;strong&gt;&lt;u&gt;@devs:&lt;/u&gt;&lt;/strong&gt; proceed with the &lt;strong&gt;production release on June 28th&lt;/strong&gt; given the green light by the QA team?

Sorry for the inconvenience,
Lazarus
&lt;/pre&gt;
&lt;/div&gt;

&lt;p&gt;Thank you,&lt;/p&gt;

&lt;p&gt;Lazarus&lt;/p&gt;

&lt;h2 id=&quot;post-scriptum&quot;&gt;Post Scriptum&lt;/h2&gt;

&lt;p&gt;Find attached a photo of my cats.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/better-emails/irida-phoebe.png&quot; alt=&quot;Meow have your attention please?&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;alert alert-light&quot;&gt;
  &lt;div class=&quot;alert-heading&quot;&gt;&lt;i class=&quot;fa fa-comments&quot;&gt;&lt;/i&gt; Comments and feedback&lt;/div&gt;

  For feedback, comments, typos etc. please use this &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/iridakos-posts/issues/4&quot;&gt;issue&lt;/a&gt;.

  &lt;hr /&gt;

  &lt;strong&gt;Thanks for visiting!&lt;/strong&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 26 Jun 2019 16:30:00 +0300</pubDate>
        <link>https://iridakos.com/programming/2019/06/26/composing-better-emails</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/06/26/composing-better-emails</guid>
        
        <category>email</category>
        
        <category>communication</category>
        
        <category>productivity</category>
        
        <category>how-to</category>
        
        <category>featured</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Pair programming</title>
        <description>
</description>
        <pubDate>Wed, 12 Jun 2019 00:00:00 +0300</pubDate>
        <link>https://iridakos.com/cats/2019/06/12/pair-programming</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2019/06/12/pair-programming</guid>
        
        <category>pair programming</category>
        
        
      </item>
    
      <item>
        <title>Monday Motivation</title>
        <description>
</description>
        <pubDate>Mon, 03 Jun 2019 00:00:00 +0300</pubDate>
        <link>https://iridakos.com/cats/2019/06/03/monday-motivation</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2019/06/03/monday-motivation</guid>
        
        <category>monday motivation</category>
        
        
      </item>
    
      <item>
        <title>How to remove duplicate lines from files preserving their order</title>
        <description>&lt;p&gt;Suppose you have a text file and you need to remove all of its duplicate lines.&lt;/p&gt;

&lt;h2 id=&quot;tldr&quot;&gt;TL;DR&lt;/h2&gt;

&lt;p&gt;To remove the duplicate lines &lt;strong&gt;preserving their order in the file&lt;/strong&gt; use:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'!visited[$0]++'&lt;/span&gt; your_file &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; deduplicated_file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;how-it-works&quot;&gt;How it works&lt;/h2&gt;

&lt;p&gt;The script keeps an associative array with &lt;em&gt;indices&lt;/em&gt; equal to the unique lines of the file and &lt;em&gt;values&lt;/em&gt; equal to their occurrences. For each line of the file, if the line occurrences are zero then it increases them by one and &lt;strong&gt;prints the line&lt;/strong&gt;, otherwise it just increases the occurrences &lt;strong&gt;without printing the line&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I was not familiar with &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; and I wanted to understand how is this accomplished with such a short script (&lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt;ward). I did my research and here is what is going on:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;the awk “script” &lt;code class=&quot;highlighter-rouge&quot;&gt;!visited[$0]++&lt;/code&gt; is executed for &lt;strong&gt;each line&lt;/strong&gt; of the input file&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;visited[]&lt;/code&gt; is a variable of type &lt;a href=&quot;http://kirste.userpage.fu-berlin.de/chemnet/use/info/gawk/gawk_12.html&quot;&gt;associative array&lt;/a&gt; (a.k.a. &lt;a href=&quot;https://en.wikipedia.org/wiki/Associative_array&quot;&gt;Map&lt;/a&gt;). We don’t have to initialize it, &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; will do this for us the first time we access it.&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;highlighter-rouge&quot;&gt;$0&lt;/code&gt; variable holds the contents of the line currently being processed&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;visited[$0]&lt;/code&gt; accesses the value stored in the map with key equal to &lt;code class=&quot;highlighter-rouge&quot;&gt;$0&lt;/code&gt; (the line being processed), a.k.a. the occurrences (which we set below)&lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;highlighter-rouge&quot;&gt;!&lt;/code&gt; negates the occurrences value:
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/gawk/manual/html_node/Truth-Values.html&quot;&gt;In awk, any nonzero numeric value or any nonempty string value is true&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;https://ftp.gnu.org/old-gnu/Manuals/gawk-3.0.3/html_chapter/gawk_8.html&quot;&gt;By default, variables are initialized to the empty string, which is zero if converted to a number&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;That being said:
        &lt;ul&gt;
          &lt;li&gt;if &lt;code class=&quot;highlighter-rouge&quot;&gt;visited[$0]&lt;/code&gt; returns a number greater than zero, this negation is resolved to &lt;code class=&quot;highlighter-rouge&quot;&gt;false&lt;/code&gt;.&lt;/li&gt;
          &lt;li&gt;if &lt;code class=&quot;highlighter-rouge&quot;&gt;visited[$0]&lt;/code&gt; returns a number equal to zero or an empty string, this negation is resolved to &lt;code class=&quot;highlighter-rouge&quot;&gt;true&lt;/code&gt;.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;the &lt;code class=&quot;highlighter-rouge&quot;&gt;++&lt;/code&gt; operation increases the variable’s value (&lt;code class=&quot;highlighter-rouge&quot;&gt;visited[$0]&lt;/code&gt;) by one.
    &lt;ul&gt;
      &lt;li&gt;If the value is empty, &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; converts it to &lt;code class=&quot;highlighter-rouge&quot;&gt;0&lt;/code&gt; (number) automatically and then it gets increased.&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;Note:&lt;/strong&gt; the operation is executed after we access the variable’s value.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Summing up, the whole expression evaluates to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;true&lt;/strong&gt; if the occurrences are zero/empty string&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;false&lt;/strong&gt; if the occurrences are greater than zero&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt;&lt;/strong&gt; statements consist of a &lt;a href=&quot;http://kirste.userpage.fu-berlin.de/chemnet/use/info/gawk/gawk_9.html&quot;&gt;&lt;strong&gt;pattern-expression&lt;/strong&gt; and an &lt;strong&gt;associated action&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-awk highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pattern&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;If the pattern succeeds then the associated action is being executed&lt;/strong&gt;. If we don’t provide an action, &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; by default &lt;code class=&quot;highlighter-rouge&quot;&gt;print&lt;/code&gt;s the input.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;An omitted action is equivalent to &lt;code class=&quot;highlighter-rouge&quot;&gt;{ print $0 }&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our script consists of one &lt;code class=&quot;highlighter-rouge&quot;&gt;awk&lt;/code&gt; statement with an expression, omitting the action.
So this:&lt;/p&gt;

&lt;div class=&quot;language-awk highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;your_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deduplicated_file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;is equivalent to this:&lt;/p&gt;

&lt;div class=&quot;language-awk highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;awk&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;visited&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$0&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;your_file&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deduplicated_file&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For every line of the file, if the expression succeeds the line is printed to the output. Otherwise, the action is not executed, nothing is printed.&lt;/p&gt;

&lt;h2 id=&quot;why-not-use-the-uniq-command&quot;&gt;Why not use the &lt;code class=&quot;highlighter-rouge&quot;&gt;uniq&lt;/code&gt; command?&lt;/h2&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;uniq&lt;/code&gt; commands removes only the &lt;strong&gt;adjacent duplicate lines&lt;/strong&gt;. Demonstration:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat &lt;/span&gt;test.txt
A
A
A
B
B
B
A
A
C
C
C
B
B
A
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;uniq&lt;/span&gt; &amp;lt; test.txt
A
B
A
C
B
A
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;other-approaches&quot;&gt;Other approaches&lt;/h2&gt;

&lt;h3&gt;Using the &lt;code&gt;sort&lt;/code&gt; command&lt;/h3&gt;

&lt;p&gt;We can also use the following &lt;a href=&quot;http://man7.org/linux/man-pages/man1/sort.1.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;sort&lt;/code&gt;&lt;/a&gt; command to remove the duplicate lines but &lt;strong&gt;the line order is not preserved&lt;/strong&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; your_file &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; sorted_deduplicated_file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3&gt;Using &lt;code&gt;cat&lt;/code&gt;, &lt;code&gt;sort&lt;/code&gt; and &lt;code&gt;cut&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;The previous approach would produce a de-duplicated file whose lines would be sorted based on the contents. &lt;a href=&quot;https://stackoverflow.com/a/20639730/2292448&quot;&gt;Piping a bunch of commands&lt;/a&gt; we can overcome this issue:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; your_file | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-uk2&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sort&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-nk1&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;cut&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f2-&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;how-it-works-1&quot;&gt;How it works&lt;/h4&gt;

&lt;p&gt;Suppose we have the following file:&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;abc
ghi
abc
def
xyz
def
ghi
klm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;cat -n test.txt&lt;/code&gt;&lt;/strong&gt; prepends the order number in each line.&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1	abc
2	ghi
3	abc
4	def
5	xyz
6	def
7	ghi
8	klm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;sort -uk2&lt;/code&gt;&lt;/strong&gt; sorts the lines based on the second column (&lt;code class=&quot;highlighter-rouge&quot;&gt;k2&lt;/code&gt; option) and keeps only the first occurrence of the lines with the same second column value (&lt;code class=&quot;highlighter-rouge&quot;&gt;u&lt;/code&gt; option)&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1	abc
4	def
2	ghi
8	klm
5	xyz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;sort -nk1&lt;/code&gt;&lt;/strong&gt; sorts the lines based on their first column (&lt;code class=&quot;highlighter-rouge&quot;&gt;k1&lt;/code&gt; option) treating the column as a number (&lt;code class=&quot;highlighter-rouge&quot;&gt;-n&lt;/code&gt; option)&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;1	abc
2	ghi
4	def
5	xyz
8	klm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;cut -f2-&lt;/code&gt;&lt;/strong&gt; prints each line starting from the second column until its end (&lt;code class=&quot;highlighter-rouge&quot;&gt;-f2-&lt;/code&gt; option: &lt;em&gt;note the &lt;code class=&quot;highlighter-rouge&quot;&gt;-&lt;/code&gt; suffix which instructs to include the rest of the line&lt;/em&gt;)&lt;/p&gt;

&lt;div class=&quot;language-text highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;abc
ghi
def
xyz
klm
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;references&quot;&gt;References&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/gawk/manual/html_node/&quot;&gt;The GNU Awk User’s Guide
&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://kirste.userpage.fu-berlin.de/chemnet/use/info/gawk/gawk_12.html&quot;&gt;Arrays in Awk&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/gawk/manual/html_node/Truth-Values.html&quot;&gt;Awk - Truth values&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ftp.gnu.org/old-gnu/Manuals/gawk-3.0.3/html_chapter/gawk_8.html&quot;&gt;Awk expressions&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/1444406/how-can-i-delete-duplicate-lines-in-a-file-in-unix&quot;&gt;How can I delete duplicate lines in a file in Unix?
&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://stackoverflow.com/questions/11532157/remove-duplicate-lines-without-sorting&quot;&gt;Remove duplicate lines without sorting [duplicate]&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://unix.stackexchange.com/questions/159695/how-does-awk-a0-work/159734#159734&quot;&gt;How does awk ‘!a[$0]++’ work?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all. Cat photo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/images/posts/remove-duplicates/duplicate-cat.jpg&quot; alt=&quot;duplicate cat&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;alert alert-light&quot;&gt;
  &lt;div class=&quot;alert-heading&quot;&gt;&lt;i class=&quot;fa fa-comments&quot;&gt;&lt;/i&gt; Comments and feedback&lt;/div&gt;

  For feedback, comments, typos etc. please use this &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/iridakos-posts/issues/3&quot;&gt;issue&lt;/a&gt;.

  &lt;hr /&gt;

  &lt;strong&gt;Thanks for visiting!&lt;/strong&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 16 May 2019 11:30:00 +0300</pubDate>
        <link>https://iridakos.com/programming/2019/05/16/remove-duplicate-lines-preserving-order-linux</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/05/16/remove-duplicate-lines-preserving-order-linux</guid>
        
        <category>linux</category>
        
        <category>bash</category>
        
        <category>scripts</category>
        
        <category>file</category>
        
        <category>awk</category>
        
        <category>how-to</category>
        
        <category>featured</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>How to manage nested objects in Elasticsearch documents</title>
        <description>&lt;p&gt;In this post we are going to manage &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html&quot;&gt;nested objects&lt;/a&gt; of a document indexed with Elasticsearch.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The nested type is a specialised version of the object datatype that allows arrays of objects to be indexed in a way that they can be queried independently of each other.
&lt;cite&gt;– &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html&quot;&gt;Nested datatype - Official Elasticsearch reference&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;p&gt;To follow this post you need:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;an up and running &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/6.7/setup.html&quot;&gt;Elasticsearch&lt;/a&gt; instance
    &lt;ul&gt;
      &lt;li&gt;&lt;em&gt;I use 6.7 here&lt;/em&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;an up and running &lt;a href=&quot;https://www.elastic.co/guide/en/kibana/6.7/setup.html&quot;&gt;Kibana&lt;/a&gt; instance to interact with Elasticsearch&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;preparation&quot;&gt;Preparation&lt;/h2&gt;

&lt;p&gt;The document of our index will represent a &lt;strong&gt;human&lt;/strong&gt; and its nested objects will be &lt;strong&gt;cats&lt;/strong&gt; (no surprises).&lt;/p&gt;

&lt;h3 id=&quot;create-the-index&quot;&gt;Create the index&lt;/h3&gt;

&lt;p&gt;Open your Kibana dev console and type the following to create the index.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;PUT&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;mappings&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;human&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cats&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nested&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;properties&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;integer&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
              &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;text&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
            &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
          &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Human has:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;a &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;name&lt;/code&gt;&lt;/strong&gt; property of type &lt;code class=&quot;highlighter-rouge&quot;&gt;text&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;a &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;cats&lt;/code&gt;&lt;/strong&gt; property of type &lt;code class=&quot;highlighter-rouge&quot;&gt;nested&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each cat has:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;a &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;colors&lt;/code&gt;&lt;/strong&gt; property of type &lt;code class=&quot;highlighter-rouge&quot;&gt;integer&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;a &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;name&lt;/code&gt;&lt;/strong&gt; property of type &lt;code class=&quot;highlighter-rouge&quot;&gt;text&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;a &lt;strong&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;breed&lt;/code&gt;&lt;/strong&gt; property of type &lt;code class=&quot;highlighter-rouge&quot;&gt;text&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;add-a-human&quot;&gt;Add a human&lt;/h3&gt;

&lt;p&gt;In the Kibana console, execute the following to add a human with three cats.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Index&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;human&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cats&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Irida&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Phoebe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Nino&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Aegean&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Confirm the insertion with:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see something like this:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos_nested_objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;human&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;found&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cats&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Irida&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Phoebe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Nino&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Aegean&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Done, moving on.&lt;/p&gt;

&lt;h2 id=&quot;managing-nested-objects&quot;&gt;Managing nested objects&lt;/h2&gt;

&lt;h3 id=&quot;add-a-new-nested-object&quot;&gt;Add a new nested object&lt;/h3&gt;

&lt;p&gt;Suppose that &lt;code class=&quot;highlighter-rouge&quot;&gt;iridakos&lt;/code&gt; got a new Persian cat named &lt;code class=&quot;highlighter-rouge&quot;&gt;Leon&lt;/code&gt;. To add it in iridakos’ collection of cats we will use the &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html&quot;&gt;Update API&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In Kibana:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/_update&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ctx._source.cats.add(params.cat)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;params&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cat&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Leon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Persian&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We accessed the nested cat objects of our human with &lt;code class=&quot;highlighter-rouge&quot;&gt;ctx._source.cats&lt;/code&gt;. This gave us a &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/painless/6.7/painless-api-reference.html#painless-api-reference-Collection&quot;&gt;collection&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;We executed the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#add-java.lang.Object-&quot;&gt;add&lt;/a&gt; method on the collection to add a new cat&lt;/li&gt;
  &lt;li&gt;The properties of the new cat (&lt;code class=&quot;highlighter-rouge&quot;&gt;params.cat&lt;/code&gt;) were passed as parameters in the &lt;code class=&quot;highlighter-rouge&quot;&gt;params&lt;/code&gt; attribute of the request under the attribute &lt;code class=&quot;highlighter-rouge&quot;&gt;cat&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirm the addition with:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cat added:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos_nested_objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;human&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;found&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cats&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Irida&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Phoebe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Nino&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Aegean&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Leon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Persian&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;remove-a-nested-object&quot;&gt;Remove a nested object&lt;/h3&gt;

&lt;p&gt;Suppose we want to remove &lt;code class=&quot;highlighter-rouge&quot;&gt;Nino&lt;/code&gt; from the human’s cat collection.&lt;/p&gt;

&lt;p&gt;In Kibana:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Nino&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/_update&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ctx._source.cats.removeIf(cat -&amp;gt; cat.name == params.cat_name)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;params&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cat_name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Nino&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notes&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We accessed the nested cat objects of our human with &lt;code class=&quot;highlighter-rouge&quot;&gt;ctx._source.cats&lt;/code&gt;. This gave us a &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/painless/6.7/painless-api-reference.html#painless-api-reference-Collection&quot;&gt;collection&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;We executed the &lt;a href=&quot;https://docs.oracle.com/javase/8/docs/api/java/util/Collection.html#removeIf-java.util.function.Predicate-&quot;&gt;removeIf&lt;/a&gt; method on the collection to conditionally remove an item&lt;/li&gt;
  &lt;li&gt;We provided a &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/painless/6.7/painless-api-reference.html#painless-api-reference-Predicate&quot;&gt;Predicate&lt;/a&gt; to the &lt;code class=&quot;highlighter-rouge&quot;&gt;removeIf&lt;/code&gt; method in which we specify which items we want to remove. This predicate will be executed on each item of the collection and resolves to a Boolean value. If the resolution is &lt;code class=&quot;highlighter-rouge&quot;&gt;true&lt;/code&gt; then the item will be removed. In our case, the condition is a simple equality check on the &lt;code class=&quot;highlighter-rouge&quot;&gt;cat&lt;/code&gt;’s name attribute.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;cat_name&lt;/code&gt; was passed as a parameter (&lt;code class=&quot;highlighter-rouge&quot;&gt;params.cat_name&lt;/code&gt;) instead of fixing it to the script source.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirm the addition with:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cat removed:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos_nested_objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;human&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;found&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cats&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Irida&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Phoebe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Leon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Persian&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;update-a-nested-object&quot;&gt;Update a nested object&lt;/h3&gt;

&lt;p&gt;Suppose we want to change all cat breeds from &lt;code class=&quot;highlighter-rouge&quot;&gt;European&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;European Shorthair&lt;/code&gt; (Phoebe is the only one in our case).&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;breed&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/_update&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;def targets = ctx._source.cats.findAll(cat -&amp;gt; cat.breed == params.current_breed); for(cat in targets) { cat.breed = params.breed }&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;params&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;current_breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We accessed the nested cat objects of our human with &lt;code class=&quot;highlighter-rouge&quot;&gt;ctx._source.cats&lt;/code&gt;. This gave us a &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/painless/6.7/painless-api-reference.html#painless-api-reference-Collection&quot;&gt;collection&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;We executed the &lt;a href=&quot;https://artifacts.elastic.co/javadoc/org/elasticsearch/painless/lang-painless/6.7.1/org/elasticsearch/painless/api/Augmentation.html#findAll%2Djava.util.Collection%2Djava.util.function.Predicate%2D&quot;&gt;findAll&lt;/a&gt; method on the collection to select specific items&lt;/li&gt;
  &lt;li&gt;We provided a &lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/painless/6.7/painless-api-reference.html#painless-api-reference-Predicate&quot;&gt;Predicate&lt;/a&gt; to the &lt;code class=&quot;highlighter-rouge&quot;&gt;findAll&lt;/code&gt; method in which we specify which items we want to select. This predicate will be executed on each item of the collection and resolves to a Boolean value. If the resolution is &lt;code class=&quot;highlighter-rouge&quot;&gt;true&lt;/code&gt; then the item will be selected. In our case, the condition is a simple equality check on the &lt;code class=&quot;highlighter-rouge&quot;&gt;cat&lt;/code&gt;’s breed attribute.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;current_breed&lt;/code&gt; was passed as a parameter (&lt;code class=&quot;highlighter-rouge&quot;&gt;params.current_breed&lt;/code&gt;) instead of fixing it to the script source.&lt;/li&gt;
  &lt;li&gt;We then loop on the selected cats (whose &lt;code class=&quot;highlighter-rouge&quot;&gt;breed&lt;/code&gt; attribute has value &lt;code class=&quot;highlighter-rouge&quot;&gt;European&lt;/code&gt;) and change their breed to the new value which we passed by another parameter &lt;code class=&quot;highlighter-rouge&quot;&gt;breed&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirm the change:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cat updated:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos_nested_objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;human&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;found&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cats&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Irida&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Phoebe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Leon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Persian&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;update-multiple-attributes-of-nested-objects-fulfilling-multiple-conditions&quot;&gt;Update multiple attributes of nested objects fulfilling multiple conditions&lt;/h4&gt;

&lt;p&gt;Now, in a more advanced example, we are going to use a more flexible script to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;target objects based on multiple conditions (here colors and breed)&lt;/li&gt;
  &lt;li&gt;update more than one attributes (here colors and breed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suppose we want to change the breed of cats who have &lt;code class=&quot;highlighter-rouge&quot;&gt;4 colors&lt;/code&gt; and their breed is &lt;code class=&quot;highlighter-rouge&quot;&gt;Persian&lt;/code&gt; to &lt;code class=&quot;highlighter-rouge&quot;&gt;Aegean&lt;/code&gt; and their colors to &lt;code class=&quot;highlighter-rouge&quot;&gt;3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The script we will use is the following:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;multiple&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;attributes&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;multiple&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;POST&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/_update&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;script&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;def targets = ctx._source.cats.findAll(cat -&amp;gt; { for (condition in params.conditions.entrySet()) { if (cat[condition.getKey()] != condition.getValue()) { return false; } } return true; }); for (cat in targets) { for (change in params.changes.entrySet()) { cat[change.getKey()] = change.getValue() } }&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;params&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;conditions&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Persian&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;changes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Aegean&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;For convenience, here’s the script source with proper indentation.&lt;/p&gt;
&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;_source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;cats&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                                         &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;condition&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;conditions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;entrySet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                                           &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                                             &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
                                           &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                                         &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
                                         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;targets&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
 &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;change&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;changes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;entrySet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;cat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getKey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getValue&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt;
 &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We select which cats we want to update by checking that their properties have the value specified in the &lt;code class=&quot;highlighter-rouge&quot;&gt;params.conditions&lt;/code&gt; parameter.&lt;/li&gt;
  &lt;li&gt;For each selected cat, we change its attributes’ values as specified in the &lt;code class=&quot;highlighter-rouge&quot;&gt;params.changes&lt;/code&gt; parameter.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Confirm:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;GET&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;iridakos_nested_objects/human/&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cat updated.&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos_nested_objects&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;human&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_version&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;found&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;_source&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;iridakos&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;cats&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Irida&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Phoebe&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;European Shorthair&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Leon&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;colors&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;breed&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Aegean&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;useful-links&quot;&gt;Useful links&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/nested.html&quot;&gt;Elasticsearch reference - Mapping - Field datatypes - Nested datatype&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html&quot;&gt;Elasticsearch reference - Document APIs - Update API&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.elastic.co/guide/en/elasticsearch/painless/6.7/painless-api-reference.html&quot;&gt;Elasticsearch reference - Painless API reference&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all! Cat photo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/programming-cat/terminator.png&quot; alt=&quot;I'll be back&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;alert alert-light&quot;&gt;
  &lt;div class=&quot;alert-heading&quot;&gt;&lt;i class=&quot;fa fa-comments&quot;&gt;&lt;/i&gt; Comments and feedback&lt;/div&gt;

  For feedback, comments, typos etc. please use this &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/iridakos-posts/issues/2&quot;&gt;issue&lt;/a&gt;.

  &lt;hr /&gt;

  &lt;strong&gt;Thanks for visiting!&lt;/strong&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 02 May 2019 15:30:00 +0300</pubDate>
        <link>https://iridakos.com/programming/2019/05/02/add-update-delete-elasticsearch-nested-objects</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/05/02/add-update-delete-elasticsearch-nested-objects</guid>
        
        <category>elasticsearch</category>
        
        <category>opensource</category>
        
        <category>scripts</category>
        
        <category>how-to</category>
        
        <category>nested objects</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Monday. Again.</title>
        <description>
</description>
        <pubDate>Mon, 15 Apr 2019 00:00:00 +0300</pubDate>
        <link>https://iridakos.com/cats/2019/04/15/monday-again</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2019/04/15/monday-again</guid>
        
        
      </item>
    
      <item>
        <title>How to alias and navigate to directories with autocomplete in Linux</title>
        <description>&lt;p&gt;I use the terminal a lot and in my day to day work I tend to navigate to the same bunch of directories.&lt;/p&gt;

&lt;p&gt;There are some awesome tools out there (like &lt;a href=&quot;https://github.com/wting/autojump&quot;&gt;autojump&lt;/a&gt; or &lt;a href=&quot;https://github.com/rupa/z&quot;&gt;z&lt;/a&gt;) but sometimes, especially when the directories are similarly named, there is a need &lt;strong&gt;to be explicit&lt;/strong&gt; to navigate to the proper one.&lt;/p&gt;

&lt;p&gt;I decided to write a script to overcome this issue and to avoid having to edit my &lt;code class=&quot;highlighter-rouge&quot;&gt;.bash*&lt;/code&gt; files to manage &lt;a href=&quot;http://tldp.org/LDP/abs/html/aliases.html&quot;&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;aliases&lt;/code&gt;&lt;/a&gt; each time I wanted to add or remove a directory.&lt;/p&gt;

&lt;h2 id=&quot;goto&quot;&gt;goto&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;goto&lt;/code&gt; is a shell utility to quickly navigate to aliased directories with autocomplete &lt;em&gt;(tab completion)&lt;/em&gt;.&lt;/p&gt;

&lt;!-- Place this tag where you want the button to render. --&gt;
&lt;p&gt;&lt;a class=&quot;btn btn-secondary bg-dark&quot; href=&quot;https://github.com/iridakos/goto&quot; data-size=&quot;large&quot; data-show-count=&quot;true&quot; aria-label=&quot;View iridakos/goto on GitHub&quot;&gt;
  &lt;i class=&quot;fa fa-github&quot; style=&quot;font-size: 110%&quot;&gt;&lt;/i&gt;
  goto repo at GitHub
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/goto/goto.gif&quot; alt=&quot;goto gif&quot; /&gt;&lt;/p&gt;

&lt;p&gt;User registers directory aliases, for example:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--register&lt;/span&gt; dev /home/iridakos/development
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and then cds to that directory with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Find below documentation on the script but make sure you check the &lt;a href=&quot;https://github.com/iridakos/goto/blob/master/README.md&quot;&gt;script’s documentation page&lt;/a&gt; for updates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sorry for the name, I know it brings back memories but it’s not what it seems :)&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;To install &lt;code class=&quot;highlighter-rouge&quot;&gt;goto&lt;/code&gt; all you have to do is clone the &lt;a href=&quot;https://github.com/iridakos/goto&quot;&gt;repository&lt;/a&gt; locally:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/iridakos/goto.git
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;navigate to it&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;goto
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and execute:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; ./install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You need to restart your shell after installation.&lt;/p&gt;

&lt;h2 id=&quot;usage&quot;&gt;Usage&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;#change-to-an-aliased-directory&quot;&gt;Change to an aliased directory&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#register-an-alias&quot;&gt;Register an alias&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#unregister-an-alias&quot;&gt;Unregister an alias&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#list-aliases&quot;&gt;List aliases&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#expand-an-alias&quot;&gt;Expand an alias&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#cleanup&quot;&gt;Cleanup&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#help&quot;&gt;Help&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#version&quot;&gt;Version&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;#extras&quot;&gt;Extras&lt;/a&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;a href=&quot;#push-before-changing-directories&quot;&gt;Push before changing directories&lt;/a&gt;&lt;/li&gt;
      &lt;li&gt;&lt;a href=&quot;#revert-to-a-pushed-directory&quot;&gt;Revert to a pushed directory&lt;/a&gt;&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;change-to-an-aliased-directory&quot;&gt;Change to an aliased directory&lt;/h3&gt;
&lt;p&gt;To change to an aliased directory, type:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;example&quot;&gt;Example&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;register-an-alias&quot;&gt;Register an alias&lt;/h3&gt;
&lt;p&gt;To register a directory alias, type:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &amp;lt;directory&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--register&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &amp;lt;directory&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;example-1&quot;&gt;Example&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; blog /mnt/external/projects/html/blog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--register&lt;/span&gt; blog /mnt/external/projects/html/blog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;notes&quot;&gt;Notes&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;highlighter-rouge&quot;&gt;goto&lt;/code&gt; &lt;strong&gt;expands&lt;/strong&gt; the directories hence you can easily alias your current directory with:
    &lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt; last_release &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;and it will automatically be aliased to the whole path.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Pressing the &lt;code class=&quot;highlighter-rouge&quot;&gt;tab&lt;/code&gt; key after the alias name, you have the default directory suggestions by the shell.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;unregister-an-alias&quot;&gt;Unregister an alias&lt;/h3&gt;

&lt;p&gt;To unregister an alias, use:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--unregister&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h4 id=&quot;example-2&quot;&gt;Example&lt;/h4&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto -u last_release
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto --unregister last_release
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;notes-1&quot;&gt;Notes&lt;/h4&gt;

&lt;p&gt;Pressing the &lt;code class=&quot;highlighter-rouge&quot;&gt;tab&lt;/code&gt; key after the command (&lt;code class=&quot;highlighter-rouge&quot;&gt;-u&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;--unregister&lt;/code&gt;), the completion script will prompt you with the list of registered aliases for your convenience.&lt;/p&gt;

&lt;h3 id=&quot;list-aliases&quot;&gt;List aliases&lt;/h3&gt;

&lt;p&gt;To get the list of your currently registered aliases, use:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--list&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;expand-an-alias&quot;&gt;Expand an alias&lt;/h3&gt;

&lt;p&gt;To expand an alias to its value, use:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--expand&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;example-3&quot;&gt;Example&lt;/h4&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; last_release
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--expand&lt;/span&gt; last_release
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;cleanup&quot;&gt;Cleanup&lt;/h3&gt;

&lt;p&gt;To cleanup the aliases from directories that are no longer accessible in your filesystem, use:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--cleanup&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;help&quot;&gt;Help&lt;/h3&gt;

&lt;p&gt;To view the tool’s help information, use:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;version&quot;&gt;Version&lt;/h3&gt;

&lt;p&gt;To view the tool’s version, use:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-v&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;extras&quot;&gt;Extras&lt;/h3&gt;

&lt;h4 id=&quot;push-before-changing-directories&quot;&gt;Push before changing directories&lt;/h4&gt;

&lt;p&gt;To first push the current directory onto the directory stack before changing directories, type:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--push&lt;/span&gt; &amp;lt;&lt;span class=&quot;nb&quot;&gt;alias&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;revert-to-a-pushed-directory&quot;&gt;Revert to a pushed directory&lt;/h4&gt;
&lt;p&gt;To return to a pushed directory, type:&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;or&lt;/p&gt;
&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;goto &lt;span class=&quot;nt&quot;&gt;--pop&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h5 id=&quot;notes-2&quot;&gt;Notes&lt;/h5&gt;

&lt;p&gt;This command is equivalent to &lt;code class=&quot;highlighter-rouge&quot;&gt;popd&lt;/code&gt;, but within the &lt;code class=&quot;highlighter-rouge&quot;&gt;goto&lt;/code&gt; command.&lt;/p&gt;

&lt;h2 id=&quot;behind-the-scenes&quot;&gt;Behind the scenes&lt;/h2&gt;

&lt;p&gt;Upon installation, a line is appended to your &lt;code class=&quot;highlighter-rouge&quot;&gt;.bashrc&lt;/code&gt; file which sources the script, registering a &lt;code class=&quot;highlighter-rouge&quot;&gt;goto&lt;/code&gt; function responsible for changing the directory based on the defined aliases of the database.&lt;/p&gt;

&lt;p&gt;The script creates a directory alias database file under &lt;code class=&quot;highlighter-rouge&quot;&gt;~/.goto&lt;/code&gt;.
Every &lt;code class=&quot;highlighter-rouge&quot;&gt;register&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;unregister&lt;/code&gt; action modifies this file.&lt;/p&gt;

&lt;p&gt;The script also uses the &lt;a href=&quot;https://www.tldp.org/LDP/abs/html/tabexpansion.html&quot;&gt;Bash programmable completion&lt;/a&gt; feature to define tab completions resolved via extraction of the aliases defined in the &lt;code class=&quot;highlighter-rouge&quot;&gt;goto&lt;/code&gt; database file.&lt;/p&gt;

&lt;p&gt;That’s all! Cat photo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/programming-cat/terminator.png&quot; alt=&quot;I'll be back&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;alert alert-light&quot;&gt;
  &lt;div class=&quot;alert-heading&quot;&gt;&lt;i class=&quot;fa fa-comments&quot;&gt;&lt;/i&gt; Code and comments&lt;/div&gt;

  You can find the code of goto at &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/goto&quot;&gt;&lt;i class=&quot;fa fa-github&quot;&gt;&lt;/i&gt; https://github.com/iridakos/goto&lt;/a&gt;.

  &lt;hr /&gt;

  For feedback, comments, typos etc. please open an &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/goto/issues&quot;&gt;issue&lt;/a&gt; in the repository.

  &lt;hr /&gt;

  &lt;strong&gt;Thanks for visiting!&lt;/strong&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 10 Apr 2019 16:00:00 +0300</pubDate>
        <link>https://iridakos.com/programming/2019/04/10/shell-navigation-with-autocomplete</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/04/10/shell-navigation-with-autocomplete</guid>
        
        <category>linux</category>
        
        <category>opensource</category>
        
        <category>bash</category>
        
        <category>scripts</category>
        
        <category>tutorial</category>
        
        <category>productivity</category>
        
        <category>tools</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Dockerizing a Rails application</title>
        <description>&lt;p&gt;Hey!&lt;/p&gt;

&lt;p&gt;In this post we are going to:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;create a docker image for the &lt;a href=&quot;/programming/2019/04/04/creating-chat-application-rails-websockets&quot;&gt;&lt;strong&gt;Rails chat application&lt;/strong&gt; that we created in the previous post&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;configure the Docker environment and run the application by:
    &lt;ul&gt;
      &lt;li&gt;creating a container for the PostgreSQL database&lt;/li&gt;
      &lt;li&gt;creating a container for the Redis server&lt;/li&gt;
      &lt;li&gt;creating a container with the required configuration from the image we built&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/post.png&quot; alt=&quot;Rails chat application gif&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h2&gt;

&lt;h3 id=&quot;install-docker&quot;&gt;Install docker&lt;/h3&gt;

&lt;p&gt;The first thing you need in order to follow this tutorial is to install &lt;a href=&quot;https://www.docker.com/&quot;&gt;Docker&lt;/a&gt; on your machine.&lt;/p&gt;

&lt;p&gt;We are going to use the &lt;a href=&quot;https://docs.docker.com/install/&quot;&gt;Docker Community Edition&lt;/a&gt;. Follow the installation instructions matching your system.&lt;/p&gt;

&lt;p&gt;I’m on Ubuntu 18.04 LTS so following the &lt;a href=&quot;https://docs.docker.com/install/linux/docker-ce/ubuntu/&quot;&gt;instructions&lt;/a&gt;, I had to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Uninstall previous versions with:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get remove docker docker-engine docker.io containerd runc
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;I chose to install the application using the repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update

&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     apt-transport-https &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     ca-certificates &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     curl &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     gnupg-agent &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
     software-properties-common

curl &lt;span class=&quot;nt&quot;&gt;-fsSL&lt;/span&gt; https://download.docker.com/linux/ubuntu/gpg | &lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-key add -
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and I verified that I had the key with the proper fingerprint after executing:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-key fingerprint 0EBFCD88
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;I set up the repository with:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;add-apt-repository &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
   &lt;span class=&quot;s2&quot;&gt;&quot;deb [arch=amd64] https://download.docker.com/linux/ubuntu &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
   &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;lsb_release &lt;span class=&quot;nt&quot;&gt;-cs&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
   stable&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The installation took place with these commands:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get update

&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;docker-ce docker-ce-cli containerd.io
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;ul&gt;
  &lt;li&gt;I checked that the installation was successful with:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ sudo docker run hello-world

Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
1b930d010525: Pull complete
Digest: sha256:...
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the &quot;hello-world&quot; image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;important-note&quot;&gt;Important note&lt;/h4&gt;

&lt;p&gt;Upon installation, a new user group was created with the name &lt;code class=&quot;highlighter-rouge&quot;&gt;docker&lt;/code&gt;. If you want to allow users to do docker stuff without using &lt;code class=&quot;highlighter-rouge&quot;&gt;sudo&lt;/code&gt;, you have to do some extra configuration (&lt;a href=&quot;https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user&quot;&gt;read more here&lt;/a&gt;) but keep in mind that:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;The docker group grants privileges equivalent to the root user&lt;/strong&gt;. For details on how this impacts security in your system, see Docker Daemon Attack Surface.
&lt;cite&gt;– &lt;a href=&quot;https://docs.docker.com/install/linux/linux-postinstall/#manage-docker-as-a-non-root-user&quot;&gt;Post-installation steps for Linux - Official Docker installation instructions&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We are going to use &lt;code class=&quot;highlighter-rouge&quot;&gt;sudo&lt;/code&gt; in this tutorial.&lt;/p&gt;

&lt;h3 id=&quot;clone-the-rails-chat-tutorial-from-github&quot;&gt;Clone the rails chat tutorial from GitHub&lt;/h3&gt;

&lt;p&gt;Navigate to your development directory on your machine and clone the sample Rails chat application with:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git clone https://github.com/iridakos/rails-chat-tutorial
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Done.&lt;/p&gt;

&lt;h3 id=&quot;configure-the-application-to-use-postgresql-for-the-production-environment&quot;&gt;Configure the application to use PostgreSQL for the production environment&lt;/h3&gt;

&lt;p&gt;The application is configured to use the predefined &lt;code class=&quot;highlighter-rouge&quot;&gt;sqlite&lt;/code&gt; database adapter. For the purpose of this tutorial we will change the adapter to &lt;code class=&quot;highlighter-rouge&quot;&gt;postgresql&lt;/code&gt; and at the second part of the post we will create a container running the PostgreSQL database.&lt;/p&gt;

&lt;p&gt;Open the file &lt;code class=&quot;highlighter-rouge&quot;&gt;config/database.yml&lt;/code&gt; file and change the &lt;code class=&quot;highlighter-rouge&quot;&gt;production&lt;/code&gt; configuration as described below:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;production&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;*default&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;postgresql&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV.fetch('DATABASE_HOST') %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV.fetch('DATABASE_PORT') %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV.fetch('DATABASE_USERNAME') %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV.fetch('DATABASE_PASSWORD') %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Open the application’s &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; and add the following lines:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;group&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:production&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'pg'&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to install the adapter. The &lt;code class=&quot;highlighter-rouge&quot;&gt;pg&lt;/code&gt; gem requires to have the package &lt;code class=&quot;highlighter-rouge&quot;&gt;libpq-dev&lt;/code&gt; installed on the machine. We will satisfy this requirement when building the image.&lt;/p&gt;

&lt;h2 id=&quot;building-the-docker-image&quot;&gt;Building the docker image&lt;/h2&gt;

&lt;p&gt;We are going to &lt;strong&gt;build the image gradually&lt;/strong&gt; in order to understand what’s going on with every command we use.&lt;/p&gt;

&lt;h3 id=&quot;create-the-dockerfile&quot;&gt;Create the Dockerfile&lt;/h3&gt;

&lt;p&gt;Whenever we want to create a new image in docker we use a file named &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;. It is a text file with instructions to be followed sequentially to assemble an image.&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;code class=&quot;highlighter-rouge&quot;&gt;Rails chat tutorial&lt;/code&gt; (from now I will call this &lt;code class=&quot;highlighter-rouge&quot;&gt;application directory&lt;/code&gt;) directory and create the file.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;touch &lt;/span&gt;Dockerfile
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and before continuing let’s try to build the image with just that empty file:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker build &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; rails-chat-tutorial
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course we get an error, but take a look at the first line of the log:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Sending build context to Docker daemon  46.39MB
Error response from daemon: the Dockerfile &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;Dockerfile&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; cannot be empty
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When building an image, Docker creates a build context which is actually the files that will be available when the &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;’s commands get executed.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;.&lt;/code&gt; (dot) part of the build command that we used tells Docker to try to build the image using the current directory for its build context.&lt;/p&gt;

&lt;p&gt;Since we didn’t explicitly specified in the command which &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; to use, Docker will use the one that is located in the root of the context.&lt;/p&gt;

&lt;h3 id=&quot;define-the-parent-image&quot;&gt;Define the parent image&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;A parent image is the image that your image is based on. It refers to the contents of the FROM directive in the Dockerfile. Each subsequent declaration in the Dockerfile modifies this parent image. Most Dockerfiles start from a parent image, rather than a base image. However, the terms are sometimes used interchangeably.
&lt;cite&gt;– &lt;a href=&quot;https://docs.docker.com/develop/develop-images/baseimages/&quot;&gt;Create a base image - Official Docker Documentation&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Building the image from scratch is out of the context of this tutorial but if you want to familiarize your self with this aspect, read more &lt;a href=&quot;https://docs.docker.com/develop/develop-images/baseimages/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Docker provides &lt;a href=&quot;https://hub.docker.com/_/ruby&quot;&gt;official Ruby images&lt;/a&gt; and we are going to use the version that the Rails chat tutorial uses which is &lt;code class=&quot;highlighter-rouge&quot;&gt;2.6.2&lt;/code&gt; as our parent image.&lt;/p&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; and add the following line:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ruby:2.6.2-stretch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and run the build command again:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker build &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; rails-chat-tutorial
Sending build context to Docker daemon  46.39MB
Step 1/1 : FROM ruby:2.6.2-stretch
2.6.2-stretch: Pulling from library/ruby
e79bb959ec00: Pull &lt;span class=&quot;nb&quot;&gt;complete
&lt;/span&gt;d4b7902036fe: Pull &lt;span class=&quot;nb&quot;&gt;complete
&lt;/span&gt;1b2a72d4e030: Pull &lt;span class=&quot;nb&quot;&gt;complete
&lt;/span&gt;d54db43011fd: Pull &lt;span class=&quot;nb&quot;&gt;complete
&lt;/span&gt;69d473365bb3: Pull &lt;span class=&quot;nb&quot;&gt;complete
&lt;/span&gt;84ed2a0dc034: Pull &lt;span class=&quot;nb&quot;&gt;complete
&lt;/span&gt;75df5efa5606: Pull &lt;span class=&quot;nb&quot;&gt;complete
&lt;/span&gt;f0d10aea813b: Pull &lt;span class=&quot;nb&quot;&gt;complete
&lt;/span&gt;Digest: sha256:d5af6b19da8381014f59e79245ae242dd5ea8dfe1a8a6c0e2bc481366f1e92b9
Status: Downloaded newer image &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;ruby:2.6.2-stretch
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 8d6721e9290e
Successfully built 8d6721e9290e
Successfully tagged rails-chat-tutorial:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Execute the following command to see which images Docker has.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker image list
REPOSITORY            TAG                 IMAGE ID            CREATED             SIZE
rails-chat-tutorial   latest              8d6721e9290e        10 days ago         870MB
ruby                  2.6.2-stretch       8d6721e9290e        10 days ago         870MB
hello-world           latest              fce289e99eb9        3 months ago        1.84kB
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;hello-world&lt;/code&gt; is the Docker’s image that we used after installing Docker.
The other image, the &lt;code class=&quot;highlighter-rouge&quot;&gt;ruby&lt;/code&gt; one is the parent image of our image. Since the &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; didn’t have any custom instructions other that just defining a parent image, the resulting image &lt;code class=&quot;highlighter-rouge&quot;&gt;rails-chat-tutorial&lt;/code&gt; is actually the same as the parent image and has the same &lt;code class=&quot;highlighter-rouge&quot;&gt;IMAGE ID&lt;/code&gt;, &lt;code class=&quot;highlighter-rouge&quot;&gt;CREATED&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;SIZE&lt;/code&gt; properties. Time to change this.&lt;/p&gt;

&lt;h3 id=&quot;copying-the-application-code&quot;&gt;Copying the application code&lt;/h3&gt;

&lt;p&gt;The purpose of the image that we are building is to serve the &lt;code class=&quot;highlighter-rouge&quot;&gt;Rails chat tutorial&lt;/code&gt; application. Eventually, to do so it’s pretty obvious that the image must contain the code of the application.&lt;/p&gt;

&lt;p&gt;We will use the &lt;code class=&quot;highlighter-rouge&quot;&gt;COPY&lt;/code&gt; command to copy the code inside the image.&lt;/p&gt;

&lt;p&gt;Open the &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; and append the following line:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; . /application&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This command will copy all files from inside the build context to the image.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;the first argument is the location of the build context to be copied&lt;/li&gt;
  &lt;li&gt;the second argument is the target location inside the image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Build the image again and execute the following command to confirm that we are good.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;docker run -i -t rails-chat-tutorial
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you take a look at the &lt;a href=&quot;https://github.com/docker-library/ruby/blob/995719add69339b78bd8cde46183b4902b761add/2.6/stretch/Dockerfile&quot;&gt;ruby’s docker image&lt;/a&gt;, you will see that the last line is:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;CMD&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; [ &quot;irb&quot; ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since we don’t define something different in our image, the same command is being executed and that’s why the execution of the previous command brought us to Ruby’s &lt;code class=&quot;highlighter-rouge&quot;&gt;irb&lt;/code&gt; console.&lt;/p&gt;

&lt;p&gt;Let’s see what the &lt;code class=&quot;highlighter-rouge&quot;&gt;/application&lt;/code&gt; directory of the container has.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;Dir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'/application/*'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/application/config.ru&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/Rakefile&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/lib&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/storage&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/Gemfile&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/app&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/Gemfile.lock&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/LICENSE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/log&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/public&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/tmp&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/vendor&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/bin&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/README.md&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/config&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/package.json&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/Dockerfile&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/application/db&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Cool, the application directory has been copied. Moving on.&lt;/p&gt;

&lt;h3 id=&quot;install-application-dependencies&quot;&gt;Install application dependencies&lt;/h3&gt;

&lt;p&gt;Before starting the server (puma in our case), we have to install the dependencies of the application. To do so, add the following line to the &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--deployment&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--without&lt;/span&gt; development &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and rebuild the image.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;build &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; rails-chat-tutorial
Sending build context to Docker daemon  46.39MB
Step 1/3 : FROM ruby:2.6.2-stretch
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 8d6721e9290e
Step 2/3 : COPY &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; /application
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; f9b9d813d6a0
Step 3/3 : RUN bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--deployment&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--without&lt;/span&gt; development &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Running &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;a6c8c25da3f5
Could not locate Gemfile
The &lt;span class=&quot;nb&quot;&gt;command&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'/bin/sh -c bundle install --deployment --without development test'&lt;/span&gt; returned a non-zero code: 10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have an error because for the bundle command to succeed we must first change to the application’s root directory that does contain the &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Change the contents of the &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; to the following:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ruby:2.6.2-stretch&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Copy application code&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; . /application&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Change to the application's directory&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /application&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Install gems&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--deployment&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--without&lt;/span&gt; development &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and rebuild. Now the gems are being installed and we are ready to start the server.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;docker build &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; rails-chat-tutorial
Sending build context to Docker daemon  46.39MB
Step 1/4 : FROM ruby:2.6.2-stretch
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 8d6721e9290e
Step 2/4 : COPY &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; /application
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; b1aae569faf4
Step 3/4 : WORKDIR /application
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Running &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;ab90edf73be5
Removing intermediate container ab90edf73be5
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; 6bbdaa9942e3
Step 4/4 : RUN bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--deployment&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--without&lt;/span&gt; development &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; Running &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;22724a3684fe
The dependency tzinfo-data &lt;span class=&quot;o&quot;&gt;(&amp;gt;=&lt;/span&gt; 0&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; will be unused by any of the platforms Bundler is installing &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt; Bundler is installing &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;ruby but the dependency is only &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run bundle lock &lt;span class=&quot;nt&quot;&gt;--add-platform&lt;/span&gt; x86-mingw32 x86-mswin32 x64-mingw32 java.
Fetching gem metadata from https://rubygems.org/............
Fetching rake 12.3.2
Installing rake 12.3.2
Fetching concurrent-ruby 1.1.5
...
...
...
Fetching sqlite3 1.4.0
Installing sqlite3 1.4.0 with native extensions
Fetching uglifier 4.1.20
Installing uglifier 4.1.20
Bundle &lt;span class=&quot;nb&quot;&gt;complete&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt; 21 Gemfile dependencies, 69 gems now installed.
Gems &lt;span class=&quot;k&quot;&gt;in &lt;/span&gt;the &lt;span class=&quot;nb&quot;&gt;groups &lt;/span&gt;development and &lt;span class=&quot;nb&quot;&gt;test &lt;/span&gt;were not installed.
Bundled gems are installed into ./vendor/bundle
...
...
...

Removing intermediate container 22724a3684fe
 &lt;span class=&quot;nt&quot;&gt;---&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; d0d3163a8cca
Successfully built d0d3163a8cca
Successfully tagged rails-chat-tutorial:latest
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;asset-compilation&quot;&gt;Asset compilation&lt;/h3&gt;

&lt;p&gt;In the production environment, assets have to be pre-compiled.&lt;/p&gt;

&lt;p&gt;We will add this task in our &lt;code class=&quot;highlighter-rouge&quot;&gt;ENTRYPOINT&lt;/code&gt; script (see below) because during asset compilation Rails initializes the application and if we executed the task upon building the image, the initialization would fail since some components (like database connection, configuration of services based on environment variables like &lt;code class=&quot;highlighter-rouge&quot;&gt;cable.yml&lt;/code&gt;) are not available.&lt;/p&gt;

&lt;p&gt;We must install a Javascript environment in the container though or else when the time comes and the task is executed, will get the following error:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ExecJS::RuntimeUnavailable: Could not find a JavaScript runtime. See https://github.com/rails/execjs &lt;span class=&quot;k&quot;&gt;for &lt;/span&gt;a list of available runtimes.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We will install &lt;code class=&quot;highlighter-rouge&quot;&gt;nodejs&lt;/code&gt;, add the following line:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-sL&lt;/span&gt; https://deb.nodesource.com/setup_10.x | bash - &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    apt &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; nodejs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Rebuild and you should be fine.&lt;/p&gt;

&lt;h3 id=&quot;start-the-server&quot;&gt;Start the server&lt;/h3&gt;

&lt;p&gt;We want to start the application in the production environment. Rails can resolve this via the environment variable &lt;code class=&quot;highlighter-rouge&quot;&gt;RAILS_ENV&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To set it in the image, add in &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; RAILS_ENV production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The last instruction in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; will be our &lt;code class=&quot;highlighter-rouge&quot;&gt;ENTRYPOINT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add the following line:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ./entrypoint.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What’s left to do is to configure the &lt;code class=&quot;highlighter-rouge&quot;&gt;entrypoint.sh&lt;/code&gt; script to do the following:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;compile the assets&lt;/li&gt;
  &lt;li&gt;start the server&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create a file named &lt;code class=&quot;highlighter-rouge&quot;&gt;entrypoint.sh&lt;/code&gt; in the root application directory and add:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# Compile the assets&lt;/span&gt;
bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rake assets:precompile

&lt;span class=&quot;c&quot;&gt;# Start the server&lt;/span&gt;
bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rails server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This file has to be executable, so in your terminal:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x ./entrypoint.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s all.&lt;/p&gt;

&lt;p&gt;Since there are no more modifications to be done in our &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt;, make sure its contents are the following:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ruby:2.6.2-stretch&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Copy application code&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; . /application&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Change to the application's directory&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /application&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Install gems&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--deployment&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--without&lt;/span&gt; development &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Set Rails environment to production&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; RAILS_ENV production&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;curl &lt;span class=&quot;nt&quot;&gt;-sL&lt;/span&gt; https://deb.nodesource.com/setup_10.x | bash - &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; nodejs

&lt;span class=&quot;c&quot;&gt;# Start the application server&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ./entrypoint.sh&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;compacting-the-dockerfile&quot;&gt;Compacting the Dockerfile&lt;/h3&gt;

&lt;p&gt;We will optimize the &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; since each &lt;code class=&quot;highlighter-rouge&quot;&gt;RUN&lt;/code&gt; command creates a new image (read more &lt;a href=&quot;http://goinbigdata.com/docker-run-vs-cmd-vs-entrypoint/&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We will merge the &lt;code class=&quot;highlighter-rouge&quot;&gt;RUN&lt;/code&gt; commands in one and move the &lt;code class=&quot;highlighter-rouge&quot;&gt;ENV&lt;/code&gt; command just before it. The resulting &lt;code class=&quot;highlighter-rouge&quot;&gt;Dockerfile&lt;/code&gt; is:&lt;/p&gt;

&lt;div class=&quot;language-docker highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;FROM&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ruby:2.6.2-stretch&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Copy application code&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;COPY&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; . /application&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Change to the application's directory&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;WORKDIR&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; /application&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Set Rails environment to production&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENV&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; RAILS_ENV production&lt;/span&gt;

&lt;span class=&quot;c&quot;&gt;# Install gems, nodejs and precompile the assets&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;bundle &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--deployment&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--without&lt;/span&gt; development &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; curl &lt;span class=&quot;nt&quot;&gt;-sL&lt;/span&gt; https://deb.nodesource.com/setup_10.x | bash - &lt;span class=&quot;se&quot;&gt;\
&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; nodejs

&lt;span class=&quot;c&quot;&gt;# Start the application server&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;ENTRYPOINT&lt;/span&gt;&lt;span class=&quot;s&quot;&gt; ['./entrypoint.sh']&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;running-the-application-in-the-docker-environment&quot;&gt;Running the application in the Docker environment&lt;/h2&gt;

&lt;h3 id=&quot;creating-the-postgresql-container&quot;&gt;Creating the PostgreSQL container&lt;/h3&gt;

&lt;p&gt;We are going to create a container for the PostgreSQL database.&lt;/p&gt;

&lt;p&gt;We need to specify two environment variables to configure a user for our application: &lt;code class=&quot;highlighter-rouge&quot;&gt;POSTGRES_USER&lt;/code&gt; and &lt;code class=&quot;highlighter-rouge&quot;&gt;POSTGRES_PASSWORD&lt;/code&gt;. The values of these environment variables will be used later on when &lt;a href=&quot;#creating-the-applications-container&quot;&gt;creating the application’s container&lt;/a&gt;.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker run &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; rails-chat-tutorial-pg
            &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;POSTGRES_USER&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;postgres
            &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;postgres
            &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 5432:5432
            &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; postgres
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Since the image doesn’t exist locally, Docker will fetch it from the &lt;a href=&quot;https://hub.docker.com/_/postgres&quot;&gt;Official Docker images&lt;/a&gt; and then it will create a container, binding the PostgreSQL default port &lt;code class=&quot;highlighter-rouge&quot;&gt;5432&lt;/code&gt; to the &lt;strong&gt;same port of the host&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt; I suggest you read this &lt;a href=&quot;https://hub.docker.com/_/postgres#how-to-extend-this-image&quot;&gt;documentation&lt;/a&gt; if you want to familiarize yourself with the options you have for customizing the container (volumes/database configuration etc).&lt;/p&gt;

&lt;h3 id=&quot;creating-the-redis-container&quot;&gt;Creating the Redis container&lt;/h3&gt;

&lt;p&gt;To create the &lt;code class=&quot;highlighter-rouge&quot;&gt;redis&lt;/code&gt; container, all we have to do is run the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker run &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; rails-chat-tutorial-redis &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 6379:6379 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; redis
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Again, since the image doesn’t exist locally, Docker will fetch it from the &lt;a href=&quot;https://hub.docker.com/_/redis&quot;&gt;Official Docker images&lt;/a&gt; and then it will create a container, binding its &lt;code class=&quot;highlighter-rouge&quot;&gt;6376&lt;/code&gt; to the &lt;strong&gt;same port of the host&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&quot;creating-the-applications-container&quot;&gt;Creating the application’s container&lt;/h3&gt;

&lt;p&gt;At this point, your docker running containers should look like this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker ps

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
&amp;lt;a container &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;    redis               &lt;span class=&quot;s2&quot;&gt;&quot;docker-entrypoint.s…&quot;&lt;/span&gt;   2 minutes ago       Up 2 minutes        0.0.0.0:6379-&amp;gt;6379/tcp   rails-chat-tutorial-redis
&amp;lt;a container &lt;span class=&quot;nb&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;    postgres            &lt;span class=&quot;s2&quot;&gt;&quot;docker-entrypoint.s…&quot;&lt;/span&gt;   2 minutes ago       Up 2 minutes        0.0.0.0:5432-&amp;gt;5432/tcp   rails-chat-tutorial-pg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;Rails chat tutorial&lt;/code&gt; in production mode needs the following environmental variables:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;em&gt;database.yml&lt;/em&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;DATABASE_HOST&lt;/strong&gt;: 172.17.0.1&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;DATABASE_PORT&lt;/strong&gt;: 5432&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;DATABASE_USERNAME&lt;/strong&gt;: postgres&lt;/li&gt;
      &lt;li&gt;&lt;strong&gt;DATABASE_PASSWORD&lt;/strong&gt;: postgres&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;em&gt;cable.yml&lt;/em&gt;
    &lt;ul&gt;
      &lt;li&gt;&lt;strong&gt;REDIS_URL&lt;/strong&gt;: redis://172.17.0.1:6379/1&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To create the container for the image that we created in this post passing the required environment variables, use:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker run &lt;span class=&quot;nt&quot;&gt;--name&lt;/span&gt; rails-chat-tutorial-web &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;DATABASE_HOST&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;172.17.0.1 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;DATABASE_PORT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;5432 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;DATABASE_USERNAME&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;postgres &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;DATABASE_PASSWORD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;postgres &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;REDIS_URL&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;redis://172.17.0.1:6379/1 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 3000:3000 &lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;
            rails-chat-tutorial
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: we bound the container’s &lt;code class=&quot;highlighter-rouge&quot;&gt;3000&lt;/code&gt; port on the same port of the host.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code class=&quot;highlighter-rouge&quot;&gt;http://localhost:3000&lt;/code&gt; and see what happens.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/dockerizing-rails/01.png&quot; alt=&quot;Error&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We don’t get very helpful information on the error since the application is running in production mode (at least this worked :P). Let’s connect to the container and check the logs:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;docker &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-it&lt;/span&gt; rails-chat-tutorial-web bash
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now you are connected to the container. Check the &lt;code class=&quot;highlighter-rouge&quot;&gt;/application/production.log&lt;/code&gt; file. Somewhere among all these lines you will see the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-log&quot;&gt;ActiveRecord::StatementInvalid (PG::UndefinedTable: ERROR:  relation users does not exist
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We set up the database server but we didn’t create/migrate the database. Since we are already connected to the container we will execute the required rake tasks.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rake db:create db:migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;a href=&quot;https://twitter.com/lazaru_s/status/1182193506430984193&quot;&gt;Reload the page and voilà&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/dockerizing-rails/02.png&quot; alt=&quot;Application home page&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s next&lt;/h2&gt;

&lt;p&gt;In the next tutorial we are going to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;refactor this image for production (use volume for postgreSQL, asset precompilation)&lt;/li&gt;
  &lt;li&gt;use &lt;a href=&quot;https://www.nginx.com/&quot;&gt;nginx&lt;/a&gt; to serve them&lt;/li&gt;
  &lt;li&gt;use &lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;docker compose&lt;/a&gt; to bind them all.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;thanks&quot;&gt;Thanks&lt;/h2&gt;

&lt;p&gt;I am very grateful for your feedback (like this one from &lt;a href=&quot;https://www.reddit.com/r/docker/comments/baerrf/dockerizing_a_rails_application/&quot;&gt;DeusOtiosus
 @ Reddit&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;That’s all! Cat photo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/programming-cat/terminator.png&quot; alt=&quot;Irida&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;alert alert-light&quot;&gt;
  &lt;div class=&quot;alert-heading&quot;&gt;&lt;i class=&quot;fa fa-comments&quot;&gt;&lt;/i&gt; Code and comments&lt;/div&gt;

  You can find the code of this tutorial on &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/rails-chat-tutorial&quot;&gt;&lt;i class=&quot;fa fa-github&quot;&gt;&lt;/i&gt; https://github.com/iridakos/rails-chat-tutorial&lt;/a&gt; on branch &lt;strong&gt;docker&lt;/strong&gt;.

  &lt;hr /&gt;

  For feedback, comments, typos etc. please open an &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues&quot;&gt;issue&lt;/a&gt; in the repository.

  &lt;hr /&gt;

  &lt;strong&gt;Thanks for visiting!&lt;/strong&gt;
&lt;/div&gt;
</description>
        <pubDate>Sun, 07 Apr 2019 04:00:00 +0300</pubDate>
        <link>https://iridakos.com/programming/2019/04/07/dockerizing-a-rails-application</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/04/07/dockerizing-a-rails-application</guid>
        
        <category>ruby</category>
        
        <category>rails</category>
        
        <category>docker</category>
        
        <category>actioncable</category>
        
        <category>postgresql</category>
        
        <category>postgres</category>
        
        <category>redis</category>
        
        <category>chat</category>
        
        <category>tutorial</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Creating a chat application from scratch using Rails and WebSockets</title>
        <description>&lt;p&gt;Hey! It’s been a while since my last post.&lt;/p&gt;

&lt;p&gt;I recently familiarized myself with the awesomeness of WebSockets and I finally found the time to write a tutorial about it. I hope you find it helpful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Update&lt;/strong&gt;: I also published another post for &lt;a href=&quot;https://twitter.com/lazaru_s/status/1182193506430984193&quot;&gt;dockerizing the application&lt;/a&gt;  of this tutorial, you can find it &lt;a href=&quot;/programming/2019/04/07/dockerizing-a-rails-application&quot;&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;introduction&quot;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;In this tutorial we are going to create a &lt;strong&gt;chat&lt;/strong&gt; web application from scratch using Rails and WebSockets.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/rails-chat-tutorial.gif&quot; alt=&quot;Rails chat tutorial gif&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;alert alert-light&quot;&gt;
  &lt;div class=&quot;alert-heading&quot;&gt;&lt;i class=&quot;fa fa-comments&quot;&gt;&lt;/i&gt; Code and comments&lt;/div&gt;

  You can find the code of this tutorial on &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/rails-chat-tutorial&quot;&gt;&lt;i class=&quot;fa fa-github&quot;&gt;&lt;/i&gt; GitHub&lt;/a&gt;.

  &lt;hr /&gt;

  For feedback, comments, typos etc. please open an &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues&quot;&gt;issue&lt;/a&gt; in the repository.
&lt;/div&gt;

&lt;h3 id=&quot;what-are-websockets&quot;&gt;What are WebSockets&lt;/h3&gt;

&lt;p&gt;WebSocket is actually a protocol that enables bidirectional communication between the client and the server of a web application over a single long living TCP connection.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The WebSocket protocol enables interaction between a web browser (or other client application) and a web server &lt;strong&gt;with lower overheads, facilitating real-time data transfer from and to the server&lt;/strong&gt;.
&lt;br /&gt;&lt;br /&gt;This is made possible by providing a standardized way for the server to send content to the client without being first requested by the client, and allowing messages to be passed back and forth while keeping the connection open. In this way, a two-way ongoing conversation can take place between the client and the server.&lt;br /&gt;&lt;br /&gt;The communications are done over TCP port number 80 (or 443 in the case of TLS-encrypted connections), which is of benefit for those environments which block non-web Internet connections using a firewall. Similar two-way browser-server communications have been achieved in non-standardized ways using stopgap technologies such as Comet.
&lt;cite&gt;– &lt;a href=&quot;https://en.wikipedia.org/wiki/WebSocket&quot;&gt;WebSocket @ Wikipedia&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;why-websockets&quot;&gt;Why WebSockets&lt;/h3&gt;

&lt;p&gt;Suppose you have to create a web page that shows the statuses of running processes.
Without WebSockets you would have to either:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Use AJAX with Javascript intervals to request and render the latest state of the processes or&lt;/li&gt;
  &lt;li&gt;Automatically reload the page every x seconds (&lt;code class=&quot;highlighter-rouge&quot;&gt;&amp;lt;meta http-equiv=&quot;refresh&quot; content=&quot;x&quot;&amp;gt;&lt;/code&gt;) or&lt;/li&gt;
  &lt;li&gt;Add a message on the page &lt;em&gt;“The statuses are not updated automatically &lt;span class=&quot;text-nowrap&quot;&gt;¯\_(ツ)_/¯&lt;/span&gt; Press &lt;a href=&quot;/programming/2019/04/04/creating-chat-application-rails-websockets&quot;&gt;here&lt;/a&gt; to reload the page.”&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of these methods would request the process statuses from the server even if nothing has changed.&lt;/p&gt;

&lt;p&gt;WebSockets are here to allow this communication to take place on demand. The cost is having to keep alive TCP connections between the server and all its clients (each for every open browser tab).&lt;/p&gt;

&lt;h2 id=&quot;building-the-application&quot;&gt;Building the application&lt;/h2&gt;

&lt;p&gt;We are going to build the web application using:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Ruby&lt;/strong&gt;: version &lt;strong&gt;2.6.2&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Rails&lt;/strong&gt;: version &lt;strong&gt;5.2.3&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;setting-up-the-environment&quot;&gt;Setting up the environment&lt;/h3&gt;

&lt;p&gt;We are going to install the proper ruby and rails versions.&lt;/p&gt;

&lt;h4 id=&quot;install-ruby&quot;&gt;Install ruby&lt;/h4&gt;

&lt;p&gt;I use &lt;a href=&quot;https://rvm.io/&quot;&gt;rvm&lt;/a&gt; to manage the &lt;strong&gt;Ruby&lt;/strong&gt; versions installed on my system. To install the desired ruby version use:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rvm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;ruby 2.6.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;install-rails&quot;&gt;Install rails&lt;/h4&gt;

&lt;p&gt;Create a directory in your system with the name &lt;code class=&quot;highlighter-rouge&quot;&gt;rails-chat-tutorial&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Navigate to that directory&lt;/strong&gt; and create the following two files:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;.ruby-version&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;ruby-2.6.2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;.ruby-gemset&lt;/em&gt;&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails-chat-tutorial
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;With these file we are letting &lt;em&gt;rvm&lt;/em&gt; know that when working on this directory, we want to use the specific ruby version (&lt;code class=&quot;highlighter-rouge&quot;&gt;.ruby-version&lt;/code&gt;) and the gems from the specific gemset (&lt;code class=&quot;highlighter-rouge&quot;&gt;.ruby-gemset&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;Now, re-entering in the directory you should see something like this:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ cd .

ruby-2.6.2 - #gemset created /home/iridakos/.rvm/gems/ruby-2.6.2@rails-chat-tutorial
ruby-2.6.2 - #generating rails-chat-tutorial wrappers...........
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Install the desired rails version with:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;gem install rails -v 5.2.3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;create-the-rails-application&quot;&gt;Create the rails application&lt;/h4&gt;

&lt;p&gt;We are ready to create our new &lt;em&gt;rails&lt;/em&gt; application:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails new .
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: We didn’t define a name for the application and rails will resolve it using the directory name: &lt;code class=&quot;highlighter-rouge&quot;&gt;rails-chat-tutorial&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Rails will create all the application’s files and install the required gems.&lt;/p&gt;

&lt;p&gt;Let’s start the application to make sure that everything is fine.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You should see something like:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;=&amp;gt; Booting Puma
=&amp;gt; Rails 5.2.3 application starting in development
=&amp;gt; Run `rails server -h` for more startup options
Puma starting in single mode...
* Version 3.12.1 (ruby 2.6.2-p47), codename: Llamas in Pajamas
* Min threads: 5, max threads: 5
* Environment: development
* Listening on tcp://localhost:3000
Use Ctrl-C to stop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Open a browser and visit &lt;code class=&quot;highlighter-rouge&quot;&gt;http://localhost:3000&lt;/code&gt;, if you see this we are good to go.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/01-rails-new.png&quot; alt=&quot;Rails new application&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;users-and-devise&quot;&gt;Users and devise&lt;/h3&gt;

&lt;p&gt;We are going to use the awesome &lt;a href=&quot;https://github.com/plataformatec/devise&quot;&gt;devise&lt;/a&gt; solution for authentication.&lt;/p&gt;

&lt;p&gt;Append the following gem requirement at the bottom of the &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; file located at the root of the application’s directory.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'devise'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;On your terminal, install the new gem by executing:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;bundle
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finish integration with devise using:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails generate devise:install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We will create the model representing our users using the devise generators.&lt;/p&gt;

&lt;p&gt;On your terminal, execute:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails generate devise User username:string
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: we have added an extra attribute &lt;code class=&quot;highlighter-rouge&quot;&gt;username&lt;/code&gt; to our model (besides the defaults generated by devise) so that we have something more friendly to present when displaying users instead of their email.&lt;/p&gt;

&lt;p&gt;Open the generated migration which you will find under &lt;code class=&quot;highlighter-rouge&quot;&gt;db/migrate/&amp;lt;datetime&amp;gt;_devise_create_users.rb&lt;/code&gt; and append the username’s unique index definition with&lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[4]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;add_index&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:users&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;             &lt;span class=&quot;ss&quot;&gt;unique: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Find the line in the file that defines the &lt;code class=&quot;highlighter-rouge&quot;&gt;username&lt;/code&gt; column and change it to:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;string&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;null: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to make the attribute required.&lt;/p&gt;

&lt;p&gt;Then in the User model which is located at &lt;code class=&quot;highlighter-rouge&quot;&gt;app/models/user.rb&lt;/code&gt; add the validation rule for uniqueness and presence:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;validates&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;uniqueness: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;presence: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, apply the database migration using:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails db:migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;rooms-and-messages&quot;&gt;Rooms and messages&lt;/h3&gt;

&lt;p&gt;Each chat message is going to take place in the context of a room.&lt;/p&gt;

&lt;p&gt;Let’s build them all.&lt;/p&gt;

&lt;p&gt;Use the following command to create the &lt;code class=&quot;highlighter-rouge&quot;&gt;Room&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails generate resource Room name:string:uniq
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and the following command to create the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomMessage&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails generate resource RoomMessage room:references user:references message:text
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We are now going to define the appropriate relations&lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[7]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/models/room.rb&lt;/code&gt; and add the relation inside the class:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;has_many&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:room_messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;dependent: :destroy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                         &lt;span class=&quot;ss&quot;&gt;inverse_of: :room&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/models/room_message.rb&lt;/code&gt; and add the relations inside the class:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;belongs_to&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;inverse_of: :room_messages&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Migrate the database with:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails db:migrate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We can now setup our routes so that the root request is served by the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomsController#index&lt;/code&gt; action.&lt;/p&gt;

&lt;p&gt;Open your &lt;code class=&quot;highlighter-rouge&quot;&gt;config/routes.rb&lt;/code&gt; file and change its contents to:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;Rails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;application&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;routes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;devise_for&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:users&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;root&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;controller: :rooms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;action: :index&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;resources&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:room_messages&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;resources&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rooms&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Restart the server and try to navigate to the application’s root url.&lt;/p&gt;

&lt;p&gt;You should see an error message, no worries:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/02.png&quot; alt=&quot;No action index for the RoomsController&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We have to create the &lt;code class=&quot;highlighter-rouge&quot;&gt;index&lt;/code&gt; action in the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomsController&lt;/code&gt;. Open the controller &lt;code class=&quot;highlighter-rouge&quot;&gt;app/controllers/rooms_controller.rb&lt;/code&gt; and change its contents to the following:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then create the file &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/index.html.erb&lt;/code&gt; and for now just add the following:&lt;/p&gt;
&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Rooms index&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Reload and voilà.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/03.png&quot; alt=&quot;Rooms index&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;adding-authentication&quot;&gt;Adding authentication&lt;/h3&gt;

&lt;p&gt;We want all users to be authenticated before start chatting, so we are going to add the following line in the &lt;code class=&quot;highlighter-rouge&quot;&gt;ApplicationController&lt;/code&gt; located at &lt;em&gt;app/controllers/application_controller.rb&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;n&quot;&gt;before_action&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:authenticate_user!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we navigate to &lt;code class=&quot;highlighter-rouge&quot;&gt;http://localhost:3000&lt;/code&gt; now we should be redirected to the sign in page &lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[10]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/04.png&quot; alt=&quot;Sign in&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Before continuing with the good stuff, let’s gear up the application with some good features.&lt;/p&gt;

&lt;h3 id=&quot;add-bootstrap&quot;&gt;Add bootstrap&lt;/h3&gt;

&lt;p&gt;We are going to use &lt;a href=&quot;https://getbootstrap.com/&quot;&gt;Bootstrap&lt;/a&gt; and we will integrate it in the application using the &lt;a href=&quot;https://github.com/twbs/bootstrap-rubygem&quot;&gt;bootstrap-rubygem&lt;/a&gt; gem.&lt;/p&gt;

&lt;p&gt;Following the instructions of the gem, append the dependencies in your &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'bootstrap'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'~&amp;gt; 4.3.1'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'jquery-rails'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;and execute &lt;code class=&quot;highlighter-rouge&quot;&gt;bundle&lt;/code&gt; to fetch and install it.&lt;/p&gt;

&lt;p&gt;Change the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/stylesheets/application.css&lt;/code&gt; file’s extension to &lt;code class=&quot;highlighter-rouge&quot;&gt;scss&lt;/code&gt; and &lt;strong&gt;replace its contents&lt;/strong&gt; with:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;@import&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&quot;bootstrap&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Add the following lines to the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/javascript/application.js&lt;/code&gt; just before the &lt;code class=&quot;highlighter-rouge&quot;&gt;//= require_tree .&lt;/code&gt; line&lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[9]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//= require jquery3&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//= require popper&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;//= require bootstrap-sprockets&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;add-simple_form&quot;&gt;Add simple_form&lt;/h3&gt;

&lt;p&gt;We are going to use this great gem to generate forms easily.&lt;/p&gt;

&lt;p&gt;Append the gem dependency in your &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; and bundle to install it.&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'simple_form'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then complete the integration using:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails generate simple_form:install &lt;span class=&quot;nt&quot;&gt;--bootstrap&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: We used the &lt;em&gt;–bootstrap&lt;/em&gt; directive since that’s the framework we are using.&lt;/p&gt;

&lt;h3 id=&quot;devise-views-with-bootstrap-and-simple-form&quot;&gt;Devise views with bootstrap and simple form&lt;/h3&gt;

&lt;p&gt;Devise uses its own views for sign in, register etc. But we do have a way to customize these views and now that we have ended up using bootstrap and simple forms, we can generate these views in a way that our choices are respected.&lt;/p&gt;

&lt;p&gt;In your terminal:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails generate devise:views
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The view for signing in is under &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/devise/sessions/new.html.erb&lt;/code&gt; and for signing up is under &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/devise/registrations/new.html.erb&lt;/code&gt;. Open these two files and change the submit button’s class by replacing the following line&lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[6]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Sign up&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;with&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:submit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Sign up&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'btn btn-success'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to render the buttons &lt;em&gt;bootstrap style&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Before viewing our changes, let’s do one last thing in our default layout.&lt;/p&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/layouts/application.html.erb&lt;/code&gt; and replace its contents with:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;RailsChatTutorial&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csrf_meta_tags&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csp_meta_tag&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stylesheet_link_tag&lt;/span&gt;    &lt;span class=&quot;s1&quot;&gt;'application'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;media: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'all'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'data-turbolinks-track'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'reload'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;javascript_include_tag&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'application'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'data-turbolinks-track'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'reload'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-12&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This last one was to use &lt;a href=&quot;https://getbootstrap.com/docs/4.0/layout/grid/&quot;&gt;Bootstrap’s grid&lt;/a&gt; in our views.&lt;/p&gt;

&lt;p&gt;Navigate to &lt;code class=&quot;highlighter-rouge&quot;&gt;http://localhost:3000&lt;/code&gt; and view what we have created.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/05.png&quot; alt=&quot;Sign in with Devise and simple form&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s try to sign up following the &lt;code class=&quot;highlighter-rouge&quot;&gt;Sign up&lt;/code&gt; link of the form:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/06.png&quot; alt=&quot;Sign up without username&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you can see, there is no field to fill in the username. For that to work we have to:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Add the field in the sign up form&lt;/li&gt;
  &lt;li&gt;Configure devise to accept the new attribute (&lt;code class=&quot;highlighter-rouge&quot;&gt;username&lt;/code&gt;) or else the &lt;code class=&quot;highlighter-rouge&quot;&gt;ApplicationController&lt;/code&gt; will &lt;a href=&quot;https://api.rubyonrails.org/classes/ActionController/Parameters.html&quot;&gt;ignore it&lt;/a&gt; once submitted from the form.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To add the field in the sign up form, open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/devise/registrations/new.html.erb&lt;/code&gt; and add these lines between the email and password fields.&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
              &lt;span class=&quot;ss&quot;&gt;required: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, open the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/controllers/application_controller.rb&lt;/code&gt; file to configure the new attribute. Change the contents to:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ApplicationController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionController&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before_action&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:authenticate_user!&lt;/span&gt;

  &lt;span class=&quot;n&quot;&gt;before_action&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:configure_permitted_parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;if: :devise_controller?&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;protected&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;configure_permitted_parameters&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;devise_parameter_sanitizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;permit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sign_up&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;keys: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Done, reload and sign up&lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[5]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/07.png&quot; alt=&quot;Sign up with username&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;cleanup-unused-components&quot;&gt;Cleanup unused components&lt;/h3&gt;

&lt;p&gt;We will not be using &lt;code class=&quot;highlighter-rouge&quot;&gt;coffee script&lt;/code&gt; or &lt;code class=&quot;highlighter-rouge&quot;&gt;turbolinks&lt;/code&gt; so let’s remove all the related stuff.&lt;/p&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt; and remove the following lines:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;# Use CoffeeScript for .coffee assets and views&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'coffee-rails'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'~&amp;gt; 4.2'&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;# Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'turbolinks'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'~&amp;gt; 5'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/javascripts/application.js&lt;/code&gt; and remove the following line:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;//= require turbolinks&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/layouts/application.html.erb&lt;/code&gt; and change the following lines &lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[3]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stylesheet_link_tag&lt;/span&gt;    &lt;span class=&quot;s1&quot;&gt;'application'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;media: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'all'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'data-turbolinks-track'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'reload'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;javascript_include_tag&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'application'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'data-turbolinks-track'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'reload'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stylesheet_link_tag&lt;/span&gt;    &lt;span class=&quot;s1&quot;&gt;'application'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;media: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'all'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;javascript_include_tag&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'application'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Check that your &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/javascripts&lt;/code&gt; folder doesn’t have any files with extension &lt;code class=&quot;highlighter-rouge&quot;&gt;.coffee&lt;/code&gt; and if you find any, remove them.&lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;2&lt;/a&gt;&lt;sup&gt;&lt;/sup&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;In the terminal, also execute the following command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;rails tmp:cache:clear
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;to clear any cached compiled coffee scripts.&lt;/p&gt;

&lt;p&gt;Done. Restart you server.&lt;/p&gt;

&lt;h3 id=&quot;adding-a-navigation-bar&quot;&gt;Adding a navigation bar&lt;/h3&gt;

&lt;p&gt;To improve the usability of the web pages will add a top &lt;a href=&quot;https://getbootstrap.com/docs/4.0/components/navbar/&quot;&gt;navigation bar&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create the directory &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/shared&lt;/code&gt; and a file inside it named &lt;code class=&quot;highlighter-rouge&quot;&gt;_navigation_bar.html.erb&lt;/code&gt;. This is going to be the partial responsible for rendering the navigation bar and which later on we will add to the application’s default layout in order to be rendered on all web pages. Add these contents:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;nav&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar navbar-expand-lg navbar-dark bg-dark justify-content-between&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar-brand&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;Rails chat tutorial&lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;button&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar-toggler&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;button&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-toggle=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;collapse&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-target=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#nav-bar-collapse&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;aria-controls=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbarColor01&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;aria-expanded=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;aria-label=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Toggle navigation&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbar-toggler-icon&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dropdown&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;a&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav-link dropdown-toggle&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;href=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;#&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbarDropdown&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;role=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;button&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-toggle=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dropdown&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;aria-haspopup=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;true&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;aria-expanded=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;avatar&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gravatar_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;username&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;dropdown-menu dropdown-menu-right&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;aria-labelledby=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;navbarDropdown&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Logout'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;destroy_user_session_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;method: :delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'dropdown-item'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Mind the &lt;code class=&quot;highlighter-rouge&quot;&gt;gravatar_url(current_user)&lt;/code&gt; line. This is a helper method that we are going to use in order to resolve the gravatar url of the signed in user. This is not a builtin method, we have to defined it but it’s pretty straightforward.&lt;/p&gt;

&lt;p&gt;Edit &lt;code class=&quot;highlighter-rouge&quot;&gt;app/helpers/application_helper.rb&lt;/code&gt; and add the following method:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;gravatar_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;gravatar_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Digest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MD5&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;hexdigest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;downcase&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://gravatar.com/avatar/&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gravatar_id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.png&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;As you can see, the user’s username, avatar and sign out link will only be rendered if the user is signed in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The avatar image has a css class &lt;code class=&quot;highlighter-rouge&quot;&gt;avatar&lt;/code&gt;. We have to define this class in the application’s stylesheets. Create a css file in which we will gather all css class that we will use in the application under the name &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/stylesheets/rails-chat-tutorial.scss&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For now add the rule for the avatar:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.avatar&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;max-height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;30px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;15px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;vertical-align&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;middle&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and open &lt;code class=&quot;highlighter-rouge&quot;&gt;application.scss&lt;/code&gt; to import the newly created stylesheet. Add the line:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;@import &quot;rails-chat-tutorial&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We have to add this partial in the application layout. Edit &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/layouts/application.html.erb&lt;/code&gt; and change its contents to:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;RailsChatTutorial&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csrf_meta_tags&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;csp_meta_tag&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;stylesheet_link_tag&lt;/span&gt;    &lt;span class=&quot;s1&quot;&gt;'application'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;media: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'all'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;javascript_include_tag&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'application'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-12&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;partial: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'shared/navigation_bar'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;my-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Reload to view the bar.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/08.png&quot; alt=&quot;Sign up with navigation bar&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Awesome. Fill in with your desired credentials and submit the form.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/09.png&quot; alt=&quot;Signed in&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;room-management&quot;&gt;Room management&lt;/h3&gt;

&lt;p&gt;We are going to create a simple layout for groups.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;One narrow column displaying vertically all the available rooms&lt;/li&gt;
  &lt;li&gt;One wide column which is going to host the chat messages and form.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rooms index page will have the second column empty since this column will be present only when user is inside a specific room.&lt;/p&gt;

&lt;p&gt;In the index page we will provide the option to create a room.&lt;/p&gt;

&lt;h4 id=&quot;room-index&quot;&gt;Room index&lt;/h4&gt;

&lt;p&gt;First we have to load all rooms in the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomsController&lt;/code&gt;. Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/controllers/rooms_controller.rb&lt;/code&gt; and change the index action as:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@rooms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/index.html.erb&lt;/code&gt; and change its contents to&lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[8]&lt;/a&gt;&lt;/sup&gt;:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-12 col-md-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mb-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_room_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;btn btn-primary&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        Create a room
      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@rooms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;nav&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav flex-column&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@rooms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;nav-link room-nav-link&quot;&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text-muted&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        The are no rooms
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;alert alert-primary&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;h4&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;alert-heading&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        Welcome to the RailsChatTutorial!
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        We need to talk.
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;hr&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        You can create or join a room from the sidebar.
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If there are rooms, the left column of the page will render a vertical navigation with links leading to each room’s page. The right column displays a simple welcome message.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/10.png&quot; alt=&quot;Room index&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pressing the &lt;code class=&quot;highlighter-rouge&quot;&gt;Create a room&lt;/code&gt; button we get the expected error for the non-existent action.&lt;/p&gt;

&lt;h4 id=&quot;room-newedit&quot;&gt;Room new/edit&lt;/h4&gt;

&lt;p&gt;We have to define the actions for creating and updating a room.&lt;/p&gt;

&lt;p&gt;Open the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/controllers/rooms_controller.rb&lt;/code&gt; and change its contents to:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomsController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# Loads:&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# @rooms = all rooms&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;# @room = current room when applicable&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before_action&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:load_entities&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@rooms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;permitted_parameters&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;flash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Room &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; was created successfully&quot;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rooms_path&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:new&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;edit&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;update&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;update_attributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;permitted_parameters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;flash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:success&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Room &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; was updated successfully&quot;&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;redirect_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rooms_path&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:new&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;protected&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load_entities&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@rooms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;all&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;permitted_parameters&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;require&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;permit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: we preload the &lt;code class=&quot;highlighter-rouge&quot;&gt;@rooms&lt;/code&gt; and the &lt;code class=&quot;highlighter-rouge&quot;&gt;@room&lt;/code&gt; variables making them available to all actions with the &lt;code class=&quot;highlighter-rouge&quot;&gt;before_action :load_entities&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;We will create a simple form for the &lt;code class=&quot;highlighter-rouge&quot;&gt;Room&lt;/code&gt; object and we will use it both when creating and editing a room. Create the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/_form.html.erb&lt;/code&gt; and add:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;simple_form_for&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;submit&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Save&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'btn btn-success'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Then, create the views for the &lt;code class=&quot;highlighter-rouge&quot;&gt;new&lt;/code&gt;/&lt;code class=&quot;highlighter-rouge&quot;&gt;edit&lt;/code&gt; action accordingly:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/rooms/new.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
  Creating a room  
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;partial: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'form'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;app/views/rooms/edit.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
  Editing room &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;partial: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'form'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Time to create the first room. From the rooms’ index page, press the &lt;code class=&quot;highlighter-rouge&quot;&gt;Create a room&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/11.png&quot; alt=&quot;New room&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Save and here it is.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/12.png&quot; alt=&quot;Room index with rooms&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Add this class in &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/stylesheets/rails-chat-tutorial.scss&lt;/code&gt; to improve the display of the rooms.&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.room-nav-link&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lighten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;40%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lighten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;45%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;err&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;.room-nav-link&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;border-top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/13.png&quot; alt=&quot;Room index with improved rooms&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: We will add the &lt;code class=&quot;highlighter-rouge&quot;&gt;edit&lt;/code&gt; link in the room’s page a.k.a. &lt;code class=&quot;highlighter-rouge&quot;&gt;show&lt;/code&gt; action.&lt;/p&gt;

&lt;p&gt;Before moving on to the Room page, we will refactor the index page so as to be able to use the left column’s content inside the room page as well.&lt;/p&gt;

&lt;p&gt;Create the partial &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/_rooms.html.erb&lt;/code&gt; with contents:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mb-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new_room_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'btn btn-primary'&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    Create a room
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@rooms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;present?&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;nav&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;nav flex-column&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@rooms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;link_to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'nav-link room-nav-link'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text-muted&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    The are no rooms
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and change the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/index.html.erb&lt;/code&gt; to use it:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-12 col-md-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;partial: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rooms'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;alert alert-primary&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;h4&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;alert-heading&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        Welcome to the RailsChatTutorial!
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/h4&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        We need to talk.
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;hr&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
        You can create or join a room from the sidebar.
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h4 id=&quot;room-page&quot;&gt;Room page&lt;/h4&gt;

&lt;p&gt;Add the &lt;code class=&quot;highlighter-rouge&quot;&gt;show&lt;/code&gt; action in the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/controllers/rooms_controller.rb&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;show&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@room_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RoomMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;room: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@room_messages&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;room_messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;includes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;We construct a new room message which we are going to use in the view to build a form for creating the chat messages.&lt;/li&gt;
  &lt;li&gt;When displaying the room message, we access its user’s email attribute to resolve the gravatar hash. We used &lt;code class=&quot;highlighter-rouge&quot;&gt;.includes(:user)&lt;/code&gt; in the query for the &lt;code class=&quot;highlighter-rouge&quot;&gt;@room_messages&lt;/code&gt; to fetch them along with their users avoiding &lt;a href=&quot;https://medium.com/@bretdoucette/n-1-queries-and-how-to-avoid-them-a12f02345be5&quot;&gt;N+1 queries&lt;/a&gt;&lt;sup&gt;&lt;a href=&quot;#acknowledgments&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Create the view &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/show.html.erb&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-12 col-md-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;partial: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rooms'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;chat&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room_messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;room_message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room_message&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;simple_form_for&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;remote: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;input-group mb-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;as: :string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;ss&quot;&gt;wrapper: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;ss&quot;&gt;label: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;ss&quot;&gt;input_html: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                                   &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'chat-input'&lt;/span&gt;
                                 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;input-group-append&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;submit&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Send&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'btn btn-primary chat-input'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:room_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;as: :hidden&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;We reused the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/_rooms.html.erb&lt;/code&gt; partial that we created in the previous step&lt;/li&gt;
  &lt;li&gt;We added a &lt;code class=&quot;highlighter-rouge&quot;&gt;div&lt;/code&gt; with class &lt;code class=&quot;highlighter-rouge&quot;&gt;.chat&lt;/code&gt; and this is where the room’s messages are rendered.&lt;/li&gt;
  &lt;li&gt;We added a form for the &lt;code class=&quot;highlighter-rouge&quot;&gt;@room_message&lt;/code&gt; that we instantiated in the controller. We also used the directive &lt;code class=&quot;highlighter-rouge&quot;&gt;remote: true&lt;/code&gt; when we instantiated the form thus the form is going to be submitted by &lt;strong&gt;Ajax&lt;/strong&gt;.&lt;/li&gt;
  &lt;li&gt;We added a hidden field for the attribute &lt;code class=&quot;highlighter-rouge&quot;&gt;:room_id&lt;/code&gt; so that the value reaches the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomMessagesController&lt;/code&gt; once we submit the form.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Style the chat components by adding the following lines to the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/stylesheets/rails-chat-tutorial.scss&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.chat&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lighten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secondary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;40%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lighten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;secondary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50vh&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;overflow-y&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;auto&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.chat-input&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border-top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Navigate to a room to see what has been done.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/14.png&quot; alt=&quot;Room page with chat&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Pressing the &lt;code class=&quot;highlighter-rouge&quot;&gt;Send&lt;/code&gt; button nothing happens on the page but if you check the server’s console you will notice:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;AbstractController::ActionNotFound (The action 'create' could not be found for RoomMessagesController):
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s fix that.&lt;/p&gt;

&lt;h4 id=&quot;creating-room-messages&quot;&gt;Creating room messages&lt;/h4&gt;

&lt;p&gt;This is going to be easy. All we have to do is implement the &lt;code class=&quot;highlighter-rouge&quot;&gt;create&lt;/code&gt; action in the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomMessagesController&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/room_messages_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomMessagesController&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;before_action&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:load_entities&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@room_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RoomMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;user: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                       &lt;span class=&quot;ss&quot;&gt;room: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                       &lt;span class=&quot;ss&quot;&gt;message: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

  &lt;span class=&quot;kp&quot;&gt;protected&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load_entities&lt;/span&gt;
    &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:room_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;we preload the room using the &lt;code class=&quot;highlighter-rouge&quot;&gt;room_id&lt;/code&gt; parameter that we added as a hidden field in the form in the previous step&lt;/li&gt;
  &lt;li&gt;we create a new message for the room setting its user to the currently signed in user&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you try to submit a message now, again you will see nothing but in the server console you can see from the log that the room message has been created.&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Started POST &quot;/room_messages&quot; for ::1 at 2019-04-04 19:24:33 +0300
Processing by RoomMessagesController#create as JS
  Parameters: {&quot;utf8&quot;=&amp;gt;&quot;✓&quot;, &quot;room_message&quot;=&amp;gt;{&quot;message&quot;=&amp;gt;&quot;My first message&quot;, &quot;room_id&quot;=&amp;gt;&quot;8&quot;}, &quot;commit&quot;=&amp;gt;&quot;Send&quot;}
  User Load (0.2ms)  SELECT  &quot;users&quot;.* FROM &quot;users&quot; WHERE &quot;users&quot;.&quot;id&quot; = ? ORDER BY &quot;users&quot;.&quot;id&quot; ASC LIMIT ?  [[&quot;id&quot;, 1], [&quot;LIMIT&quot;, 1]]
  ↳ /home/iridakos/.rvm/gems/ruby-2.6.2@rails-chat-tutorial/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
  Room Load (0.2ms)  SELECT  &quot;rooms&quot;.* FROM &quot;rooms&quot; WHERE &quot;rooms&quot;.&quot;id&quot; = ? LIMIT ?  [[&quot;id&quot;, 8], [&quot;LIMIT&quot;, 1]]
  ↳ app/controllers/room_messages_controller.rb:13
   (0.1ms)  begin transaction
  ↳ app/controllers/room_messages_controller.rb:5
  RoomMessage Create (0.7ms)  INSERT INTO &quot;room_messages&quot; (&quot;room_id&quot;, &quot;user_id&quot;, &quot;message&quot;, &quot;created_at&quot;, &quot;updated_at&quot;) VALUES (?, ?, ?, ?, ?)  [[&quot;room_id&quot;, 8], [&quot;user_id&quot;, 1], [&quot;message&quot;, &quot;My first message&quot;], [&quot;created_at&quot;, &quot;2019-04-04 16:24:33.456641&quot;], [&quot;updated_at&quot;, &quot;2019-04-04 16:24:33.456641&quot;]]
  ↳ app/controllers/room_messages_controller.rb:5
   (4.0ms)  commit transaction
  ↳ app/controllers/room_messages_controller.rb:5
No template found for RoomMessagesController#create, rendering head :no_content
Completed 204 No Content in 88ms (ActiveRecord: 5.1ms)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;A user would expect to have the message field cleared after sending a new message. We don’t disappoint users.&lt;/p&gt;

&lt;p&gt;Create a file &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/javascripts/room.js&lt;/code&gt; and add the following:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;#new_room_message&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;ajax:success&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;input[type=&quot;text&quot;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;''&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We bind to the &lt;code class=&quot;highlighter-rouge&quot;&gt;ajax:success&lt;/code&gt; event triggered by &lt;a href=&quot;https://guides.rubyonrails.org/working_with_javascript_in_rails.html#form-with&quot;&gt;Rails&lt;/a&gt; on successful submission of the form and all we want to do is clear the text field’s value.&lt;/p&gt;

&lt;p&gt;Reload the page and try submitting again and check it out. The field value should be emptied after sending the message.&lt;/p&gt;

&lt;h4 id=&quot;displaying-room-messages&quot;&gt;Displaying room messages&lt;/h4&gt;

&lt;p&gt;If you reload the page you will see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/15.png&quot; alt=&quot;Room message to string&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s beautify the messages.&lt;/p&gt;

&lt;p&gt;Replace the contents of &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/show.html.erb&lt;/code&gt; with:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-12 col-md-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;partial: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'rooms'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;chat&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room_messages&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;room_message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;chat-message-container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row no-gutters&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-auto text-center&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gravatar_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;avatar&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

            &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;message-content&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mb-1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;message&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

                &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text-right&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class=&quot;nt&quot;&gt;&amp;lt;small&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;created_at&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
                  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
                &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
              &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;simple_form_for&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;remote: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;input-group mb-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;as: :string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;ss&quot;&gt;wrapper: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;ss&quot;&gt;label: &lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                 &lt;span class=&quot;ss&quot;&gt;input_html: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                                   &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'chat-input'&lt;/span&gt;
                                 &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;input-group-append&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;submit&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Send&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;class: &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'btn btn-primary chat-input'&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;form&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;input&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:room_id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;as: :hidden&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;cp&quot;&gt;&amp;lt;%&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;and add the following css classes &lt;strong&gt;inside the .chat class&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.chat-message-container&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;err&quot;&gt;.avatar&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;nc&quot;&gt;.message-content&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1px&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;solid&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;border-radius&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;5px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lighten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;primary&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10%&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;white&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;.chat-message-container&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;margin-top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;10px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Reload the page. Magic.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/16.png&quot; alt=&quot;Improved display of room messages&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;introducing-websockets---actioncable&quot;&gt;Introducing WebSockets - ActionCable&lt;/h2&gt;

&lt;p&gt;Time to start using WebSockets with ActionCable.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Action Cable seamlessly integrates WebSockets with the rest of your Rails application. It allows for real-time features to be written in Ruby in the same style and form as the rest of your Rails application, while still being performant and scalable. It’s a full-stack offering that provides both a client-side JavaScript framework and a server-side Ruby framework. You have access to your full domain model written with Active Record or your ORM of choice.
&lt;cite&gt;– &lt;a href=&quot;https://guides.rubyonrails.org/action_cable_overview.html&quot;&gt;Action Cable Overview @ Ruby on Rails Guides (v5.2.3)&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;install-redis&quot;&gt;Install redis&lt;/h3&gt;

&lt;p&gt;We are going to use the &lt;code class=&quot;highlighter-rouge&quot;&gt;redis&lt;/code&gt; adapter which is &lt;a href=&quot;https://guides.rubyonrails.org/action_cable_overview.html#redis-adapter&quot;&gt;a safe option for production environments&lt;/a&gt; unlike the &lt;code class=&quot;highlighter-rouge&quot;&gt;async&lt;/code&gt; one.&lt;/p&gt;

&lt;p&gt;You first must install &lt;a href=&quot;https://redis.io/&quot;&gt;redis&lt;/a&gt; on your system.&lt;/p&gt;

&lt;p&gt;To install it on Ubuntu you just have to execute the following commands in your terminal:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt update
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;apt &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;redis-server
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;To check that installation is successful, in your terminal make sure you get a PONG:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;$ redis-cli
127.0.0.1:6379&amp;gt; ping
PONG
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;configure-actioncable&quot;&gt;Configure ActionCable&lt;/h3&gt;

&lt;p&gt;Since we are working on the development environment, open your &lt;code class=&quot;highlighter-rouge&quot;&gt;config/cable.yml&lt;/code&gt; and replace its contents with:&lt;/p&gt;

&lt;div class=&quot;language-yml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;development&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV.fetch(&quot;REDIS_URL&quot;) { &quot;redis://localhost:6379/1&quot; } %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;channel_prefix&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;rails-chat-tutorial_development&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;async&lt;/span&gt;

&lt;span class=&quot;na&quot;&gt;production&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;adapter&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;redis&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&amp;lt;%= ENV.fetch(&quot;REDIS_URL&quot;) { &quot;redis://localhost:6379/1&quot; } %&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;channel_prefix&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;rails-chat-tutorial_production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; we have added an option &lt;code class=&quot;highlighter-rouge&quot;&gt;channel_prefix&lt;/code&gt; because:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Additionally, a channel_prefix may be provided to avoid channel name collisions when using the same Redis server for multiple applications
&lt;cite&gt;– &lt;a href=&quot;https://guides.rubyonrails.org/action_cable_overview.html#redis-adapter&quot;&gt;Action Cable Overview # Redis Adapter @ Ruby on Rails Guides (v5.2.3)&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finally, we are going to add the dependency in the &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;gem&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'redis'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Don’t forget to bundle after altering the &lt;code class=&quot;highlighter-rouge&quot;&gt;Gemfile&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&quot;configure-devise-for-authenticating-websocket-connections&quot;&gt;Configure Devise for authenticating websocket connections&lt;/h3&gt;

&lt;p&gt;When establishing a websocket connection, we don’t have access to the user session but we do have access to the cookies. So, in order to be able to authenticate the user we need to do some devise related stuff first (&lt;a href=&quot;https://rubytutorial.io/actioncable-devise-authentication/&quot;&gt;credits to Greg Molnar&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Create an initializer for warden hooks under the name &lt;code class=&quot;highlighter-rouge&quot;&gt;config/initializers/warden_hooks.rb&lt;/code&gt; and add the following lines:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;no&quot;&gt;Warden&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Manager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;after_set_user&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;id&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;no&quot;&gt;Warden&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Manager&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;before_logout&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;auth&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explain:&lt;/strong&gt; We add a cookie with the user’s id upon successful sign in and we remove it once the user logs out.&lt;/p&gt;

&lt;h3 id=&quot;configure-the-websocket-connection&quot;&gt;Configure the websocket connection&lt;/h3&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/channels/application_cable/connection.rb&lt;/code&gt; and change its contents to the following:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;ApplicationCable&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Connection&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ActionCable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Connection&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Base&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;identified_by&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:current_user&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;connect&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;current_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find_verified_user&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

    &lt;span class=&quot;kp&quot;&gt;private&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find_verified_user&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;verified_user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_by&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;id: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cookies&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;signed&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'user.id'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;verified_user&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;reject_unauthorized_connection&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explain:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Here identified_by is a connection identifier that can be used to find the specific connection later. Note that anything marked as an identifier will automatically create a delegate by the same name on any channel instances created off the connection.
&lt;cite&gt;– &lt;a href=&quot;https://guides.rubyonrails.org/action_cable_overview.html#connection-setup&quot;&gt;Action Cable Overview # Connection setup @ Ruby on Rails Guides (v5.2.3)&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the &lt;code class=&quot;highlighter-rouge&quot;&gt;find_verified_user&lt;/code&gt; method we access the cookie that we previously set in the warden hook.&lt;/p&gt;

&lt;h3 id=&quot;create-the-room-channel&quot;&gt;Create the room channel&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;A channel encapsulates a logical unit of work, similar to what a controller does in a regular MVC setup.
&lt;cite&gt;– &lt;a href=&quot;https://guides.rubyonrails.org/action_cable_overview.html#channelsp&quot;&gt;Action Cable Overview # Channels @ Ruby on Rails Guides (v5.2.3)&lt;/a&gt;&lt;/cite&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will create the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomChannel&lt;/code&gt; in which all Room pages will subscribe to.&lt;/p&gt;

&lt;p&gt;Create &lt;code class=&quot;highlighter-rouge&quot;&gt;app/channels/room_channel.rb&lt;/code&gt; with the following contents:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RoomChannel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ApplicationCable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Channel&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;subscribed&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;room&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;stream_for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;# or&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# stream_from &quot;room_#{params[:room]}&quot;&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explain&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;code class=&quot;highlighter-rouge&quot;&gt;subscribed&lt;/code&gt; method gets called once a subscription to the channel is established and it is responsible to setup the stream from which data will be sent back and forth.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We are going to configure the room page code later on to request subscriptions to this channel passing the &lt;code class=&quot;highlighter-rouge&quot;&gt;room&lt;/code&gt; parameter.&lt;/p&gt;

&lt;p&gt;We have two options:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Use &lt;code class=&quot;highlighter-rouge&quot;&gt;stream_for&lt;/code&gt;: this way Rails automatically generates a stream name for the given object (&lt;code class=&quot;highlighter-rouge&quot;&gt;room&lt;/code&gt; in our case), for example: “room:asdfwer234”. When we want afterwards to broadcast data to the stream, all we have to do is call &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomChannel.broadcast_to(room_object, data)&lt;/code&gt; in which case Rails resolves the stream name from the &lt;code class=&quot;highlighter-rouge&quot;&gt;room_object&lt;/code&gt;. In other words, we don’t have to manually resolve the stream name in which the data have to be send (see next item).
    &lt;ul&gt;
      &lt;li&gt;This option is available when the channel handles subscriptions bound to models like in our case, a specific room&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;Use &lt;code class=&quot;highlighter-rouge&quot;&gt;stream_from&lt;/code&gt;: we manually define the name of the stream and later on, when we want to broadcast to the stream, we have to use: &lt;code class=&quot;highlighter-rouge&quot;&gt;ActionCable.server.broadcast(&quot;room_#{a_room_id_here}&quot;, data)&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Read more &lt;a href=&quot;https://guides.rubyonrails.org/action_cable_overview.html#streams&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;broadcast-room-messages&quot;&gt;Broadcast room messages&lt;/h3&gt;

&lt;p&gt;Every time a room message is being created, we just need to broadcast to the message’s room stream.
To do so, alter the &lt;code class=&quot;highlighter-rouge&quot;&gt;create&lt;/code&gt; action of the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/controllers/room_messages_controller.rb&lt;/code&gt; to this:&lt;/p&gt;

&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt;
  &lt;span class=&quot;vi&quot;&gt;@room_message&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;RoomMessage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;user: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;ss&quot;&gt;room: &lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                                     &lt;span class=&quot;ss&quot;&gt;message: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dig&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

  &lt;span class=&quot;no&quot;&gt;RoomChannel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;broadcast_to&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room_message&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explain&lt;/strong&gt;: we added the line &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomChannel.broadcast_to @room, @room_message&lt;/code&gt; which will broadcast to the room’s specific stream (as explained above) the &lt;code class=&quot;highlighter-rouge&quot;&gt;@room_message&lt;/code&gt; transformed to json via the &lt;code class=&quot;highlighter-rouge&quot;&gt;to_json&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;So, on the other side, the client side, we are going to be receiving the json representation of the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomMessage&lt;/code&gt; model. Let’s see what that is:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;room_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;user_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My first message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2019-04-04T17:09:00.637Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;updated_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2019-04-04T17:09:00.637Z&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We plan to add the new messages in the room’s page via Javascript and this information is not adequate. The only thing we are missing is the user avatar. Time to refactor.&lt;/p&gt;

&lt;p&gt;Open &lt;code class=&quot;highlighter-rouge&quot;&gt;app/models/user.rb&lt;/code&gt; and add the following method:&lt;/p&gt;

&lt;div class=&quot;highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;def gravatar_url
  gravatar_id = Digest::MD5::hexdigest(email).downcase
  &quot;https://gravatar.com/avatar/#{gravatar_id}.png&quot;
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We had already implemented this in the &lt;code class=&quot;highlighter-rouge&quot;&gt;app/helpers/application_helper.rb&lt;/code&gt; file and we won’t be using it anymore so &lt;strong&gt;remove it&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Update &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/shared/_navigation_bar.html.erb&lt;/code&gt; and change the previous gravatar resolution to this:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;avatar&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;current_user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gravatar_url&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Update &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/show.html.erb&lt;/code&gt; and change it there too, with:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;room_message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gravatar_url&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;avatar&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, we will change the &lt;code class=&quot;highlighter-rouge&quot;&gt;JSON&lt;/code&gt; representation of the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomMessage&lt;/code&gt; to include the user’s url:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/room_message.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;language-ruby highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;as_json&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;user_avatar_url: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;gravatar_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s confirm that the new JSON transformation is valid:&lt;/p&gt;

&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;29&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;room_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;user_id&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;My first message&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;created_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2019-04-04T17:09:00.637Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;updated_at&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2019-04-04T17:09:00.637Z&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;user_avatar_url&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;https://gravatar.com/avatar/02a28db6886d578f75a820b50f2dd334.png&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Great, moving on.&lt;/p&gt;

&lt;h3 id=&quot;subscribe-to-the-room-stream&quot;&gt;Subscribe to the room stream&lt;/h3&gt;

&lt;p&gt;We are going to add some data in the room page in order to use them via Javascript to subscribe to the appropriate streams each time we visit a room.&lt;/p&gt;

&lt;p&gt;Open the file &lt;code class=&quot;highlighter-rouge&quot;&gt;app/views/rooms/show.html.erb&lt;/code&gt; and alter the line in which we define the chat div, to this:&lt;/p&gt;

&lt;div class=&quot;language-erb highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;chat&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-channel-subscribe=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;room&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-room-id=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;%=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;id&lt;/span&gt; &lt;span class=&quot;cp&quot;&gt;%&amp;gt;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explain&lt;/strong&gt;: We added two data attributes, one defining to which channel we want to subscribe and one defining to which room we are.&lt;/p&gt;

&lt;p&gt;At the end of the file, add the following snippet:&lt;/p&gt;

&lt;div class=&quot;language-html highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;d-none&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-role=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;message-template&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;chat-message-container&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;row no-gutters&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col-auto text-center&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;img&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;src=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;avatar&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;alt=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-role=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;user-avatar&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;col&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;message-content&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;p&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;mb-1&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-role=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;message-text&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

          &lt;span class=&quot;nt&quot;&gt;&amp;lt;div&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;text-right&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&quot;nt&quot;&gt;&amp;lt;small&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;data-role=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;message-date&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/small&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This snippet is going to be used as a template for each incoming message. Every time a message arrives, we will&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;clone this html&lt;/li&gt;
  &lt;li&gt;alter the appropriate elements’ values and&lt;/li&gt;
  &lt;li&gt;append the resulting html to the end of the chat div.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now we will create the Javascript that will do the work of subscribing and handling incoming channel data.&lt;/p&gt;

&lt;p&gt;Create the file &lt;code class=&quot;highlighter-rouge&quot;&gt;app/assets/javascripts/channels/room_channel.js&lt;/code&gt; and add the following code:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;[data-channel-subscribe=&quot;room&quot;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$element&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;room_id&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;room-id&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;messageTemplate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;[data-role=&quot;message-template&quot;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;scrollTop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;scrollHeight&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;        

    &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;subscriptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;channel&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;RoomChannel&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;room&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;room_id&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;received&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
          &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;messageTemplate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;children&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;clone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;[data-role=&quot;user-avatar&quot;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;attr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user_avatar_url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;[data-role=&quot;message-text&quot;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;[data-role=&quot;message-date&quot;]&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;updated_at&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;append&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
          &lt;span class=&quot;nx&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;scrollTop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;$element&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;scrollHeight&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)},&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Explain&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;For each element that has a data attribute &lt;code class=&quot;highlighter-rouge&quot;&gt;channel-subscribe&lt;/code&gt; with value &lt;code class=&quot;highlighter-rouge&quot;&gt;room&lt;/code&gt;
    &lt;ul&gt;
      &lt;li&gt;Create a subscription to the “RoomChannel” passing the element’s &lt;code class=&quot;highlighter-rouge&quot;&gt;room-id&lt;/code&gt; data attribute as a parameter with name &lt;code class=&quot;highlighter-rouge&quot;&gt;room&lt;/code&gt; (remember this line of the &lt;code class=&quot;highlighter-rouge&quot;&gt;RoomChannel&lt;/code&gt;: &lt;code class=&quot;highlighter-rouge&quot;&gt;Room.find params[:room]&lt;/code&gt; ?)
        &lt;ul&gt;
          &lt;li&gt;When data is received, clone the template snippet and alter its contents based on the incoming object attributes.&lt;/li&gt;
          &lt;li&gt;Append the newly generated content to the chat div and finally&lt;/li&gt;
          &lt;li&gt;Do some animation to impress by scrolling smoothly to the bottom of the div.&lt;/li&gt;
        &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;acknowledgments&quot;&gt;Acknowledgments&lt;/h2&gt;

&lt;p&gt;Thank you very much for your feedback.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;[1] Armando Andini - &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/3&quot;&gt;N+1 queries&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[2] Rodolfo Ruiz - &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/5&quot;&gt;Coffeescript leftovers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[3] Felix Wolfsteller - &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/1&quot;&gt;Turbolinks leftovers&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[4] Maria Kravtsova - &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/2&quot;&gt;Migration typo&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[5][7][8] Tony Dehnke - &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/6&quot;&gt;Sign up step&lt;/a&gt;, &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/8&quot;&gt;Missing step for adding model relations&lt;/a&gt;, &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/7&quot;&gt;Missing line from html code block&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[6] keytonw - &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/9&quot;&gt;Devise view missing button class&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[9] Martin - &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/11&quot;&gt;Mention order of requirements in application.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;[10] Sumak - &lt;a href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues/15&quot;&gt;Remove duplicate authentication related code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s all! Long post, tired cat photo.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://iridakos.com/assets/images/posts/rails-chat-tutorial/irida.jpg&quot; alt=&quot;Tired cat photo&quot; /&gt;&lt;/p&gt;

&lt;div class=&quot;alert alert-light&quot;&gt;
  &lt;div class=&quot;alert-heading&quot;&gt;&lt;i class=&quot;fa fa-comments&quot;&gt;&lt;/i&gt; Code and comments&lt;/div&gt;

  You can find the code of this tutorial on &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/rails-chat-tutorial&quot;&gt;&lt;i class=&quot;fa fa-github&quot;&gt;&lt;/i&gt; GitHub&lt;/a&gt;.

  &lt;hr /&gt;

  For feedback, comments, typos etc. please open an &lt;a class=&quot;alert-link&quot; href=&quot;https://github.com/iridakos/rails-chat-tutorial/issues&quot;&gt;issue&lt;/a&gt; in the repository.

  &lt;hr /&gt;

  &lt;strong&gt;Thanks for visiting!&lt;/strong&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 04 Apr 2019 23:00:00 +0300</pubDate>
        <link>https://iridakos.com/programming/2019/04/04/creating-chat-application-rails-websockets</link>
        <guid isPermaLink="true">https://iridakos.com/programming/2019/04/04/creating-chat-application-rails-websockets</guid>
        
        <category>ruby</category>
        
        <category>rails</category>
        
        <category>websockets</category>
        
        <category>devise</category>
        
        <category>bootstrap</category>
        
        <category>chat</category>
        
        <category>actioncable</category>
        
        <category>redis</category>
        
        <category>featured</category>
        
        <category>tutorial</category>
        
        
        <category>programming</category>
        
      </item>
    
      <item>
        <title>Vacuum cleaner</title>
        <description>
</description>
        <pubDate>Sat, 24 Nov 2018 00:00:00 +0200</pubDate>
        <link>https://iridakos.com/cats/2018/11/24/vacuum-cleaner</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2018/11/24/vacuum-cleaner</guid>
        
        
      </item>
    
      <item>
        <title>Terminator</title>
        <description>
</description>
        <pubDate>Sat, 24 Nov 2018 00:00:00 +0200</pubDate>
        <link>https://iridakos.com/cats/2018/11/24/terminator</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2018/11/24/terminator</guid>
        
        
      </item>
    
      <item>
        <title>Nightmare</title>
        <description>
</description>
        <pubDate>Sat, 24 Nov 2018 00:00:00 +0200</pubDate>
        <link>https://iridakos.com/cats/2018/11/24/nightmare</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2018/11/24/nightmare</guid>
        
        
      </item>
    
      <item>
        <title>Monday</title>
        <description>
</description>
        <pubDate>Sat, 24 Nov 2018 00:00:00 +0200</pubDate>
        <link>https://iridakos.com/cats/2018/11/24/monday</link>
        <guid isPermaLink="true">https://iridakos.com/cats/2018/11/24/monday</guid>
        
        
      </item>
    
  </channel>
</rss>
