<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Lola</title>
    <description>The latest articles on DEV Community by Lola (@lolaodelola).</description>
    <link>https://dev.to/lolaodelola</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F178466%2F07f37851-bb29-453a-b055-360b4c660fe0.jpeg</url>
      <title>DEV Community: Lola</title>
      <link>https://dev.to/lolaodelola</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lolaodelola"/>
    <language>en</language>
    <item>
      <title>From Bootstrap to Grid</title>
      <dc:creator>Lola</dc:creator>
      <pubDate>Thu, 21 Apr 2022 16:43:13 +0000</pubDate>
      <link>https://dev.to/samsunginternet/from-bootstrap-to-grid-1c31</link>
      <guid>https://dev.to/samsunginternet/from-bootstrap-to-grid-1c31</guid>
      <description>&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The Bootstrap Way&lt;/li&gt;
&lt;li&gt;The Problem&lt;/li&gt;
&lt;li&gt;CSS-Grid&lt;/li&gt;
&lt;li&gt;&lt;code&gt;display: flex&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Combining CSS-Grid with Flexbox&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;Further Watching&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This post isn't going to be a CSS-grid tutorial, there are loads out there, &lt;a href="https://medium.com/samsung-internet-dev/common-responsive-layouts-with-css-grid-and-some-without-245a862f48df" rel="noopener noreferrer"&gt;Jo even wrote one&lt;/a&gt; and since, CSS Grid has emerged as vita tool to enable responsive design. This is a post about how to understand the difference between traditional CSS layout frameworks (Bootstrap, Tailwind, Foundation, etc) &amp;amp; CSS-grid.&lt;/p&gt;

&lt;p&gt;I’ve been building things on the web for almost 8yrs &amp;amp; in that time, Bootstrap has been my layout framework of choice. When I began developing on the web, creating responsive layouts in vanilla CSS was intimidating, especially as a Ruby, predominately back-end, engineer but thankfully, CSS has continued to evolve in that time and now we have CSS-grid. Despite this though, many developers still opt to use frameworks which impact the load of their websites and web apps when they don’t need to. I know for me, CSS-grid was still intimidating, I didn’t understand when to use that vs when to use flexbox or if I could use them together. In this post I’m going to try to explain how CSS-grid (&amp;amp; flexbox) work if you’re coming from a framework such as Bootstrap.&lt;/p&gt;

&lt;p&gt;To learn and understand CSS-grid I decided to create a grid for my website since the layout is fairly simple and there are few elements on the screen. I marked up the grid and any sub-grids I used to get a clear understanding of where the elements are positioned. The red dashed lines are are the main grid while the yellow marks the sub-grid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyudn3n0xtht7vxsq1fd2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyudn3n0xtht7vxsq1fd2.png" alt="the lolaodelola.dev site with red markings to show the current main grid and yellow markings to show the sub-grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without the use of any layout framework, the elements use the original HTML flow&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26ajj9170b2pvbtl34kb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26ajj9170b2pvbtl34kb.png" alt="the lolaodelola.dev site without any layout frameworks"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was able to recreate the layout, with only two changes (the positioning of the header) and make it fully responsive to width without any media queries.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdahe3i618t5pvq2okpme.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdahe3i618t5pvq2okpme.gif" alt="a gif of the responsiveness of lolaodelola.dev using css-grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bootstrap Way
&lt;/h2&gt;

&lt;p&gt;Bootstrap typically work by defining a fixed, 12 column grid, while this number and the fixed width has historical context it’s mostly arbitrary, especially now considering the diversity in viewport dimensions. With this fixed width column system, you define how many columns your elements should take up at various viewport widths within a container e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col-3-lg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This example defines a container then says the child element should take up 3 columns on a large screen, which in Bootstrap is a screen width of ≥992px. Other frameworks approach this in a different way, for example Tailwind actually uses CSS-grid under the hood. Bootstrap is also mobile-first and in the most recent version, if you have child elements that should take up an equal amount of space, regardless of device width, you don’t have to specify a unit e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ...
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the past Boostrap used CSS floats under the hood, however the current version, Bootstrap 5.1 uses flexbox (which I’ll go into more detail later).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Bootstrap is a good way to quickly create a layout, especially if that layout is one of the few basic layouts that are used on the web. It has an extensive list of class definitions for developers to choose from, the documentation is robust and it’s free to use, there’s a place for Bootstrap. But choosing to use it should be intentional and not because you’re intimidated by CSS-grid.&lt;/p&gt;

&lt;h3&gt;
  
  
  Inflexiblity
&lt;/h3&gt;

&lt;p&gt;In Ruby on Rails development, the methodology is “convention over configuration” which is to say it’s easier (read: better) to do things as they’re defined than it is to try and customise the framework to meet your needs. I think most frameworks, regardless of language, work in this way. While Bootstrap is robust, it isn’t flexible. The minute you want to create layouts that don’t follow the rules of a 12 column grid, or have elements doing interesting things like overlapping, or even decide to adjust the layout dependent on height instead of width, things begin to get complicated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Obscures the CSS
&lt;/h3&gt;

&lt;p&gt;The job of a framework is to create a sort of instruction manual of using a language in a certain way to build certain things. So, yes, frameworks will naturally obstruct the vanilla language being used to construct them however, Bootstrap goes an extra mile to redefine things that can be easily defined in one rule, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nc"&gt;.d-flex&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a rule that can easily be defined within the custom CSS, without the &lt;code&gt;!important&lt;/code&gt; keyword.&lt;/p&gt;

&lt;p&gt;On the topic of &lt;code&gt;!important&lt;/code&gt; this is another place where CSS is obscured, the keyword is litered all through the framework and should you be using Bootstrap in conjuction with another stylesheet, especially on big projects, you will have to be careful and aware of the order of how your stylesheets are being loaded and where styles may be overwritten.&lt;/p&gt;

&lt;h3&gt;
  
  
  Overbloat
&lt;/h3&gt;

&lt;p&gt;Because Bootstrap tries to cover many basis, there are inevitably rules and styles you won’t end up using but these styles will still be loaded into the site. Bootstrap also comes with a visual identity, there are styles for all kinds of elements, buttons, navs, leads, etc but even if you elect to just include the grid in your project, you won’t be using all aspects of the grid. In fact, it’s possible you may just use 3 or 4 grid properties but will still be loading a 53KB file (if only using &lt;code&gt;bootstrap-grid.min.css&lt;/code&gt; ), my custom grid.css file for this project ended up being only 881bytes without being minified and is only 62 lines long.&lt;/p&gt;

&lt;h2&gt;
  
  
  CSS-Grid
&lt;/h2&gt;

&lt;p&gt;Learning CSS-grid requires unlearning Bootstrap (or which framework you’re using if it’s not using grid under the hood). Before I get into the minutiae, it’s important to note that CSS-grid encourages you to have multiple grids on a page where as Bootstrap assumes you have one main grid which you nest elements within. CSS-Grid says apply the grid where you need it, which really encourages you to think about the default display of elements (which elements are block, which are inline and do you need to flex anything?).&lt;/p&gt;

&lt;h3&gt;
  
  
  What is a Column, What is a Row, What is a Cell?
&lt;/h3&gt;

&lt;p&gt;Any grid framework or understanding works on a x-axis and a y-axis, it’s 2-dimensional in that way, this  may seem like an obvious fact but is important to remember. Within Bootstrap, columns and rows work in the traditional way. A row is horizontal space while a column is a vertical space. In the image below the green dotted line around the perimeter of the elements indicates the row while the dotted line down the middle separates the columns. So there is one row and two columns. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4tzqmcgmlqmwd42tryq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4tzqmcgmlqmwd42tryq.png" alt="the lolaodelola.dev site with the dev tools layout grid showing the columns in a green dashed line"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This would be defined in the HTML as&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"row"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;img&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"col"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is to say both the row and the column refer to the space between the lines of the grid, rather than the lines themselves. In other words, we define the row and column on the page and fill both with content.&lt;/p&gt;

&lt;p&gt;CSS-grid also uses rows and columns but not in the same way. In grid, the columns and rows refer to the lines rather than the space between the lines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpiduzhrkgnej0r0mwhqe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpiduzhrkgnej0r0mwhqe.png" alt="the dev tools layout shows where the column and row lines are when the page has multiple columns"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although difficult to see, each line is numbered. The numbers in this image refer to the rows and columns, so the first vertical line is column 1, the second is column 2, and the first horizontal line is row 1 and the second is row 2. The space in between these lines, the cell, contains the image. Similarly, the block of text starts at horizontal line 2 i.e. column 2 and ends at horizontal line 3 i.e. column 3 and also starts at vertical line 1 i.e. row 1 and ends at vertical line 2, i.e. row 2.&lt;/p&gt;

&lt;p&gt;And when the page collapses into a single column the image is still starts at column 1 and ends at column 2 and starts at row 1 and ends at row 2 but the block of text now also starts tarts at column 1 and ends at column 2 but sits between row 2 &amp;amp; 3.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The space between the rows and columns is called a cell&lt;/strong&gt;. So the image sits in a cell that between two columns and two rows.&lt;/p&gt;

&lt;p&gt;The CSS and HTML for this aren’t complex&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!--Grid cell 1 --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;img&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Grid cell 2 --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbouj3u7xejyghgq153al.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbouj3u7xejyghgq153al.png" alt="the dev tools layout shows where the column and row lines are when the page is in single column"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will go into detail about &lt;code&gt;grid-template-columns&lt;/code&gt; a little later but the important thing here is that I’m defining a grid on the parent element (similarly to how you might define a container in bootstrap) and then telling the CSS how I want the grid to look i.e. how I want elements to occupy the available space.&lt;/p&gt;

&lt;p&gt;If I want the elements to span multiple columns or rows, I can define that in the CSS&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;
&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="err"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-column&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;grid-row&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will cause the image to start at column 1/row1 and end at column 3/row3, which will occupy 2 cells. If I wanted to have an element occupy 2 cells with Bootstrap, I’d give the element a &lt;code&gt;.col-2&lt;/code&gt; however, remember that Bootstrap works on a fixed-width grid and CSS-grid doesn’t. Play with this on &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid-column" rel="noopener noreferrer"&gt;MDN to really get to grips with it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid-area#examples" rel="noopener noreferrer"&gt;You can also define a &lt;code&gt;grid-area&lt;/code&gt;&lt;/a&gt; which is a combination of the rows and columns. &lt;/p&gt;

&lt;h3&gt;
  
  
  Fractions (aka FR)
&lt;/h3&gt;

&lt;p&gt;With CSS-grid comes a new unit to define how much space elements should take up. While it’s entirely fine to use &lt;code&gt;px&lt;/code&gt;, &lt;code&gt;ch&lt;/code&gt;, &lt;code&gt;em&lt;/code&gt;, &lt;code&gt;rem&lt;/code&gt;, &lt;code&gt;%&lt;/code&gt;, etc &lt;code&gt;fr&lt;/code&gt; (fraction) is a little more flexible in the context of grid.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As mentioned earlier, the &lt;code&gt;grid-template-columns&lt;/code&gt; defines the vertical space the elements in my grid should occupy. I can define the same for rows with &lt;code&gt;grid-template-rows&lt;/code&gt; but for now let’s focus on columns. In the CSS above, I’ve said that each column should take one fraction of the available grid space. Regardless of the viewport width, the grid cells will only take up 1 fraction of space in the grid.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31k3tbqjf9kyson224zj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F31k3tbqjf9kyson224zj.png" alt="When the screen width is too small, the text becomes very cramped and the image very small side by side"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So even on smaller devices the elements will still try to take up 1 fraction of the available grid. Of course, you can use any fraction here, &lt;code&gt;2fr&lt;/code&gt;, &lt;code&gt;7fr&lt;/code&gt;, etc and mix and match. You can also tailor to consider how many cells will be in the grid and define those too, so if my grid had 4 cells I could say &lt;code&gt;grid-template-columns: 1fr 1fr 1fr 1fr&lt;/code&gt; to say I want 4 cells and each should take up 1 fraction of the available grid space. You can also mix and match different units to get your ideal layout, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid-template-columns" rel="noopener noreferrer"&gt;have a go on MDN&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Gaps aka Gutters
&lt;/h3&gt;

&lt;p&gt;The grid gutter in Bootstrap is the space between columns and rows, in the image below each column has a box around the perimeter and a space in the middle which is the gutter.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flszavydehvybqmpjfetm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flszavydehvybqmpjfetm.png" alt="the two columns have boxes around them with a gap between them"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While the gutters in Bootstrap can be redefined, most users use the default gutters and don’t have to consider them. With grid, gutters are called gaps and you also may not have to define gaps on grid dependent on the units you choose to define the columns but implementing gaps is straight-forward. You have the option of defining the &lt;code&gt;column-gap&lt;/code&gt;, &lt;code&gt;row-gap&lt;/code&gt; or for if you want both the vertical and horizontal gaps to be the same then &lt;code&gt;gap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Gaps can also be used to define the space within flex elements, so if you plan to nest grids within flex elements, and are defining gaps on both the grid and flex element, you may find your gaps are slightly wider than you anticipate. The solution is to adjust them as you see fit. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/gap" rel="noopener noreferrer"&gt;You can play with gaps on MDN.&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Get Responsive without Media Queries
&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, I was able to recreate the responsiveness of my original site without using media queries. This requires a combination of rules to create the fluidity of a responsive web page.&lt;/p&gt;

&lt;p&gt;First up, &lt;code&gt;repeat&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This says create 2 columns each taking up 1 fraction of space in the grid, the issue here is that on smaller viewports, there will be 2 squished cells which isn’t want we want.&lt;/p&gt;

&lt;p&gt;To overcome this hurdle, we can define the minimum width for the columns using &lt;code&gt;minmax&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we’re saying we want &lt;code&gt;2&lt;/code&gt; columns, with a minimum of &lt;code&gt;50ch&lt;/code&gt; width, taking up &lt;code&gt;1fr&lt;/code&gt; of the available space.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foky3fnwoiial99btcck4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foky3fnwoiial99btcck4.png" alt="when the screen width is too small, the column to the right overflows"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This presents a new problem, when we’re on devices with a viewport width that’s smaller than the available row space, the content will overflow. This is also unideal, so there’s one more part to enable the cells collapsing like we expect.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;auto-fit&lt;/code&gt;/ &lt;code&gt;auto-fill&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="py"&gt;grid-template-columns&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;repeat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auto-fit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;minmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;fr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ve decided to use &lt;code&gt;auto-fit&lt;/code&gt; here which collapses the columns into rows as we expect. &lt;code&gt;auto-fit&lt;/code&gt; and &lt;code&gt;auto-fill&lt;/code&gt; have similar functions in that they both look at the available space in a row and assign column space to the available cells. Sara Soueidan explains the difference as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;&lt;code&gt;auto-fill&lt;/code&gt; FILLS the row with as many columns as it can fit. So it creates implicit columns whenever a new column can fit, because it’s trying to FILL the row with as many columns as it can. The newly added columns can and may be empty, but they will still occupy a designated space in the row. &lt;br&gt;
&lt;code&gt;auto-fit&lt;/code&gt; FITS the CURRENTLY AVAILABLE columns into the space by expanding them so that they take up any available space. The browser does that after FILLING that extra space with extra columns (as with &lt;code&gt;auto-fill&lt;/code&gt; ) and then collapsing the empty ones.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I recommend reading the &lt;a href="https://css-tricks.com/auto-sizing-columns-css-grid-auto-fill-vs-auto-fit/#aa-fill-or-fit-whats-the-difference" rel="noopener noreferrer"&gt;full explainer&lt;/a&gt; to really get your head around the difference.&lt;/p&gt;

&lt;p&gt;The combination of &lt;code&gt;repeat&lt;/code&gt;, &lt;code&gt;minmax&lt;/code&gt; and &lt;code&gt;auto-fit&lt;/code&gt;/ &lt;code&gt;auto-fill&lt;/code&gt; creates a layout that’s responsive to width without media queries and in one line.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;display: flex&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Flexbox deserves its own post so I won’t go into too much detail here but it’s important to know how it fits in with grid. Many people aren’t only intimidated by CSS-grid, but also by Flexbox and the difference is between the two. Coming from Bootstrap, it’s tricky to know when to use either. The good news is you can use both but they do serve different purposes.&lt;/p&gt;

&lt;p&gt;As I mentioned before CSS-grid works along the X-axis and Y-axis, it’s 2-dimensional. Flexbox only works along the X-axis, which is the horizontal axis and so it’s 1-dimensional. Adding elements to a flex element will cause the elements to flow horizontally.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgjzqbc7zs6ojd0q3h2a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpgjzqbc7zs6ojd0q3h2a.png" alt="The flex container for the nav. Each item is in its own box with the surrounding space shaded in."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the example above, I have a &lt;code&gt;ul&lt;/code&gt; element which usually stacks its list items vertically, however, since I’ve given the element a &lt;code&gt;display: flex&lt;/code&gt; the elements are lined up horizontally. It’s possible to allow flex elements to stack vertically to avoid overflow with &lt;code&gt;flex-wrap: wrap&lt;/code&gt; as I’ve done for the list of buttons here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdi5skmq253h17bnuj1e.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcdi5skmq253h17bnuj1e.gif" alt="A gif of the responsive buttons created using flex"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The CSS for this is two lines&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;flex-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;wrap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Justify &amp;amp; Align Content
&lt;/h3&gt;

&lt;p&gt;The super power of Flexbox is being able to justify and align content the way we want. Aligning content positions the element along its own y-axis, while justify position an element along its own x-axis. &lt;/p&gt;

&lt;h2&gt;
  
  
  Combining CSS-Grid with Flexbox
&lt;/h2&gt;

&lt;p&gt;Okay, so we can kinda grasp CSS-Grid and Flexbox how and why would we put them together? Let’s revisit my very first image with the Bootstrap grid outlines:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1yohgpwwft6rf7kocyq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp1yohgpwwft6rf7kocyq.png" alt="the lolaodelola.dev site with red markings to show the current main grid and yellow markings to show the sub-grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To recap, the red dashed lines are the main grid and the yellow lines are the subgrid. Breaking this down I can see that I think I want 2 columns and 3 rows for the main grid, however CSS-Grid forces us to only use the grid where necessary. This is where personal preference comes into play, there aren’t any concrete rules here, it’s entirely up to me and how I want to lay this out. Bootstrap’s approach to this would be to make all the columns flex elements and wrap them as necessary and not use the grid at all.&lt;/p&gt;

&lt;p&gt;The method I ended up going with was a combination of CSS-Grid and Flexbox.&lt;/p&gt;

&lt;p&gt;I changed my mind about the layout to be a little more accesible. The previous layout would have screenreaders reading the image before the title which isn’t ideal. I’ve moved the title into a header with the nav, and since neither the header or the footer needs to work on a 2-dimensional level (or can just without changing the native display properties of the elements), I’ve decided to only apply the grid to the main content. The red dashed line shows 3 columns, 2 rows which create space for 2 cells.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2vcw9vyo3a6xl7iis4e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl2vcw9vyo3a6xl7iis4e.png" alt="the new lolaodelola.dev layout with red dashed lines outlining the grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’ve moved the title into a header with the nav, and since neither the header or the footer needs to work on a 2-dimensional level (or can just without changing the native display properties of the elements), I’ve decided to only apply the grid to the main content. The red dashed line shows 3 columns, 2 rows which create space for 2 cells.&lt;/p&gt;

&lt;p&gt;I’ve decided to use flex for elements which normally have a &lt;code&gt;display: block&lt;/code&gt; so that they can flow horizontally, wrap if necessary and are justified and aligned as expected on all screen sizes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx3v997ycj8h83b251e2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffx3v997ycj8h83b251e2.png" alt="the new lolaodelola.dev layout with yellow dashed lines outlining the the flex elements, some of which are a sub-grid"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;CSS-Grid is very robust and there are definitions that I didn’t cover here, such as &lt;code&gt;grid-template-areas&lt;/code&gt; which allows you to define sections of a page with different grids to create a layout, it also allows for empty cells (without defining empty HTML elements). Or grid ordering which lets you define the order of cells within a grid in the CSS.&lt;/p&gt;

&lt;p&gt;One of the qualities of Bootstrap is that there’s the option to create sub-grids fairly easily and while it’s possible to nest grids with CSS-grid, there is a dedicated sub-grid &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Subgrid" rel="noopener noreferrer"&gt;ruleset on its way&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Further Watching
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=AMPKmh98XLY&amp;amp;t=225s" rel="noopener noreferrer"&gt;“Designing Intrinsic Layouts” by Jen Simmons—An Event Apart video&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=dQHtT47eH0M&amp;amp;t=56s" rel="noopener noreferrer"&gt;Using Flexbox + CSS Grid Together: Easy Gallery Layout&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=mVQiNpqXov8" rel="noopener noreferrer"&gt;MinMax in CSS Grid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>grid</category>
      <category>frameworks</category>
    </item>
    <item>
      <title>The Trouble with `has_one`</title>
      <dc:creator>Lola</dc:creator>
      <pubDate>Tue, 10 Aug 2021 13:19:27 +0000</pubDate>
      <link>https://dev.to/samsunginternet/the-trouble-with-hasone-261m</link>
      <guid>https://dev.to/samsunginternet/the-trouble-with-hasone-261m</guid>
      <description>&lt;p&gt;Recently I was working on my dissertation and came across an interesting problem with using the has_one association in Rails. But before we get into that, let’s take a step back to understand a little about how associations work in Rails.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/l0HlI6NdcrtkV5C7e/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/l0HlI6NdcrtkV5C7e/giphy.gif" alt="A woman on big brother looking confused"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Rails Associations
&lt;/h2&gt;

&lt;p&gt;I’m not going to assume everyone reading this knows or understands in depth about databases and object relational mappers so I’ll try to keep this brief and simple. If you want a more in depth understanding, the &lt;a href="https://guides.rubyonrails.org/association_basics.html"&gt;Rails docs&lt;/a&gt; are a good starting point to understanding this in that specific context.&lt;/p&gt;

&lt;p&gt;Let’s say you want to build a content site where different &lt;strong&gt;creators&lt;/strong&gt; can create &lt;strong&gt;posts&lt;/strong&gt;, you’d have a relational database with two tables &lt;strong&gt;Creator&lt;/strong&gt; and &lt;strong&gt;Post&lt;/strong&gt; that may look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WhlF2AWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AzTLAQfTO-wxZDMXgvOQ3Fg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WhlF2AWq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AzTLAQfTO-wxZDMXgvOQ3Fg.png" alt="A spreadsheet with two tables, Creator with the rows ID and Name and Post with the rows ID, Title, Type and Body"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your creator table has an &lt;em&gt;ID&lt;/em&gt; and &lt;em&gt;Name&lt;/em&gt; column for every item that gets created and your post table has an &lt;em&gt;ID&lt;/em&gt;, &lt;em&gt;Title&lt;/em&gt;, &lt;em&gt;Type&lt;/em&gt; and &lt;em&gt;Body&lt;/em&gt; column for every item. In each column, the primary key will be the &lt;em&gt;ID&lt;/em&gt; column since that’s going to be the unique identifier for each record. The &lt;a href="https://www.bbc.co.uk/bitesize/guides/ztsvb9q/revision/5"&gt;primary key&lt;/a&gt; is important when creating associations because it acts as the &lt;a href="https://www.bbc.co.uk/bitesize/guides/ztsvb9q/revision/5"&gt;foreign key&lt;/a&gt; in the associated table.&lt;/p&gt;

&lt;p&gt;Now we need to decide what kind of relationship the two tables will have with each other since we’d likely want to know which creators created which posts. There are a few different kinds of associations you can create but I’ll only touch on two.&lt;/p&gt;

&lt;h3&gt;
  
  
  has_many
&lt;/h3&gt;

&lt;p&gt;A has_many association, says one item in a table can be associated with many items in another table. For example, if our system is a standard content creation system then a &lt;strong&gt;creator&lt;/strong&gt; can have many &lt;strong&gt;posts&lt;/strong&gt; since one &lt;strong&gt;creator&lt;/strong&gt; can create many &lt;strong&gt;posts&lt;/strong&gt; in which case, the association in Rails would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Creator&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:posts&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:creator&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And our database would look like:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5i8fzcDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUvKD65Tc6EPzhXAK3IsoDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5i8fzcDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUvKD65Tc6EPzhXAK3IsoDA.png" alt="A spreadsheet with two tables, Creator with the rows ID and Name and Post with the rows ID, Title, Type, Body and Creator_ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;creator_id&lt;/code&gt; would be pulled from the &lt;code&gt;id&lt;/code&gt; column, which is the primary key in the &lt;strong&gt;creator&lt;/strong&gt; table and act as a foreign key in the &lt;strong&gt;post&lt;/strong&gt; table. So if you wanted to find all the posts created by Tiffany Pollard, you’d do a search on the &lt;strong&gt;post&lt;/strong&gt; table where the &lt;code&gt;creator_id&lt;/code&gt; matches Tiffany Pollard’s &lt;code&gt;id&lt;/code&gt; in the &lt;strong&gt;creator&lt;/strong&gt; table.&lt;/p&gt;
&lt;h3&gt;
  
  
  has_one
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;has_one&lt;/code&gt; relationship says one item in a table can only be associated with one item in another table, no more than one. We may want to create a system where a &lt;strong&gt;creator&lt;/strong&gt; can only ever create one &lt;strong&gt;post&lt;/strong&gt; in which case, our Rails code would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Creator&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:creator&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;creator&lt;/strong&gt; &lt;code&gt;has_one&lt;/code&gt; post and a post &lt;code&gt;belongs_to&lt;/code&gt; a &lt;strong&gt;creator&lt;/strong&gt;. The database looks the same as before:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5i8fzcDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUvKD65Tc6EPzhXAK3IsoDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5i8fzcDT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2AUvKD65Tc6EPzhXAK3IsoDA.png" alt="A spreadsheet with two tables, Creator with the rows ID and Name and Post with the rows ID, Title, Type, Body and Creator_ID"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And just like with &lt;code&gt;has_many&lt;/code&gt; the &lt;code&gt;creator_id&lt;/code&gt; is the foreign key for the creator’s &lt;code&gt;id&lt;/code&gt; in the post table.&lt;/p&gt;

&lt;p&gt;Okay, so now onto the problem.&lt;/p&gt;

&lt;p&gt;...&lt;/p&gt;
&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;In Rails when you create a &lt;code&gt;has_one&lt;/code&gt; association, understandably the assumption is that a &lt;strong&gt;creator&lt;/strong&gt; can only ever have one &lt;strong&gt;post&lt;/strong&gt;. So what happens when a &lt;strong&gt;creator&lt;/strong&gt; tries to create another &lt;strong&gt;post&lt;/strong&gt;? You’d hope that it’d check to see if a post exists and ask the creator if they want to replace the post or just replace the post with the assumption that that’s the intention of the creator. But that’s not what happens, instead, you get this error:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u1-QJjlm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2ANBIfqCesY82KGPb0P4jLyQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u1-QJjlm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/1%2ANBIfqCesY82KGPb0P4jLyQ.png" alt='A rails error message that reads "Failed to remove the existing associated post. The record failed to save after its foreign key was set to nil.'&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is a common error with &lt;code&gt;has_one&lt;/code&gt; and is summed up nicely in this &lt;a href="https://github.com/rails/rails/issues/17325"&gt;issue&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is because prior to deleting, the foreign key of the target association is set to nil and a save operation is performed on the target.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s unclear &lt;em&gt;why&lt;/em&gt; this happens, if you go through the issue you’ll notice it was created in 2014 and the discussion is still ongoing. It seems this started out as a bug but may have evolved to become the desired functionality.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6V0ONV9O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AS57ZWGL44S9x3ayM" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6V0ONV9O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/1400/0%2AS57ZWGL44S9x3ayM" alt="A small dog wearing glasses and a shirt using a laptop"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are a number of ways to fix this and it all depends on your system. Essentially, you want to make sure the old association is deleted before you try to create a new one. So, you can do this in your model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Creator&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:post&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;dependent: :destroy&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Post&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:creator&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or in the method where you create your resource (either in your controller or specific lib file) you can run something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;creator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Creator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by_id&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;creator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;before you create any post. Andy Croll from Coverage Book recommends &lt;a href="https://andycroll.com/ruby/be-careful-assigning-to-has-one-relations/"&gt;rolling things up in a transaction&lt;/a&gt; and there are more suggestions in the &lt;a href="https://github.com/rails/rails/issues/17325"&gt;GitHub issue&lt;/a&gt; too.&lt;/p&gt;

&lt;h2&gt;
  
  
  Further Reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://andycroll.com/ruby/be-careful-assigning-to-has-one-relations/"&gt;Be Careful Assigning has_one Relations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/rails/rails/issues/17325"&gt;Building a has_one association fails on save if target has a validation on foreign_key&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bbc.co.uk/bitesize/guides/ztsvb9q/revision/5"&gt;BBC Bitesize: Introducing Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://guides.rubyonrails.org/association_basics.html"&gt;Rails ActiveRecord Associations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>webdev</category>
      <category>database</category>
    </item>
    <item>
      <title>"You Are Not Your Failed Test Suite" and Other Affirmations; an App on Heroku</title>
      <dc:creator>Lola</dc:creator>
      <pubDate>Sun, 24 Jan 2021 15:39:54 +0000</pubDate>
      <link>https://dev.to/lolaodelola/you-are-not-your-failed-test-suite-and-other-affirmations-an-app-on-heroku-db9</link>
      <guid>https://dev.to/lolaodelola/you-are-not-your-failed-test-suite-and-other-affirmations-an-app-on-heroku-db9</guid>
      <description>&lt;p&gt;We all need a little encouragement from time to time, especially when computers insist on doing exactly what we tell them. Fortunately, you can manufacture your own cheerleader to deliver those small affirmations all developers need. Let’s look at how you can create a small application hosted on &lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt; that sends text messages to developers that might appreciate a little encouragement.&lt;/p&gt;

&lt;p&gt;The app allows users to sign up for messages, get encouraging texts (such as “You are not your failing test suite” and “You’re bigger than your bugs”) once a week, and then stop the messages if the users no longer want to receive them.&lt;br&gt;
We’ll build the app using Ruby on Rails, Postgres, and the Twilio API, and we’ll use Heroku pipelines and Heroku CI to run our tests and manage our deployment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;First let’s walk through what you’ll need to get the app running. This is an intermediate-level tutorial, which may not be suitable for complete beginners. To follow along, you should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;be comfortable writing &lt;a href="https://guides.rubyonrails.org/getting_started.html"&gt;Ruby on Rails&lt;/a&gt; and have it installed.&lt;/li&gt;
&lt;li&gt;be comfortable using the terminal (or IDE, though I’ll be referring to a terminal in this tutorial).&lt;/li&gt;
&lt;li&gt;have &lt;a href="https://bundler.io/v1.12/"&gt;Bundler&lt;/a&gt; installed.&lt;/li&gt;
&lt;li&gt;have &lt;a href="https://www.postgresql.org/download/"&gt;Postgres&lt;/a&gt; installed.&lt;/li&gt;
&lt;li&gt;have &lt;a href="https://ngrok.com/download"&gt;ngrok&lt;/a&gt; installed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You’ll need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;a href="https://www.twilio.com/"&gt;Twilio account&lt;/a&gt; (the free account is fine)&lt;/li&gt;
&lt;li&gt;a &lt;a href="https://heroku.com/"&gt;Heroku account&lt;/a&gt; (the free account is fine for hosting, but we’ll also use Heroku CI and scheduler, which has a cost)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;First we need to set up Ruby, Postgres, and Twilio.&lt;/p&gt;
&lt;h3&gt;
  
  
  Rails &amp;amp; Gems
&lt;/h3&gt;

&lt;p&gt;I’ve provided a &lt;a href="https://github.com/lolaodelola/dev_affirmations_starter"&gt;starter project&lt;/a&gt; which you should clone to your local directory. To get started, run bundle install.&lt;/p&gt;
&lt;h3&gt;
  
  
  Postgres
&lt;/h3&gt;

&lt;p&gt;If you’ve never run Postgres on your machine (or you’ve stopped it), you’ll need to start the process by running &lt;code&gt;postgres -D /usr/local/pgsql/data&lt;/code&gt;. If you get any errors, check out the &lt;a href="https://www.postgresql.org/docs/9.1/server-start.html"&gt;PSQL start-up guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You may also need to make sure that your database for the project has been created. To do this, you’ll need to run &lt;code&gt;rails db:create&lt;/code&gt; to create the test and development databases.&lt;/p&gt;
&lt;h3&gt;
  
  
  Twilio
&lt;/h3&gt;

&lt;p&gt;Follow the prompts to create a new project on Twilio and when you’re done, you’ll see your dashboard:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hw11upWa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/rk5OcvNU8pXwWOb9CIync4UHfDDFj95dzRP8Hxyl-I6RFLz8AxF0NRYkwBtzFGHrk9vBNoQkpd29wcoH_Crs8DXvfRhZVqcuBDItFcHdbtWPbNPhtY5Nd2nDLzrb79nuXu3Ge-_m" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hw11upWa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh3.googleusercontent.com/rk5OcvNU8pXwWOb9CIync4UHfDDFj95dzRP8Hxyl-I6RFLz8AxF0NRYkwBtzFGHrk9vBNoQkpd29wcoH_Crs8DXvfRhZVqcuBDItFcHdbtWPbNPhtY5Nd2nDLzrb79nuXu3Ge-_m" alt="The Twilio dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the left-hand side, you want to click the three dots in the circle and choose Programmable Messaging. I won’t go into all the details of getting set up on Twilio, as they have a great &lt;a href="https://www.twilio.com/console/sms/getting-started/build"&gt;walk-through guide&lt;/a&gt; that does just that. The important thing to make sure you do is get a phone number as the guide prompts you to do.&lt;/p&gt;
&lt;h2&gt;
  
  
  ENV
&lt;/h2&gt;

&lt;p&gt;Next we need to connect our app to our Twilio account. In your application, create a .env file at the root of your file structure and add the following to it:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You want to make sure you add this file to the .gitignore. That way, you avoid checking sensitive information into git.&lt;/p&gt;

&lt;h2&gt;
  
  
  Models &amp;amp; Data
&lt;/h2&gt;

&lt;p&gt;There are three models we’ll need for this app:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers (our users)&lt;/li&gt;
&lt;li&gt;Affirmations (the messages we send)&lt;/li&gt;
&lt;li&gt;SentAffirmations (keep track of if we've sent the affirmation to each user)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take a detailed look at each one.&lt;/p&gt;

&lt;h3&gt;
  
  
  Developers
&lt;/h3&gt;

&lt;p&gt;These will be our main users. Usually for user objects, I’d use something like &lt;a href="https://github.com/heartcombo/devise"&gt;Devise&lt;/a&gt; to help manage authentication; however, that’s overkill for what we need. So we can simplify things by running:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails g model Developer phone_number:string confirmed:boolean uuid:string&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This is the bare-minimum data that we need to create our developers. The &lt;code&gt;phone_number&lt;/code&gt; will be used to send users messages, &lt;code&gt;confirmed&lt;/code&gt; is needed to get their confirmation for consent to store their details, and &lt;code&gt;uuid&lt;/code&gt; is a unique, difficult-to-guess identifier.&lt;/p&gt;

&lt;p&gt;Once your migration file looks as you'd expect it to, run &lt;code&gt;rails db:migrate&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then, in your developer model you want to add the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;We add a validation to the &lt;code&gt;phone_number&lt;/code&gt; field to make sure there’s always one when a developer is created. We also want to add a scope so that we can easily access confirmed developers.&lt;/p&gt;

&lt;p&gt;We also want to ensure that a uuid gets generated when a developer is created. We can write a test to check this. In spec/models you should see a file called developer_spec.rb. This is where you’re going to write this test:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This small test confirms that, when we create a developer, the uuid isn’t nil (we can then assume that the developer has uuid). In your terminal, run &lt;code&gt;rspec spec/models/developer&lt;/code&gt; to run the test. It should fail.&lt;/p&gt;

&lt;p&gt;To make it pass, we’ll need to add the following code to our model:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;before_create&lt;/code&gt; is a &lt;a href="https://guides.rubyonrails.org/active_record_callbacks.html#callbacks-overview"&gt;Rails callback&lt;/a&gt; to which we can send methods to be invoked. In this case, we’re sending our private method &lt;code&gt;generate_uuid&lt;/code&gt;. It’s private so that only this object has permission to invoke it. Ruby gives us the &lt;code&gt;SecureRandom&lt;/code&gt; class, which we can use to call the handy &lt;code&gt;uuid&lt;/code&gt; method that creates uuids for us. &lt;code&gt;self&lt;/code&gt; is the instance of the class. Using our test as an example, &lt;code&gt;self&lt;/code&gt; would be &lt;code&gt;d&lt;/code&gt; since &lt;code&gt;d&lt;/code&gt; is an instance of Developer. So we’re setting the &lt;code&gt;uuid&lt;/code&gt; on self to be whatever &lt;code&gt;SecureRandom.uuid&lt;/code&gt; gives us, then we’re invoking that method right before the object is created. If you’re new to callbacks, roughly this is what’s happening:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Now when you run &lt;code&gt;rspec spec/models/developer_spec&lt;/code&gt;, your tests should pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Affirmations
&lt;/h3&gt;

&lt;p&gt;These are the messages we’re going to send out. The migration command you want to run is: &lt;code&gt;rails g model Affirmation body:string&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To keep things simple, we only need the body for the affirmation. Run the migration once you’re happy with the file.&lt;/p&gt;

&lt;p&gt;In the Affirmation model, make sure that you validate the presence of the body by adding: &lt;code&gt;validates_presence_of :body&lt;/code&gt; to the top of the file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sent Affirmations
&lt;/h3&gt;

&lt;p&gt;This will act as a join table between Developers and Affirmations, so that we can keep track of which developers have gotten which affirmations.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;rails g model SentAffirmation developer_id:integer affirmation_id:integer sent_at:datetime&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Once you’ve checked that your migration file looks as you expect, run the migration.&lt;/p&gt;

&lt;p&gt;Here, we also want to set up the following relationships:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Make sure the right file has the right relationship.&lt;/p&gt;

&lt;h2&gt;
  
  
  Controllers
&lt;/h2&gt;

&lt;p&gt;Now let's look at the controllers. We'll need two: one for Developers and one for Affirmations. &lt;/p&gt;

&lt;h3&gt;
  
  
  Developers Controller
&lt;/h3&gt;

&lt;p&gt;The developer controller is going to be the longest one since it handles the sign-up process. We’re also going to deviate from convention a little; there won't be any views for our controllers. We'll also create some custom endpoints for this controller.&lt;/p&gt;

&lt;p&gt;First let’s run &lt;code&gt;rails g controllers Developers&lt;/code&gt;. This will give us the developers_controller.rb file, where we want to add the following to the very top of the file:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;skip_before_action :verify_authenticity_token&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;This will remove the CORS authentication so that we can receive params from outside the application, i.e. Twilio. From here, we want to add the following:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's look at the interesting parts of this code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;receive&lt;/code&gt; will be the endpoint we use to receive the texts from our developers which Twilio forwards to us in a webhook. Here, we want to check the body of the request to guarantee we call the right method. In the config/routes.rb file, add &lt;code&gt;get 'twilio/receive', to: developers#receive&lt;/code&gt; so that we have a defined route and can add it as a webhook in Twilio. To do this, you’ll need to run &lt;code&gt;ngrok&lt;/code&gt; in your terminal for the appropriate port number where your rails server will be running. For me, that’s 3000 so it’d be &lt;code&gt;ngrok http 3000&lt;/code&gt;. This will give us a forwarding host.&lt;/p&gt;

&lt;p&gt;Add this host to your config/application.rb with &lt;code&gt;config.hosts &amp;lt;&amp;lt; '&amp;lt;YOUR HOST&amp;gt;.ngrok.io'&lt;/code&gt;. In Twilio, you’ll need to click the three dots in the Twilio menu and select Phone Numbers. Doing so should show you a page with your active numbers. Select your number and you’ll be redirected to a page that allows you to configure the number. If you scroll down to the Messaging section, you’ll see the input for the "A MESSAGE COMES IN" webhook. There, you want to add &lt;code&gt;&amp;lt;YOUR NGROK HOST&amp;gt;.ngrok.io/twilio/recieve&lt;/code&gt;. This will enable Twilio to send the data that reaches the webhook directly to your local app. Use this to test the delivery of texts as you continue to build.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;create&lt;/code&gt; will create our developer object/record using the phone number in the params. When the developer is created, we’re using the Twilio TwiML to send a confirmation text to the developer. Within the text, make sure to include the url for their confirmation link &lt;code&gt;#{preconfirm_url(dev.uuid)}&lt;/code&gt; within the text string. The &lt;code&gt;render xml: twiml.to_xml&lt;/code&gt; makes sure we render the correct file format which is sent to the Twilio API.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;delete&lt;/code&gt; finds and deletes a user should they want to be deleted. Since phone numbers may be less unique than uuids, we could tighten this process by using uuid to find developers. But for now, this is fine.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;preconfirm&lt;/code&gt; just acts as a GET placeholder for confirm. In the routes file, add the corresponding route &lt;code&gt;get: 'developers/:developer_uuid/confirm', to: 'developers#preconfirm, as: 'preconfirm'&lt;/code&gt; This will allow us to set and collect the uuid as a param and also use &lt;code&gt;preconfirm_url&lt;/code&gt; as we’ve given it a name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;confirm&lt;/code&gt; is a private method that updates the confirmed field when a developer clicks the link in our text. It also renders a plain-text confirmation message in the browser. Add the matching route &lt;code&gt;patch 'developers/:developer_uuid/confirm', to: 'developers#confirm'&lt;/code&gt; to the routes file. Notice that it’s a PATCH HTTP method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Affirmations Controller
&lt;/h3&gt;

&lt;p&gt;Our affirmations controller is going to be simpler by comparison since we only need two methods and endpoints. First, let’s create it: &lt;code&gt;rails g controller Affirmations&lt;/code&gt;. We’re also going to be breaking Rails convention here, since we don’t need all the endpoints and also want to include a static page here too.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's look at this code.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;landing&lt;/code&gt; will act as our root path and just renders the static HTML page. In the routes file, you’ll first need to add &lt;code&gt;root affirmations#landing&lt;/code&gt; to the top of the file and then, in views/affirmations, you'll create a HTML file called landing.erb.html with some markup you want people to see when they visit &lt;code&gt;/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;new&lt;/code&gt; instantiates an affirmation which will be available to us in the view. Similar to the landing action, you’ll need to create a view, but this time it’ll be a form with space for a flash notice:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;create&lt;/code&gt; creates an affirmation, then redirects to the new affirmation path with a success notice.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;affirmation_params&lt;/code&gt; is the private method that whitelists and accepts the correct params. We pass it to &lt;code&gt;Affirmation.create&lt;/code&gt; in the create method.&lt;/p&gt;

&lt;p&gt;Add &lt;code&gt;resources :affirmations, only: %i[new create]&lt;/code&gt; to the routes file to ensure you’ve got the correct endpoints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Lib, Task &amp;amp; Job
&lt;/h2&gt;

&lt;p&gt;Composing and sending the affirmation text is going to happen in a lib file, rake task, and job. &lt;a href="https://github.com/ruby/rake"&gt;Rake&lt;/a&gt; is a library that allows developers to create and manage tasks.&lt;/p&gt;

&lt;p&gt;First, we’ll create the lib.&lt;/p&gt;

&lt;h3&gt;
  
  
  Lib
&lt;/h3&gt;

&lt;p&gt;The affirmation text should be a small self-contained class. This is where we’ll be using a bulk of the Twilio API. Before we get started, we want to make sure the lib folder is auto loaded for when the project starts up, so make sure your config/application.rb file has &lt;code&gt;config.autoload_paths&amp;lt;&amp;lt; Rails.root.join('lib')&lt;/code&gt;. Now in the lib folder, you want to create an affirmation_text.rb file. This will be our class for composing the affirmation text.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;initialize&lt;/code&gt; will set our client to be the Twilio client, to which we’re passing the environment variables we defined earlier.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;messages&lt;/code&gt; takes the developer’s phone number and an affirmation. The Twilio client gives us &lt;code&gt;messages.create&lt;/code&gt; which allows us to dynamically create SMS messages with our own values.&lt;/p&gt;

&lt;h3&gt;
  
  
  Job
&lt;/h3&gt;

&lt;p&gt;Instead of sending the messages as we call the method, we actually want to put them in a job queue. By using a job queue here, the server can still accept incoming requests without having to wait for the text to be sent. We can create a job by running &lt;code&gt;rails g job SendAffirmation&lt;/code&gt; . This will give us a send_affirmation_job.rb file in app/jobs. In there, we want to do a few things:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Let's walk through this code.&lt;/p&gt;

&lt;p&gt;First, we want to define the queue we're using by including &lt;code&gt;queue_as: default&lt;/code&gt; at the top of the file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;deliver&lt;/code&gt; is where we’ll tell it what to do when the job is run. It accepts developer and affirmation objects which will be used to send the text message. Since we don’t want to call the actual Twilio API when we’re testing, we can create a mock object. The code checks for the Rails environment. If it’s a test environment, it uses the mock method, if not, it uses the production method.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;send_prod&lt;/code&gt; calls the lib we created in the previous step, which then calls the real Twilio API endpoint.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;send_test&lt;/code&gt; calls our mock object.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;MockAffirmationText&lt;/code&gt; is the mock object, with a message method to mimic &lt;code&gt;AffirmationText&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can also write a test for this job. In our spec/jobs/ you should see a corresponding job file. In that job file, add:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Given that we have some test data (which is what &lt;code&gt;confirmed_dev&lt;/code&gt; and &lt;code&gt;affirmations&lt;/code&gt; are) and we’re using the test queue adapter, when we call &lt;code&gt;SendAffirmationJob.new.deliver(confirmed_dev, affirmations.first)&lt;/code&gt; a job should be queued.&lt;/p&gt;

&lt;h3&gt;
  
  
  Task
&lt;/h3&gt;

&lt;p&gt;Because this will be run on a scheduler, we want to make a rake task that’ll be called at various intervals. In lib/tasks, create a rake file called send_affirmation_task.rb. Your rake file should look like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This will allow us to call rake &lt;code&gt;affirmation:send_text&lt;/code&gt; when we need to. In this block, we’re using the count to create an offset so that we can pick a random affirmation to send. Then for all the confirmed developers (&lt;code&gt;confirmed&lt;/code&gt; comes from our previously defined scope) we trigger the job and create a &lt;code&gt;SentAffirmation&lt;/code&gt; to keep track of our affirmations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heroku
&lt;/h2&gt;

&lt;p&gt;For deployment, we’re going to use Heroku. Heroku is a Platform-as-a-Service (PaaS) provider that makes it easy to deploy and host applications. Using Heroku keeps us from worrying about the details of hosting, building, scaling, etc. We'll use &lt;a href="https://blog.heroku.com/heroku_flow_pipelines_review_apps_and_github_sync"&gt;Heroku pipelines&lt;/a&gt; to create our staging and production apps, and CI to run the tests before each deploy. &lt;/p&gt;

&lt;p&gt;First, we want to make sure we’ve got an app.json file at the root of our project. Mine looks like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You’ll need to make sure that the database cleaner environment variables are set so that the tests run properly on Heroku CI. You’ll also need to make sure you have a Procfile at the root of your app. The &lt;a href="https://devcenter.heroku.com/articles/procfile"&gt;Heroku Procfile&lt;/a&gt; allows us to set the necessary commands for running our web and worker processes. It also allows us to decide what command we should run on each release of the app:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Push this up to your GitHub repo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QJUz0sai--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/jak8TmTRWUzj_ZTD-da1rEZHlWKIN8suDAfNV1mBakzfpef-5tzDnqzEDuLoUyO_4kKhitrVXbi8FIuJC1u8uU8uUGlFWnzwwEXkpCXfdC-wR4R14_bQ6gVVYCUCLrCJnlCxuKao" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QJUz0sai--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/jak8TmTRWUzj_ZTD-da1rEZHlWKIN8suDAfNV1mBakzfpef-5tzDnqzEDuLoUyO_4kKhitrVXbi8FIuJC1u8uU8uUGlFWnzwwEXkpCXfdC-wR4R14_bQ6gVVYCUCLrCJnlCxuKao" alt="Heroku deploy button"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your Heroku account, we'll create a new pipeline. This pipeline will allow us to manage the different environments (i.e. staging and production) for our app. Click New in the right-hand corner and then choose "Create new pipeline". Follow the prompts and connect it to the correct GitHub repo. Once everything has been created, your tests will run in the Tests tab and should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9TMbS_Sc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/X_PZbFv-gv0Bv4RjRh8IoZ7CCocdYLSr_WFaMUhGqr42yxwH3PioPSG2DxN3znVhwuRR5wBzdIxv24GGmiyz1w0ECEMv6Ol0Uv_xIYfqoz2dxAwSCS2NVgMzb5raBv4noOFtn32c" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9TMbS_Sc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/X_PZbFv-gv0Bv4RjRh8IoZ7CCocdYLSr_WFaMUhGqr42yxwH3PioPSG2DxN3znVhwuRR5wBzdIxv24GGmiyz1w0ECEMv6Ol0Uv_xIYfqoz2dxAwSCS2NVgMzb5raBv4noOFtn32c" alt="Heroku test dashboard"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we can create our staging and production apps. In Pipeline under staging and production, you’ll see the option to "add app".  Click this and create a new app under each. Once this is done, we'll also use the Heroku UI to provision a database for each and a scheduler instance for the production app. You do this by clicking on the app name &amp;gt; "Resources". In the search box search for "Heroku Postgres" and "Heroku Scheduler". Even though you've provisioned the databases for each app, you still need to run the migrations. So for each app, go to More &amp;gt; Run Console&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PzC74Cz7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://39296.cdn.cke-cs.com/xnX5w1TWo7hQQOywFbkx/images/e1dcf77be01da7e134a919c07bf4db6a1bc925f17456fd00.png/w_522" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PzC74Cz7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://39296.cdn.cke-cs.com/xnX5w1TWo7hQQOywFbkx/images/e1dcf77be01da7e134a919c07bf4db6a1bc925f17456fd00.png/w_522" alt="Heroku 'more' menu open with 'run console' highlighted"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the modal that appears, run &lt;code&gt;rake db:migrate&lt;/code&gt;. Remember to do this for both your staging and production apps.&lt;/p&gt;

&lt;p&gt;To configure the scheduler, create a scheduled job that runs the rake task we created, so &lt;code&gt;rake affirmation:send_text&lt;/code&gt; which should look like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p7btHX88--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/VsNmEmKDLheTj-OqFwwM90II67Hv0oClODtT0VKIpjhbO-b-IvHyaI-Y4nXIBx1-ay0nRUkjrot9Q3mtRwei8I0mAAJPC5i_h5VIn1jvwxToSSnQJQbub5F51t99jbYBs8UlFphH" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p7btHX88--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/VsNmEmKDLheTj-OqFwwM90II67Hv0oClODtT0VKIpjhbO-b-IvHyaI-Y4nXIBx1-ay0nRUkjrot9Q3mtRwei8I0mAAJPC5i_h5VIn1jvwxToSSnQJQbub5F51t99jbYBs8UlFphH" alt="Heroku scheduler interface"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For each of the apps, we want to enable automatic deploys when the CI passes. The arrows on the right-hand side of the app components in the Pipeline will show more options. For example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IcZKPY85--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/-3w90lQT46ZeBk8ykN_Ain33AmySMoBqONgYjnpVeQ29jlnMDLJoajaDkEO9qxC6RNszcI8c5_Q7GTRMS9yqU5mHwPcyWfCQ2EUD9AZuKVlxYGwfI-7kRrMJPCA-8ZYG4Cu1z3VF" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IcZKPY85--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh5.googleusercontent.com/-3w90lQT46ZeBk8ykN_Ain33AmySMoBqONgYjnpVeQ29jlnMDLJoajaDkEO9qxC6RNszcI8c5_Q7GTRMS9yqU5mHwPcyWfCQ2EUD9AZuKVlxYGwfI-7kRrMJPCA-8ZYG4Cu1z3VF" alt="Heroku promotion menu"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You want to click "Configure automatic deploys" which will show this modal:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ThjviOzr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/rT1joQXILknZqBGaDSR6Hh37nhxF9guLyKgeEKBlRZQP2qCMSFi5CpCH4dos_Wd06Fy8MITk21sbvZbwh-ooMogV2dixyv3Tyur_oX3fsAkXS9T0YvPHFxh8WoF5rIxmBeIgjwvJ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ThjviOzr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh6.googleusercontent.com/rT1joQXILknZqBGaDSR6Hh37nhxF9guLyKgeEKBlRZQP2qCMSFi5CpCH4dos_Wd06Fy8MITk21sbvZbwh-ooMogV2dixyv3Tyur_oX3fsAkXS9T0YvPHFxh8WoF5rIxmBeIgjwvJ" alt="Heroku automatic deploy modal"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ensure that "Wait for CI to pass before deploy" is checked, then hit "Enable Automatic Deploys".’ Now whenever you hit "push to master", your tests will run. Once they pass, your app will be deployed. And because we’re using the &lt;a href="https://devcenter.heroku.com/articles/release-phase"&gt;Heroku release phase&lt;/a&gt; to manage our migrations, they’ll also run automatically with every release.&lt;/p&gt;

&lt;p&gt;The last thing you want to ensure is that your environment variables are set up properly. We don’t want to add the secret variables to our app.json since that would make them public. But in the settings for each of your staging and production apps, you can add config variables, so set the variables we defined in our .env here too:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ebh98Nvf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/TRb7tIp1NPNysgZj0Bhm2OsBMAlRBKPXjgAi6yJv0l2y_Mge8NAVP5_xl-Woig-MDbNSUkQBnzhQFcCoyxdwzAvNYuROOydzQfSr1s4v-HWtvzQrRC1KjEKN90HMFjZ3eJfAXNbh" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ebh98Nvf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://lh4.googleusercontent.com/TRb7tIp1NPNysgZj0Bhm2OsBMAlRBKPXjgAi6yJv0l2y_Mge8NAVP5_xl-Woig-MDbNSUkQBnzhQFcCoyxdwzAvNYuROOydzQfSr1s4v-HWtvzQrRC1KjEKN90HMFjZ3eJfAXNbh" alt="Heroku Config Vars settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the staging app, the variables should be the same as in our .env. But for the production app, you want to make sure that you’re using the production Twilio SID and Token which you can find in your Twilio account.&lt;/p&gt;

&lt;h2&gt;
  
  
  The App in Action
&lt;/h2&gt;

&lt;p&gt;Now we're ready to run the app! Let's see what it looks like in action:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Y1Gdh0H5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://39296.cdn.cke-cs.com/xnX5w1TWo7hQQOywFbkx/images/634840ac2b1309e55e577dc552575fecb21f701394d6681b.png/w_2560" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y1Gdh0H5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://39296.cdn.cke-cs.com/xnX5w1TWo7hQQOywFbkx/images/634840ac2b1309e55e577dc552575fecb21f701394d6681b.png/w_2560" alt="App landing page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aJBmbIDy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://39296.cdn.cke-cs.com/xnX5w1TWo7hQQOywFbkx/images/8e92aeb061f5229cda54198362ee9d8b96da15aa513b0339.png/w_2560" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aJBmbIDy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://39296.cdn.cke-cs.com/xnX5w1TWo7hQQOywFbkx/images/8e92aeb061f5229cda54198362ee9d8b96da15aa513b0339.png/w_2560" alt="App affirmation submition form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KFrX_7UE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://39296.cdn.cke-cs.com/xnX5w1TWo7hQQOywFbkx/images/2fb84aaafd9cdabd3986c6d5d425fdd4a508c2c4bbab1852.jpeg/w_976" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KFrX_7UE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://39296.cdn.cke-cs.com/xnX5w1TWo7hQQOywFbkx/images/2fb84aaafd9cdabd3986c6d5d425fdd4a508c2c4bbab1852.jpeg/w_976" alt="SMS affirmation message"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Notes on Costs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;You can host basic apps on Heroku for free. However, Heroku CI costs $10 a month to use&lt;/li&gt;
&lt;li&gt;Heroku Scheduler has a free tier, but the dynos it uses to run are only paid dynos, so you’ll have to pay for the usage costs of those too.&lt;/li&gt;
&lt;li&gt;Twilio gives you a free $20 to test with, however you'll need to top up your account when you move to a production environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I've used Heroku's pipeline and CI in other production apps, but in those places everything was already set up. I've always found this aspect of Heroku a bit intimidating, but creating this fun little app allowed me to get familiar with the features, particularly the CI. There's still some work to be done to move this app to production. For example, a moderation feature is necessary to stop people from submitting weird affirmations, and some type of limitation on the texts would be good to limit costs. There's a lot of scope to play around with, &lt;a href="https://github.com/lolaodelola/dev_affirmations_starter"&gt;so have fun&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>heroku</category>
      <category>ci</category>
      <category>pipelines</category>
    </item>
    <item>
      <title>Promises for Rubyists</title>
      <dc:creator>Lola</dc:creator>
      <pubDate>Mon, 07 Dec 2020 10:57:42 +0000</pubDate>
      <link>https://dev.to/samsunginternet/promises-for-rubyists-2loe</link>
      <guid>https://dev.to/samsunginternet/promises-for-rubyists-2loe</guid>
      <description>&lt;h1&gt;
  
  
  The Soundtrack
&lt;/h1&gt;

&lt;p&gt;I tried to write a post about JavaScript Promises using Ciara - Promise, but it didn't work so instead have this genre-agnostic playlist of 10 songs with the title Promise. Don't let my hard work be in vain &amp;amp; have a listen.&lt;br&gt;
&lt;iframe width="100%" height="380px" src="https://open.spotify.com/embed/playlist/6mvCLTreLdT2gBMTwUeTKJ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  The Background
&lt;/h1&gt;

&lt;p&gt;JavaScript and Ruby are both single-threaded programming languages, they can really only do one thing at a time, in a particular order. This also means they're both synchronous. They run in a queue-like way, the first operation or function to get called is the first to be performed before any other operation is performed, this presents a problem the moment you want to do anything that requires multi-tasking. Both languages have workarounds, modules, gems and in-built features that can allow you to write asynchronous code, e.g. JavaScript's &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API"&gt;Web Workers&lt;/a&gt; or background jobs in Ruby. JavaScript also has promises, the topic of today, which Ruby doesn't have an in-built match for at the moment, so I'm going to try my best to recreate what this could look like.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Promise
&lt;/h1&gt;

&lt;p&gt;It's a commitment to give you &lt;em&gt;something&lt;/em&gt; later, it'll either be the thing you ask for or an error but you'll definitely get something.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Essentially, a promise is a returned object to which you attach callbacks, instead of passing callbacks into a function.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;-&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Callbacks in Ruby
&lt;/h3&gt;

&lt;p&gt;In Ruby, we really mainly deal with callbacks in the context of Rails (or other web framework) when we're manipulating objects during their creation phase. You might have used a &lt;code&gt;before_create: :do_thing&lt;/code&gt; in a model, this is generally what callbacks are in Rails (not necessarily Ruby), and there are a &lt;a href="https://guides.rubyonrails.org/active_record_callbacks.html"&gt;list of them&lt;/a&gt;. But using plain old Ruby, you'd have a method that you could pass a block to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="n"&gt;total&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
     &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;total&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;add_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"the total is &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;total&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The callback here is the block we pass to &lt;code&gt;add_one(5)&lt;/code&gt; which is then called with our &lt;code&gt;yield&lt;/code&gt; in the definition of the method. So here we're passing the callback to the method.&lt;/p&gt;

&lt;h3&gt;
  
  
  Callbacks in JavaScript
&lt;/h3&gt;

&lt;p&gt;Unlike Ruby, JavaScript functions can accept functions as arguments but not blocks which means you'd create dedicated callback functions in a JS context.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getTotal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;the total is ${total}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;addOne&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;getTotal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we're also passing the callback to the function, similar to the Ruby implementation. This is synchronous since a blocking operation (the &lt;code&gt;addOne&lt;/code&gt;) needs to happen first before the callback can happen.&lt;/p&gt;

&lt;h1&gt;
  
  
  Implementation
&lt;/h1&gt;

&lt;p&gt;There isn't a native way to write promises in Ruby but just to illustrate the functionality, imagine being able to send data between your controller and view without refreshing the page in Ruby, with no JavaScript. It's the stuff dreams are made of but in the real world we need JavaScript.&lt;/p&gt;

&lt;p&gt;I've been working on the &lt;a href="https://medium.com/samsung-internet-dev/samsung-the-global-goals-web-debuts-f8cdae4ec21d"&gt;Samsung's Global Goals&lt;/a&gt; PWA and in this I've had to use promises to interact with Stripe and the Payment Request API. Let's see a real world example of this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
  &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fetchPaymentIntentClientSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchedPaymentIntentCS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/fetchPaymentIntent/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;clientSecretObj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fetchedPaymentIntentCS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;clientSecretObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

 &lt;span class="nx"&gt;fetchPaymentIntentClientSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;confirmPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;fetchPaymentIntentClientSecret&lt;/code&gt; function is defined using the keyword &lt;code&gt;async&lt;/code&gt;, in the function we make a call to the server using &lt;code&gt;await&lt;/code&gt; and &lt;code&gt;fetch&lt;/code&gt; this call then gives us back some data which we return. The &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; functions are important here:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; keywords enable asynchronous, promise-based behaviour to be written in a asynchronous style, avoiding the need to explicitly configure promise chains.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The function could also be written like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;fetchPaymentIntentClientSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/fetchPaymentIntent/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// response.json also returns a promise since it has to wait for the response to finish before it can parse it&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientSecretObj&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;clientSecretObj&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// extract the thing you need from the response&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fetchPaymentIntentCSPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fetchPaymentIntentClientSecret&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;confirmPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;paymentRequest&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that &lt;code&gt;fetchPaymentIntentClientSecret&lt;/code&gt; actually returns a promise. &lt;code&gt;async&lt;/code&gt; and &lt;code&gt;await&lt;/code&gt; are just syntactic sugar for the promises syntax. Using these keywords together, along with &lt;code&gt;fetch&lt;/code&gt; allows us to make the asynchronous call to the server. So when we actually call the function, because it's a promise, we can chain the callbacks and really take advantage of the asynchronous nature. The &lt;code&gt;clientSecret&lt;/code&gt; is returned from the server and we can pass that to the next function that needs it if the call is successful and if it's not, we can log the error instead.&lt;/p&gt;

&lt;p&gt;All without the page being refreshed or modified.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Note
&lt;/h3&gt;

&lt;p&gt;You might have seen promise syntax that looks like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;myFancyFunc&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// does something&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFancyFuncPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;myFancyFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and you're wondering why I haven't done that here. Well, the syntax is different if you're working with a promise-based API, which I am. In our example &lt;code&gt;fetch&lt;/code&gt; returns a promise as does &lt;code&gt;response.json&lt;/code&gt; so we need to treat them as such. &lt;code&gt;new Promise&lt;/code&gt; is used to make promises out of async APIs which are not promise based, e.g. the callback based functions we defined earlier.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why?
&lt;/h1&gt;

&lt;p&gt;Within the context web development, promises are unique to JavaScript in that they're native. Coming from a Ruby background I found them strange, why not just do these things in a background job? But honestly, a small action like retrieving a client secret doesn't need to be done in a job (and probably shouldn't be) and it's probably not the best user experience to reload the page just to get a client secret, especially if the user hasn't triggered it.&lt;/p&gt;

&lt;p&gt;Promises can also be quite complex to get your head around, this post is a primer but I'd encourage you to read more:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(Using Promises)[&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises&lt;/a&gt;]&lt;/li&gt;
&lt;li&gt;(Promise)[&lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise"&gt;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
