<?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: thomasvanholder</title>
    <description>The latest articles on DEV Community by thomasvanholder (@thomasvanholder).</description>
    <link>https://dev.to/thomasvanholder</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%2F507235%2F60ddcad4-dde3-448b-aa93-0ebc82d45508.png</url>
      <title>DEV Community: thomasvanholder</title>
      <link>https://dev.to/thomasvanholder</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thomasvanholder"/>
    <language>en</language>
    <item>
      <title>Create a modal with the HTML dialog element, Tailwind and Stimulus</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Fri, 29 Jul 2022 08:24:00 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/create-a-modal-with-the-html-dialog-element-tailwind-and-stimulus-573b</link>
      <guid>https://dev.to/thomasvanholder/create-a-modal-with-the-html-dialog-element-tailwind-and-stimulus-573b</guid>
      <description>&lt;p&gt;Support for the dialog element is now widespread, with safari being the last of the main browsers to provide &lt;a href="https://caniuse.com/?search=dialog" rel="noopener noreferrer"&gt;native support&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dialog" rel="noopener noreferrer"&gt;dialog HTML element&lt;/a&gt; is an appealing choice for creating a modal as it comes with built-in functionality for &lt;strong&gt;opening&lt;/strong&gt; and &lt;strong&gt;closing&lt;/strong&gt; modals.&lt;/p&gt;

&lt;p&gt;This tutorial uses Stimulus as a light-weight JavaScript framework. To learn more about Stimulus, visit the &lt;a href="https://stimulus.hotwired.dev/" rel="noopener noreferrer"&gt;docs&lt;/a&gt;. When you use  vanilla JS, you can mimic the &lt;code&gt;data-action&lt;/code&gt; and &lt;code&gt;data-target&lt;/code&gt; behavior in by utilizing the appropriate &lt;code&gt;document.querySelector&lt;/code&gt;s and &lt;code&gt;eventListener&lt;/code&gt;s instead.&lt;/p&gt;

&lt;p&gt;The form and button styling are extrapolated to improve readability. &lt;a href="https://gist.github.com/thomasvanholder/4e71ffea4bcdb4984b466c7758dbfa36" rel="noopener noreferrer"&gt;See here&lt;/a&gt; for a full gist of the CSS, HTML and JS.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;1. Add button and dialog&lt;/li&gt;
&lt;li&gt;2. Close modal by esc key&lt;/li&gt;
&lt;li&gt;3. Close modal by backdrop click&lt;/li&gt;
&lt;li&gt;4. Reset form after modal close&lt;/li&gt;
&lt;li&gt;5. Change default backdrop style&lt;/li&gt;
&lt;li&gt;6. Add animation&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  1. Add button and dialog
&lt;/h2&gt;

&lt;p&gt;To start, let's create a &lt;code&gt;button&lt;/code&gt; and &lt;code&gt;dialog&lt;/code&gt; element wrapped in a &lt;a href="https://stimulus.hotwired.dev/reference/controllers" rel="noopener noreferrer"&gt;stimulus controller&lt;/a&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;data-controller=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;data-action=&lt;/span&gt;&lt;span class="s"&gt;"modal#open"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-outline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Open modal&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;dialog&lt;/span&gt; &lt;span class="na"&gt;data-modal-target=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;data-action=&lt;/span&gt;&lt;span class="s"&gt;"modal#close"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"absolute top-4 right-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;X&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Reset your password&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;hr&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mb-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"space-y-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;Email&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;data-action=&lt;/span&gt;&lt;span class="s"&gt;"modal#close"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-outline"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Close&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Reset Password&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dialog&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;The corresponding stimulus controller is pretty barebones.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;//app/javascript/controllers/modal_controller.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@hotwired/stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/showModal" rel="noopener noreferrer"&gt;showModal()&lt;/a&gt; method displays the modal  on the top layer and adds a default background. Any interaction outside the dialog is inaccessible.&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLDialogElement/close" rel="noopener noreferrer"&gt;close()&lt;/a&gt; method simply closes the dialog.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsmwt9vilijlq2iqft142.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%2Fsmwt9vilijlq2iqft142.gif" alt="Button and dialog"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Close modal by esc key
&lt;/h2&gt;

&lt;p&gt;This is an easy one. Closing the modal by escape key is included by default when utilising the dialog element. Nice!&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Close modal by backdrop click
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Remove all default padding on the dialog element to ensure only a background click triggers the closing of the modal.&lt;/li&gt;
&lt;li&gt;Add padding on the &lt;code&gt;h1&lt;/code&gt; and &lt;code&gt;form&lt;/code&gt; element instead.&lt;/li&gt;
&lt;/ul&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;dialog&lt;/span&gt; &lt;span class="na"&gt;data-modal-target=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 ...
 &lt;span class="nt"&gt;&amp;lt;h1&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Reset your password&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

 &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-4 space-y-4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   ...
 &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;Add an &lt;code&gt;eventListener&lt;/code&gt; that initiates after opening the modal to listen for the backdrop click.&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ....&lt;/span&gt;
  &lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;showModal&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;click&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;backdropClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;backdropClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalTarget&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;backdropClick()&lt;/code&gt; method verifies if the clicked element is the dialog and, if so, closes the modal.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Reset form after modal close
&lt;/h2&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%2Fmv6pcqj7ad15x79c0mjd.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%2Fmv6pcqj7ad15x79c0mjd.gif" alt="reset form"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The form still populates previously filled input after closing and re-opening the modal. To start the modal with empty inputs, add a form target and reset the form.&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;form&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-4 space-y-4"&lt;/span&gt; &lt;span class="na"&gt;data-modal-target=&lt;/span&gt;&lt;span class="s"&gt;"form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  ...
&lt;span class="nt"&gt;&amp;lt;/form&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 javascript"&gt;&lt;code&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@hotwired/stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modalTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;formTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// or find by id selector&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;h2&gt;
  
  
  5. Change default backdrop style
&lt;/h2&gt;

&lt;p&gt;Add the &lt;code&gt;backdrop&lt;/code&gt; selector to the dialog html element.&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;dialog&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-0 backdrop:bg-gray-400 backdrop:bg-opacity-50"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 ...
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;




&lt;h2&gt;
  
  
  6. Add animation
&lt;/h2&gt;

&lt;p&gt;The default animation is quite abrupt and appears instantaneous on the screen. To make the transition smoother, let's add a fade-in &lt;a href="https://tailwindcss.com/docs/animation#customizing-your-theme" rel="noopener noreferrer"&gt;custom animation&lt;/a&gt; with a duration of 0.5 seconds.&lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;tailwind.config.js&lt;/code&gt; file, add a fade-in &lt;code&gt;keyframe&lt;/code&gt; and &lt;code&gt;animation&lt;/code&gt;. The effect can be applied using the &lt;code&gt;animate-fade-in&lt;/code&gt; class.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ... &lt;/span&gt;
  &lt;span class="na"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;extend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;keyframes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fade-in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;0%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;opacity&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;100%&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;animation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fade-in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fade-in 0.5s ease-in-out&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;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;Next, add the newly created animation to the dialog element using the &lt;a href="https://tailwindcss.com/docs/hover-focus-and-other-states#open-closed-state" rel="noopener noreferrer"&gt;open modifier&lt;/a&gt;: &lt;code&gt;open:animate-fade-in&lt;/code&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;dialog&lt;/span&gt; &lt;span class="na"&gt;data-modal-target=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-0 backdrop:bg-gray-400 backdrop:bg-opacity-50 open:animate-fade-in"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 ...
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You can easily add this animation to the backdrop as well: &lt;code&gt;open:backdrop:animate-fade-in&lt;/code&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;dialog&lt;/span&gt; &lt;span class="na"&gt;data-modal-target=&lt;/span&gt;&lt;span class="s"&gt;"modal"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-0 backdrop:bg-gray-400 backdrop:bg-opacity-50 open:animate-fade-in open:backdrop:animate-fade-in"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
 ...
&lt;span class="nt"&gt;&amp;lt;/dialog&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;




&lt;p&gt;That's it! Using the dialog element simplifies creating modals by leveraging its build-in API features.&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%2Fw136ut9gudn642k7bw7o.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%2Fw136ut9gudn642k7bw7o.gif" alt="Final"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>html</category>
      <category>stimulus</category>
      <category>javascript</category>
    </item>
    <item>
      <title>How to migrate rails sprockets to propshaft</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Wed, 16 Mar 2022 16:08:21 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/how-to-migrate-rails-sprockets-to-propshaft-2ad5</link>
      <guid>https://dev.to/thomasvanholder/how-to-migrate-rails-sprockets-to-propshaft-2ad5</guid>
      <description>&lt;p&gt;Propshaft has a smaller scope than sprockets and requires you to rely on the &lt;a href="https://github.com/rails/jsbundling-rails"&gt;js-bundling&lt;/a&gt; and &lt;a href="https://github.com/rails/cssbundling-rails"&gt;css-bundling&lt;/a&gt; gems to handle the building of CSS and JS assets. Read the &lt;a href="https://github.com/rails/propshaft/blob/main/UPGRADING.md"&gt;docs&lt;/a&gt; for an extensive upgrade guide.&lt;/p&gt;

&lt;p&gt;To migrate from webpacker to js-bundling, you can read &lt;a href="https://dev.to/thomasvanholder/how-to-migrate-from-webpacker-to-jsbundling-rails-esbuild-5f2"&gt;this article&lt;/a&gt;.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;Depreciate Sprockets&lt;/li&gt;
&lt;li&gt;Install Propshaft&lt;/li&gt;
&lt;li&gt;Migrate Asset Helpers&lt;/li&gt;
&lt;li&gt;Display inline SVG&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Depreciate Sprockets
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Remove the &lt;code&gt;gem "sprockets"&lt;/code&gt; from Gemfile&lt;/li&gt;
&lt;li&gt;Delete the &lt;code&gt;config/assets.rb&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Delete the &lt;code&gt;assets/config/manifest.js&lt;/code&gt; file&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  2. Install Propshaft
&lt;/h2&gt;

&lt;p&gt;Add to Gemfile&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;gem&lt;/span&gt; &lt;span class="s2"&gt;"propshaft"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Migrate asset helpers
&lt;/h2&gt;

&lt;p&gt;Replace asset helpers like &lt;code&gt;image_url&lt;/code&gt; and &lt;code&gt;font_url&lt;/code&gt; in css files with standard URLs because Sprockets uses absolute paths while Propshaft uses relative paths. Make sure to prepend the asset path with &lt;code&gt;/&lt;/code&gt; to link to the asset.&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="c"&gt;/* old */&lt;/span&gt;
&lt;span class="nt"&gt;image_url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"home.png"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;/* new */&lt;/span&gt;
&lt;span class="nt"&gt;url&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;"/home.png"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Display inline svg
&lt;/h2&gt;

&lt;p&gt;Before Propshaft loading inline SVG requires to dump a long SVG content inline or to leverage a gem like &lt;a href="https://github.com/jamesmartin/inline_svg"&gt;inline_svg&lt;/a&gt;. Propshaft offers the ability to render inline svg's.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;assets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'logo.svg'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;content&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rails</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to turn on Rails 7 framework defaults (part 1)</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Fri, 21 Jan 2022 09:39:06 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/rails-7-framework-defaults-part-1-2a59</link>
      <guid>https://dev.to/thomasvanholder/rails-7-framework-defaults-part-1-2a59</guid>
      <description>&lt;p&gt;This tutorial inspects turning on each setting of &lt;code&gt;new_framework_defaults_7.0.rb&lt;/code&gt; file. The intended goal is to fully migrate to Rails 7's default set-up.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;button_to_generates_button_tag&lt;/li&gt;
&lt;li&gt;apply_stylesheet_media_default&lt;/li&gt;
&lt;li&gt;verify_foreign_keys_for_fixtures&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. button_to_generates_button_tag
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;button_to_generates_button_tag&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;button_to&lt;/strong&gt; helper had inconsistent behaviour. &lt;a href="https://github.com/rails/rails/pull/40747"&gt;Rails PR&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;string argument: &lt;code&gt;&amp;lt;input type="submit"&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;block argument: &lt;code&gt;&amp;lt;button type="submit"&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# 'new' is the string argument&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sx"&gt;%= button_to "New", new_task_path %&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"New"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;New&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. apply_stylesheet_media_default
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;action_view&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;apply_stylesheet_media_default&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;stylesheet_link_tag&lt;/code&gt; can specify a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/@media#media_types"&gt;media type&lt;/a&gt;. When omitting a media attribute, &lt;code&gt;screen&lt;/code&gt; is no longer set as the default media value &lt;a href="https://edgeguides.rubyonrails.org/configuring.html#config-action-view-apply-stylesheet-media-default"&gt;Rails Guide&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;stylesheet_link_tag&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Before
&lt;/h3&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;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"...css"&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"screen"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  After
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"...css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. verify_foreign_keys_for_fixtures
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;active_record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify_foreign_keys_for_fixtures&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What
&lt;/h3&gt;

&lt;p&gt;Ensures all foreign key constraints are valid after fixtures are loaded in tests. &lt;a href="https://github.com/rails/rails/pull/42674?hmsr=joyk.com&amp;amp;utm_source=joyk.com&amp;amp;utm_medium=referral"&gt;Rails PR&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Before
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# test/fixtures/parrots.yml&lt;/span&gt;
&lt;span class="ss"&gt;george:
  name: &lt;/span&gt;&lt;span class="s2"&gt;"Curious George"&lt;/span&gt;
  &lt;span class="ss"&gt;pirate: &lt;/span&gt;&lt;span class="n"&gt;redbeard&lt;/span&gt;

&lt;span class="c1"&gt;# test/fixtures/pirates.yml&lt;/span&gt;
&lt;span class="ss"&gt;blackbeard:
  name: &lt;/span&gt;&lt;span class="s2"&gt;"Blackbeard"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fixtures can refer to a missing association.&lt;br&gt;
&lt;code&gt;parrots(:george).pirate&lt;/code&gt; will be &lt;code&gt;nil&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  After
&lt;/h3&gt;

&lt;p&gt;An error is raised when fixtures are loaded in tests.&lt;br&gt;
&lt;code&gt;"Foreign key violations found in your fixture data. Ensure you aren't referring to labels that don't exist on associations."&lt;/code&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to set-up Rails Hotwire  live reload</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Sat, 08 Jan 2022 09:25:31 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/how-to-set-up-rails-hotwire-live-reload-38i9</link>
      <guid>https://dev.to/thomasvanholder/how-to-set-up-rails-hotwire-live-reload-38i9</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Install Gem&lt;/li&gt;
&lt;li&gt;Run install script&lt;/li&gt;
&lt;li&gt;Listen to file changes&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;This tutorial will explore a modern way to &lt;a href="https://github.com/kirillplatonov/hotwire-livereload"&gt;live-reload&lt;/a&gt; a rails app set-up with &lt;strong&gt;css-bundling&lt;/strong&gt; (tailwind) and &lt;strong&gt;js-bundling&lt;/strong&gt; (esbuild).&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Install Gem
&lt;/h2&gt;

&lt;p&gt;Add to &lt;code&gt;Gemfile&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"hotwire-livereload"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Run install script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails livereload:install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Listen to file changes
&lt;/h2&gt;

&lt;p&gt;View, helpers, and assets files are listened for by &lt;a href="https://github.com/kirillplatonov/hotwire-livereload#configuration"&gt;default&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you use rails's &lt;code&gt;css-bundling&lt;/code&gt; and &lt;code&gt;js-bundling&lt;/code&gt; gems, find the bundled JS and CSS file &lt;code&gt;app/builds&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The app/builds folder includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;app/builds/application.css&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app/builds/application.js&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An additional watch process is needed to re-build the JS and CSS file after changes (see &lt;a href="https://github.com/rails/jsbundling-rails#javascript-bundling-for-rails"&gt;docs&lt;/a&gt;). Tailwind, for example, uses a Just-in-time compiler to only add classes to the CSS that are being used in your application. This requires specifying an additional path to listen for any (Just-in-time) changes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# config/environments/development.rb&lt;/span&gt;

&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;hotwire_livereload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen_paths&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"app/assets/builds"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rails</category>
      <category>hotwire</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>How to upgrade your Rails app to Ruby 3.1 with rbenv</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Wed, 29 Dec 2021 12:55:57 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/how-to-upgrade-your-rails-app-to-ruby-31-with-rbenv-5efl</link>
      <guid>https://dev.to/thomasvanholder/how-to-upgrade-your-rails-app-to-ruby-31-with-rbenv-5efl</guid>
      <description>&lt;p&gt;Ruby 3.1 release &lt;a href="https://www.ruby-lang.org/en/news/2021/12/25/ruby-3-1-0-released/"&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Upgrade rbenv&lt;/li&gt;
&lt;li&gt;Install Ruby 3.1.0&lt;/li&gt;
&lt;li&gt;Set local Ruby version&lt;/li&gt;
&lt;li&gt;Update Gemfile&lt;/li&gt;
&lt;li&gt;Debug gem&lt;/li&gt;
&lt;li&gt;New features&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Upgrade rbenv
&lt;/h2&gt;

&lt;p&gt;To include Ruby 3.1 as one of the available install options, first upgrade ruby-build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;brew update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew upgrade ruby-build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See all available versions with &lt;code&gt;rbenv install --list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Ruby &lt;code&gt;3.1.0&lt;/code&gt; should return in the result.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Install Ruby 3.1.0
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rbenv &lt;span class="nb"&gt;install &lt;/span&gt;3.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Set local Ruby version
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rbenv &lt;span class="nb"&gt;local &lt;/span&gt;3.1.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify that the &lt;code&gt;.ruby-version&lt;/code&gt; file in the root of your folder now lists version 3.1.0.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Update Gemfile
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# old&lt;/span&gt;
&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="s2"&gt;"3.0.3"&lt;/span&gt;

&lt;span class="c1"&gt;# new&lt;/span&gt;
&lt;span class="n"&gt;ruby&lt;/span&gt; &lt;span class="s2"&gt;"3.1.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tip: You can link to the ruby &lt;code&gt;.ruby_version&lt;/code&gt; file instead to read the ruby version. A single source defines the ruby version and you avoid a discrepancy between the &lt;code&gt;gemfile&lt;/code&gt; and &lt;code&gt;.ruby_version&lt;/code&gt; file to occur.&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;ruby&lt;/span&gt; &lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'.ruby-version'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might run into the error &lt;strong&gt;cannot load such file -- net/smtp (LoadError)&lt;/strong&gt;. &lt;code&gt;net-smtp&lt;/code&gt; has been removed from the default gems in ruby 3.1. As &lt;a href="https://github.com/rails/rails/pull/42366"&gt;Action Mailbox&lt;/a&gt; depends on net/smtp temporarily add to your gemfile until the &lt;code&gt;mail&lt;/code&gt; gem includes it as a dependancy.&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;gem&lt;/span&gt; &lt;span class="s2"&gt;"net-smtp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;require: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Debug gem
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/ruby/debug"&gt;debug gem&lt;/a&gt; is the new preferred debugger. Alternative gems like &lt;code&gt;pry&lt;/code&gt; are no longer necessary. Rails 7 includes the debug gem &lt;a href="https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem"&gt;by default&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Gemfile:&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;group&lt;/span&gt; &lt;span class="ss"&gt;:development&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:test&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# old&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s1"&gt;'pry'&lt;/span&gt;
  &lt;span class="c1"&gt;# new&lt;/span&gt;
  &lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"debug"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"&amp;gt;= 1.0.0"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Learn more in this &lt;a href="https://www.youtube.com/watch?v=XeWHrsp6nwo&amp;amp;list=PLbHJudTY1K0f0oMhWtY-UyzOb7tUlaHps&amp;amp;index=99"&gt;video&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  6. New Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Error highlighting &lt;a href="https://github.com/ruby/error_highlight"&gt;examples&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;IRB auto-completion&lt;/li&gt;
&lt;li&gt;Typeprof &lt;a href="https://github.com/ruby/typeprof/blob/master/doc/demo.md"&gt;examples&lt;/a&gt; / &lt;a href="https://github.com/ruby/typeprof/blob/master/doc/ide.md"&gt;vs code extension&lt;/a&gt; / &lt;a href="https://www.youtube.com/watch?v=UTMj51j9yEg&amp;amp;list=PLbHJudTY1K0f0oMhWtY-UyzOb7tUlaHps&amp;amp;index=103"&gt;video&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Short Syntax Hash Values &lt;a href="https://dev.to/baweaver/ruby-3-1-shorthand-hash-syntax-first-impressions-19op"&gt;examples&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>migration</category>
      <category>tutorial</category>
      <category>rails</category>
    </item>
    <item>
      <title>How to upgrade Rails 6.1 to Rails 7</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Wed, 22 Dec 2021 13:51:08 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/how-to-upgrade-rails-61-to-rails-7-33a3</link>
      <guid>https://dev.to/thomasvanholder/how-to-upgrade-rails-61-to-rails-7-33a3</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Update rails in gemfile&lt;/li&gt;
&lt;li&gt;Upgrade rails packages&lt;/li&gt;
&lt;li&gt;Add sprockets to gemfile&lt;/li&gt;
&lt;li&gt;Run update rails task&lt;/li&gt;
&lt;li&gt;Verify framework defaults&lt;/li&gt;
&lt;li&gt;Verify depreciated methods&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;How to upgrade an exising application to Rails 7. Note that Rails 7 requires Ruby 2.7.0 or newer.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Update rails in gemfile
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# old&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"rails"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 6.1.4"&lt;/span&gt;

&lt;span class="c1"&gt;# new&lt;/span&gt;
&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"rails"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"~&amp;gt; 7.0.0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the terminal run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Upgrade rails packages
&lt;/h2&gt;

&lt;p&gt;In the &lt;strong&gt;package.json&lt;/strong&gt; file, find all @rails packages and upgrade then one by one. For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn upgrade @rails/actioncable &lt;span class="nt"&gt;--latest&lt;/span&gt;
yarn upgrade @rails/activestorage &lt;span class="nt"&gt;--latest&lt;/span&gt;
yarn upgrade @rails/request.js &lt;span class="nt"&gt;--latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Add sprockets to gemfile
&lt;/h2&gt;

&lt;p&gt;When you are using the asset pipeline, assets related errors can pop up when running a rails command.&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# - Don't know how to build task 'assets:precompile'&lt;/span&gt;
&lt;span class="c"&gt;# - 'method_missing': undefined method `assets'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add sprockets to the gem file as it's now an &lt;a href="https://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#sprockets-is-now-an-optional-dependency"&gt;optional depedency&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;gem&lt;/span&gt; &lt;span class="s2"&gt;"sprockets-rails"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bundle &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Run update rails task
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/rails app:update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will prompt you file by file to integrate the new rails 7 defaults.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;strong&gt;Overwrite .../config/boot.rb? (enter "h" for help) [Ynaqdhm]&lt;/strong&gt;&lt;br&gt;
Note: press &lt;code&gt;h&lt;/code&gt; to see the menu options.&lt;/p&gt;

&lt;p&gt;Go through every file to inspect the difference between the default set-up of rails 7 and your current configuration.&lt;/p&gt;

&lt;p&gt;You can open the files in your editor to compare when selecting merge (m). If you run into the following error:&lt;br&gt;
&lt;code&gt;Please specify merge tool to 'THOR_MERGE' env&lt;/code&gt;&lt;br&gt;
Run the app:update command again with your editor specified.&lt;/p&gt;

&lt;p&gt;For example (vs code)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;THOR_MERGE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;code bin/rails app:update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After completing the set-up run &lt;code&gt;rails db:migrate&lt;/code&gt; to migrate the newly added active storage migration file.&lt;/p&gt;

&lt;p&gt;❗️ If you have set-up other environments, non-default enviroments, like &lt;strong&gt;staging.rb&lt;/strong&gt; make sure to update that file too.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Verify framework defaults
&lt;/h2&gt;

&lt;p&gt;After completing the &lt;code&gt;bin/rails app:update&lt;/code&gt; from the step 4, Rails creates a &lt;strong&gt;new_framework_defaults_7.0.rb&lt;/strong&gt; file in &lt;code&gt;config/initializers&lt;/code&gt;. This file helps you to make a big upgrade a little easier by flipping on the new default settings one-by-one in multiple deployments.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;application.rb&lt;/strong&gt; file's setting &lt;strong&gt;load_defaults&lt;/strong&gt; specifies which rails version's default settings to load. This means you can temporarily utilize the default configuration settings from Rails 6.1 while running Rails 7.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Initialize configuration defaults for originally generated Rails version.&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_defaults&lt;/span&gt; &lt;span class="mf"&gt;6.1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, gradually turn on each setting and verify your application is still working as intended. Once you've switched on every setting, you can remove the &lt;strong&gt;new_framework_defaults_7.0.rb&lt;/strong&gt; and flip the &lt;strong&gt;load_defaults&lt;/strong&gt; version in application.rb to 7.0.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/thomasvanholder/rails-7-framework-defaults-part-1-2a59"&gt;How to turn on Rails 7 framework defaults (part 1)&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Initialize configuration defaults for originally generated Rails version.&lt;/span&gt;
&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_defaults&lt;/span&gt; &lt;span class="mf"&gt;7.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Verify depreciated methods
&lt;/h2&gt;

&lt;p&gt;Your application might use other depreciated features. Read through the &lt;a href="https://edgeguides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-from-rails-6-1-to-rails-7-0"&gt;Rails 6.1 to Rails 7 section&lt;/a&gt; to identify and fix any methods call or settings that are no longer supported.&lt;/p&gt;




</description>
      <category>rails</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to upgrade Tailwind 2 to Tailwind 3</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Tue, 14 Dec 2021 10:51:41 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/how-to-upgrade-tailwind-2-to-tailwind-3-2a3c</link>
      <guid>https://dev.to/thomasvanholder/how-to-upgrade-tailwind-2-to-tailwind-3-2a3c</guid>
      <description>&lt;p&gt;In package.json file, verify your current installed tailwind version. Find tailwind's complete upgrade guide, including all minor changes &lt;a href="https://tailwindcss.com/docs/upgrade-guide#"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This tutorial has as starting point:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tailwind 2.2.16&lt;/li&gt;
&lt;/ul&gt;




&lt;ol&gt;
&lt;li&gt;Upgrade tailwind&lt;/li&gt;
&lt;li&gt;Upgrade typography package&lt;/li&gt;
&lt;li&gt;Upgrade forms package&lt;/li&gt;
&lt;li&gt;Upgrade autoprefixer package&lt;/li&gt;
&lt;li&gt;Upgrade postcss package&lt;/li&gt;
&lt;li&gt;Remove aspect-ratio package&lt;/li&gt;
&lt;li&gt;Replace purge option with content&lt;/li&gt;
&lt;li&gt;Remove dark mode config&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Upgrade tailwind
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn upgrade tailwindcss &lt;span class="nt"&gt;--latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Upgrade typography package
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn upgrade @tailwindcss/typography &lt;span class="nt"&gt;--latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Upgrade forms package
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn upgrade @tailwindcss/forms &lt;span class="nt"&gt;--latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Upgrade autoprefixer package
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn upgrade autoprefixer &lt;span class="nt"&gt;--latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Upgrade postcss package
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn upgrade postcss &lt;span class="nt"&gt;--latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Remove aspect-ratio package
&lt;/h2&gt;

&lt;p&gt;Tailwind 3 comes with &lt;a href="https://www.youtube.com/watch?v=mSC6GwizOag&amp;amp;t=3s"&gt;native aspect-ratio&lt;/a&gt; (7:42). This implies that the package.json can be slimmed down by removing the aspect ratio package if you had it installed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn remove @tailwindcss/aspect-ratio
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the tailwind.config.js file, remove aspect-ratio from the plugins.&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="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@tailwindcss/aspect-ratio&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Search your codebase for the usage of &lt;a href="https://github.com/tailwindlabs/tailwindcss-aspect-ratio#usage"&gt;legacy aspect ratio&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Replace with the &lt;a href="https://tailwindcss.com/docs/aspect-ratio"&gt;new aspect ratio&lt;/a&gt; attributes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  7. Replace purge option with content
&lt;/h2&gt;

&lt;p&gt;If after compiling the CSS, you see the warning message:&lt;br&gt;
&lt;code&gt;The "purge"/"content" options have changed in Tailwind CSS v3.0.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Replace the &lt;code&gt;purge&lt;/code&gt; option in tailwind.config.js with &lt;code&gt;content&lt;/code&gt; as mentioned &lt;a href="https://tailwindcss.com/docs/upgrade-guide#configure-content-sources"&gt;here&lt;/a&gt;.&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="c1"&gt;// old&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;purge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//new&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...]&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  8. Remove dark mode config
&lt;/h2&gt;

&lt;p&gt;In the tailwind.config.js file, remove the dark mode setting if it's value is set to false.&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="c1"&gt;// old&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;darkMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;//new&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tailwindcss</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to migrate Rails UJS to Hotwire (Turbo)</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Sat, 11 Dec 2021 09:10:53 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/how-to-migrate-rails-ujs-to-hotwire-turbo-hdh</link>
      <guid>https://dev.to/thomasvanholder/how-to-migrate-rails-ujs-to-hotwire-turbo-hdh</guid>
      <description>&lt;p&gt;See &lt;a href="https://turbo.hotwired.dev/handbook/drive#performing-visits-with-a-different-method"&gt;Hotwire handbook&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Update hotwired/turbo-rails&lt;/li&gt;
&lt;li&gt;Remove rails/ujs&lt;/li&gt;
&lt;li&gt;Replace link_to delete&lt;/li&gt;
&lt;li&gt;Replace link_to data confirm&lt;/li&gt;
&lt;li&gt;Replace button data disable with&lt;/li&gt;
&lt;li&gt;Set status response in controller&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Update hotwired/turbo-rails
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;package.json&lt;/strong&gt;, update &lt;code&gt;@hotwired/turbo-rails&lt;/code&gt; package to 7.1.0 (or greater)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; "@hotwired/turbo-rails": "^7.1.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Remove rails/ujs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;From the package.json file
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn remove @rails/ujs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;From the application.js entry point
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@rails/ujs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="c1"&gt;// remove this line&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Replace link_to delete
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;method: :delete&lt;/code&gt;&lt;br&gt;
becomes&lt;br&gt;
&lt;code&gt;data: {turbo_method: :delete}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;%# Old %&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s2"&gt;"Destroy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@task&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;method: :delete&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;%# New %&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s2"&gt;"Destroy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@task&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;turbo_method: :delete&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Replace link_to data confirm
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;data: {confirm: 'Are you sure?'}&lt;/code&gt;&lt;br&gt;
becomes&lt;br&gt;
&lt;code&gt;data: {turbo_confirm: 'Are you sure?'}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;%# Old %&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s2"&gt;"Destroy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@task&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;method: :delete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;confirm: &lt;/span&gt;&lt;span class="s1"&gt;'Are you sure?'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;%# New %&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="n"&gt;link_to&lt;/span&gt; &lt;span class="s2"&gt;"Destroy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@task&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;turbo_method: :delete&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;turbo_confirm: &lt;/span&gt;&lt;span class="s1"&gt;'Are you sure?'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Replace button data disable with
&lt;/h2&gt;

&lt;p&gt;In Rails UJS, a form's submit button can be disabled and its text replaced by adding the data disable_with attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;button&lt;/span&gt; &lt;span class="s2"&gt;"Search"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;data: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;disable_with: &lt;/span&gt;&lt;span class="s2"&gt;"Searching..."&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With Turbo, you can set the text content based on the parent's button disabled status. &lt;a href="https://github.com/hotwired/turbo/pull/386"&gt;Source&lt;/a&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;button&lt;/span&gt;             &lt;span class="nc"&gt;.show-when-disabled&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="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;disabled&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;   &lt;span class="nc"&gt;.show-when-disabled&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;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;button&lt;/span&gt;             &lt;span class="nc"&gt;.show-when-enabled&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;initial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;disabled&lt;/span&gt;    &lt;span class="nc"&gt;.show-when-enabled&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="nb"&gt;none&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;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"show-when-enabled"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"show-when-disabled"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submitting...&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you use Tailwind, you can leverage Tailwind's &lt;a href="https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state"&gt;group&lt;/a&gt; and &lt;a href="https://tailwindcss.com/docs/hover-focus-and-other-states#disabled"&gt;disabled&lt;/a&gt; status to create a similar effect.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;button&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s2"&gt;"group"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"group-disabled:hidden"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Search&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;span&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hidden group-disabled:block group-disabled:cursor-wait"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Searching...&lt;span class="nt"&gt;&amp;lt;/span&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Set status response in controller
&lt;/h2&gt;

&lt;p&gt;Respond with a &lt;a href="http://www.railsstatuscodes.com/see_other.html"&gt;303 status code&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TasksController&lt;/span&gt;
 &lt;span class="o"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;destroy&lt;/span&gt;
    &lt;span class="vi"&gt;@task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="vi"&gt;@task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;
    &lt;span class="n"&gt;redirect_to&lt;/span&gt; &lt;span class="n"&gt;tasks_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;info: &lt;/span&gt;&lt;span class="s2"&gt;"Task deleted"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;status: :see_other&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt; 
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rails</category>
      <category>hotwire</category>
      <category>tailwindcss</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Import Class in Relative File into Tailwind CSS and Rails</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Sat, 04 Dec 2021 08:37:30 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/extract-class-in-relative-file-with-rails-and-tailwind-css-50ii</link>
      <guid>https://dev.to/thomasvanholder/extract-class-in-relative-file-with-rails-and-tailwind-css-50ii</guid>
      <description>&lt;p&gt;To import a relative CSS file into Tailwind, the &lt;a href="https://tailwindcss.com/docs/installation#include-tailwind-in-your-css"&gt;postcss-import&lt;/a&gt; is required.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install postcss-import&lt;/li&gt;
&lt;li&gt;Add postcss-config file&lt;/li&gt;
&lt;li&gt;Add postcss to build script&lt;/li&gt;
&lt;li&gt;Create a button class&lt;/li&gt;
&lt;li&gt;Swap tailwind directive for import&lt;/li&gt;
&lt;li&gt;Extract button class into seperate file&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Install postcss-import
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add postcss-import
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Add postcss.config.file
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;postcss&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;postcss-import&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tailwindcss&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;autoprefixer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Add postcss to build:css script
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;package.json&lt;/strong&gt; add &lt;code&gt;--postcss&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;old&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:css"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;new&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build:css"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tailwindcss --postcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. Create a button class
&lt;/h2&gt;

&lt;p&gt;Add a button component in &lt;strong&gt;application.tailwind.css&lt;/strong&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="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.btn-blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;text-white&lt;/span&gt; &lt;span class="err"&gt;bg-blue-500&lt;/span&gt; &lt;span class="err"&gt;rounded-lg&lt;/span&gt; &lt;span class="py"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bg-blue-700&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's see it we get a blue button&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt; &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"button"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"btn-blue"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Save&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Swap tailwind directive for import
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* old */&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@tailwind&lt;/span&gt; &lt;span class="n"&gt;utilities&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c"&gt;/* new */&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/base"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/components"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/utilities"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Extract button class into seperate file
&lt;/h2&gt;

&lt;p&gt;in &lt;strong&gt;application.tailwind.css&lt;/strong&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="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/base"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/components"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"./components/buttons.css"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;@import&lt;/span&gt; &lt;span class="s1"&gt;"tailwindcss/utilities"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in &lt;strong&gt;./components/buttons.css&lt;/strong&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="k"&gt;@layer&lt;/span&gt; &lt;span class="n"&gt;components&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.btn-blue&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="err"&gt;@apply&lt;/span&gt; &lt;span class="err"&gt;text-white&lt;/span&gt; &lt;span class="err"&gt;bg-blue-500&lt;/span&gt; &lt;span class="err"&gt;rounded-lg&lt;/span&gt; &lt;span class="py"&gt;hover&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;bg-blue-700&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few notes from the Tailwind docs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't mix custom css and imports in the same file&lt;/li&gt;
&lt;li&gt;Wrap custom css in @layer components to avoid specificity issues&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>tailwindcss</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>Display content with the 'only' class  in Tailwind CSS</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Fri, 26 Nov 2021 07:15:58 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/display-content-with-the-only-class-in-tailwindcss-4glh</link>
      <guid>https://dev.to/thomasvanholder/display-content-with-the-only-class-in-tailwindcss-4glh</guid>
      <description>&lt;p&gt;With Tailwind's JIT release, developers can act up HTML elements that are in a specific state. The &lt;a href="https://tailwindcss.com/docs/just-in-time-mode#exhaustive-pseudo-class-support"&gt;only&lt;/a&gt; class is practical addition to display a HTML element if it has no sibling HTML elements. Under the tailwind-hood, the only class translates into the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:only-child"&gt;only-child&lt;/a&gt; selector.&lt;/p&gt;




&lt;ul&gt;
&lt;li&gt;empy state&lt;/li&gt;
&lt;li&gt;only:block&lt;/li&gt;
&lt;li&gt;refactored&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Empty state
&lt;/h2&gt;

&lt;p&gt;Imagine you want to display content only if it is stored in the database. The initial step is to create a conditional statement to render parts of the HTML based on the condition you provide. In the rails example below, the conditional check is &lt;code&gt;@tasks.empty?&lt;/code&gt;. If the &lt;code&gt;@tasks&lt;/code&gt; collection is empty, the empty state message is displayed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;empty?&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="vi"&gt;@tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="s2"&gt;"task/task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;task: &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"block"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;All tasks completed.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  only:block
&lt;/h2&gt;

&lt;p&gt;Now, although the code above definitely works, you have added a(nother) conditional to your code.&lt;/p&gt;

&lt;p&gt;An alternative is to handle this natively with CSS.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="vi"&gt;@tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="s2"&gt;"task/task"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;task: &lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hidden only:block"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;All tasks completed.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The empty state's element (p-tag) has a default state of hidden. The added &lt;strong&gt;only&lt;/strong&gt; class change the display status to &lt;strong&gt;block&lt;/strong&gt; when the element has no siblings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refactored
&lt;/h2&gt;

&lt;p&gt;Or leverage the rails &lt;a href="https://guides.rubyonrails.org/layouts_and_rendering.html#rendering-collections"&gt;collection renderer&lt;/a&gt; to re-factor your code into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
  &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="vi"&gt;@tasks&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"hidden only:block"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;All tasks completed.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tailwindcss</category>
      <category>css</category>
      <category>rails</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Click label  to choose radio button Tailwind CSS's peer class</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Sat, 20 Nov 2021 08:08:20 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/click-label-to-choose-radio-button-tailwindcsss-peer-class-39nb</link>
      <guid>https://dev.to/thomasvanholder/click-label-to-choose-radio-button-tailwindcsss-peer-class-39nb</guid>
      <description>&lt;p&gt;With Tailwind's release of its Just-In-Time compiler, the &lt;code&gt;peer&lt;/code&gt; class has been &lt;a href="https://tailwindcss.com/docs/just-in-time-mode#sibling-selector-variants" rel="noopener noreferrer"&gt;introduced&lt;/a&gt;. The peer class is practical when changing an HTML element's behavior based on a previous sibling's state. Radio buttons chosen by label click are such a use-case.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How to choose radio by label click&lt;/li&gt;
&lt;li&gt;Tailwind Peer class&lt;/li&gt;
&lt;li&gt;Single radio button&lt;/li&gt;
&lt;li&gt;Multiple radio buttons&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How to choose radio by label click
&lt;/h2&gt;

&lt;p&gt;A label click will select a radio by matching two attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;radio button: &lt;strong&gt;id&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;label: &lt;strong&gt;for&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tailwind Peer class
&lt;/h2&gt;

&lt;p&gt;You can add peer behavior by adding two classes to the HTML.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add the &lt;code&gt;peer&lt;/code&gt; class to the HTML tag you want to observe the state for.&lt;/li&gt;
&lt;li&gt;Add the &lt;code&gt;peer-checked&lt;/code&gt; class, followed by the desired behavior change, to a sibling element.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Single radio button
&lt;/h2&gt;

&lt;p&gt;Let's start with a single radio button.&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%2Fuhrongkmz8a0tz07j77u.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%2Fuhrongkmz8a0tz07j77u.gif" alt="Single radio"&gt;&lt;/a&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;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sr-only peer"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"answer"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"answer_yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex p-5 bg-white border border-gray-300 rounded-lg cursor-pointer focus:outline-none hover:bg-gray-50 peer-checked:ring-green-500 peer-checked:ring-2 peer-checked:border-transparent"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"answer_yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Yes&lt;span class="nt"&gt;&amp;lt;/label&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;"absolute hidden w-5 h-5 peer-checked:block top-5 right-3"&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Once the input radio with a class &lt;code&gt;peer&lt;/code&gt; is chosen, its sibling label and div will change:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The label gets a green border.
Due to &lt;code&gt;peer-checked:ring-green-500 peer-checked:ring-2 peer-checked:border-transparent&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The icon, initially hidden, appears.
Due to &lt;code&gt;peer-checked:block&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Multiple radio buttons
&lt;/h2&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%2Fe18y2g7eh1y6i2i6tgmg.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%2Fe18y2g7eh1y6i2i6tgmg.gif" alt="Multiple radio buttons"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A single radio button does not make much sense, so let's add in 2 other options and display the radio buttons in a grid.&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;ul&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"grid grid-cols-3 gap-x-5 m-10 max-w-md mx-auto"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"relative"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sr-only peer"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"answer"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"answer_yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex p-5 bg-white border border-gray-300 rounded-lg cursor-pointer focus:outline-none hover:bg-gray-50 peer-checked:ring-green-500 peer-checked:ring-2 peer-checked:border-transparent"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"answer_yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Yes&lt;span class="nt"&gt;&amp;lt;/label&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;"absolute hidden w-5 h-5 peer-checked:block top-5 right-3"&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;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"relative"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sr-only peer"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"no"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"answer"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"answer_no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex p-5 bg-white border border-gray-300 rounded-lg cursor-pointer focus:outline-none hover:bg-gray-50 peer-checked:ring-red-500 peer-checked:ring-2 peer-checked:border-transparent"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"answer_no"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;No&lt;span class="nt"&gt;&amp;lt;/label&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;"absolute hidden w-5 h-5 peer-checked:block top-5 right-3"&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;/li&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"relative"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"sr-only peer"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"radio"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"maybe"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"answer"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"answer_maybe"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"flex p-5 bg-white border border-gray-300 rounded-lg cursor-pointer focus:outline-none hover:bg-gray-50 peer-checked:ring-yellow-500 peer-checked:ring-2 peer-checked:border-transparent"&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"answer_maybe"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Maybe&lt;span class="nt"&gt;&amp;lt;/label&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;"absolute hidden w-5 h-5 peer-checked:block top-5 right-3"&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;/li&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;You can combine multiple peer classes into a single document as long as a parent class (in this case, the &lt;code&gt;&amp;lt;li&amp;gt;&lt;/code&gt;) acts as a separator.&lt;/p&gt;

&lt;p&gt;That's it. &lt;/p&gt;

&lt;p&gt;Purposeful radio buttons without any JS or a custom CSS class.&lt;/p&gt;

</description>
      <category>tailwindcss</category>
      <category>tutorial</category>
      <category>webdev</category>
      <category>css</category>
    </item>
    <item>
      <title>How to Migrate Environment Variables (ENV) to Rails Credentials</title>
      <dc:creator>thomasvanholder</dc:creator>
      <pubDate>Sat, 13 Nov 2021 17:03:06 +0000</pubDate>
      <link>https://dev.to/thomasvanholder/how-to-migrate-environment-variables-env-to-rails-credentials-15ha</link>
      <guid>https://dev.to/thomasvanholder/how-to-migrate-environment-variables-env-to-rails-credentials-15ha</guid>
      <description>&lt;ol&gt;
&lt;li&gt;Why Should You Move From .Env to Credentials?&lt;/li&gt;
&lt;li&gt;How it Works&lt;/li&gt;
&lt;li&gt;Migrate From .Env to Rails Credentials&lt;/li&gt;
&lt;li&gt;How to Use Credentials in Multiple File Formats&lt;/li&gt;
&lt;li&gt;How to Share Keys With a Team&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;small&gt;Initially published on Medium on Jan 26th 2020&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;One key rules them all&lt;/p&gt;

&lt;p&gt;Rails credentials are the new gold standard. ENV files are an insecure ancestor. In this article, you’ll learn why and how to migrate, how to use API keys in Ruby, YML and js.erb, and how to share a single key once with your team.&lt;/p&gt;

&lt;p&gt;DHH &lt;a href="https://twitter.com/dhh/status/983452583368019968?ref_src=twsrc%5Etfw%7Ctwcamp%5Etweetembed%7Ctwterm%5E983452583368019968%7Ctwgr%5E%7Ctwcon%5Es1_&amp;amp;ref_url=https%3A%2F%2Fcdn.embedly.com%2Fwidgets%2Fmedia.html%3Ftype%3Dtext2Fhtmlkey%3Da19fcc184b9711e1b4764040d3dc5c07schema%3Dtwitterurl%3Dhttps3A%2F%2Ftwitter.com%2Fdhh%2Fstatus%2F983452583368019968image%3D"&gt;tweeted&lt;/a&gt; about its arrival nearly three years ago, but new technology often takes time to catch up. A wake-up call is when you find yourself too frequently juggling API keys between developers in your team. It might be time to take a second look at how to implement credentials in a rails app.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Why Should You Move From .Env to Credentials?
&lt;/h2&gt;

&lt;p&gt;The further a project gets in its development cycle, the more services are integrated. Every external service has its API key. It usually doesn’t take too long before developers start hunting teammates for the latest API key. How annoying!&lt;/p&gt;

&lt;p&gt;Or, just imagine when an API key gets refreshed. Every developer individually has to update it into local dotenv files. That seems anti-automation and anti-programmatic — and it is.&lt;/p&gt;

&lt;p&gt;Stop throwing API keys through Slack or email and avoid a security breach of your keys. Luckily, rails credentials offer an easy and welcoming successor. Uploading your keys to Github.&lt;/p&gt;

&lt;p&gt;Uploading to Github!? Yes, uploading to Github! A small annotation is that the API keys are fully encrypted.&lt;/p&gt;

&lt;p&gt;The big win is that there is only a single key to share with your team. It never changes! Any new API keys added by your fellow developers as rails credentials are pulled from Github as you pull the latest main (&lt;a href="https://www.zdnet.com/article/github-to-replace-master-with-main-starting-next-month/"&gt;prev. master&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;You can find the key in the config/master.key folder.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. How it Works
&lt;/h2&gt;

&lt;p&gt;Running &lt;code&gt;bin/rails credentials:edit&lt;/code&gt; in rails creates two files needed in the config folder:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;credentials.yml.enc&lt;/code&gt; stores all your API keys. In case you were wondering, the .enc extension signifies encryption.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;master.key&lt;/code&gt; is the key use to decrypt the encrypted.file (1.) Make sure to check the inclusion of the &lt;code&gt;master.key&lt;/code&gt; in your &lt;code&gt;.gitignore.yml&lt;/code&gt; file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;Credentials.yml.enc&lt;/code&gt; is safe and secure sent along with your repository to Github. The master key, however, is never sent along — guard it like your life depends on it!&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Migrate From .Env to Rails Credentials
&lt;/h2&gt;

&lt;p&gt;Open the credentials file by running the following in your terminal:&lt;br&gt;
&lt;code&gt;EDITOR='code --wait' bin/rails credentials:edit&lt;/code&gt;. Depending on the editor you currently use, replace &lt;code&gt;code&lt;/code&gt; (VS Code). For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;vim or vi= Vim&lt;/li&gt;
&lt;li&gt;atom = Atom&lt;/li&gt;
&lt;li&gt;subl or stt = Sublime&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The credentials file automatically opens in the editor and waits to for you to update and close the file again. Migrate the ENV keys you are using in the .env file to the credentials.yml file.&lt;/p&gt;

&lt;p&gt;Turn your legacy &lt;code&gt;.ENV&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="s"&gt;STRIPE_PUBLISHABLE_KEY=pk_test_VG8LlUN82DcZS3cAOJVy0WyIR9Jwz0YZkq302MKc00t&lt;/span&gt;
&lt;span class="s"&gt;STRIPE_SECRET_KEY=sk_test_VG8LlUN82DcZS3cAOJVy0WyIR9Jwz0YZkq302MKc00tgAAYF&lt;/span&gt;
&lt;span class="s"&gt;STRIPE_WEBHOOK_SECRET_KEY=whsec_cZpB0VG8cZpB0VG8cZpB0VG8UrgA2gcZpB0VG8cZpB&lt;/span&gt;
&lt;span class="s"&gt;CLOUDINARY_URL=cloudinary://15031853100444:XOr3XQ-DcZ4dBoan80@DcZ4Boan800U&lt;/span&gt;
&lt;span class="s"&gt;GOOGLE_API_KEY=S3cAOJVy0WyS3cAOJVy0WyIR9AOJVy0WyIR92e&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Into a &lt;code&gt;credentials.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stripe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;publishable_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pk_test_VG8LlUN82DcZS3cAOJVy0WyIR9Jwz0YZkq302MKc00tgAAYF&lt;/span&gt;
  &lt;span class="na"&gt;secret_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sk_test_VG8LlUN82DcZS3cAOJVy0WyIR9Jwz0YZkq302MKc00tgAAYF&lt;/span&gt;
  &lt;span class="na"&gt;web_hook_secret_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;whsec_cZpB0VG8cZpB0VG8cZpB0VG8UrgA2gcZpB0VG8cZpB&lt;/span&gt;

&lt;span class="na"&gt;google_api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;S3cAOJVy0WyS3cAOJVy0WyIR9AOJVy0WyIR92e&lt;/span&gt;

&lt;span class="na"&gt;cloudinary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;cloud_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;abcdefg&lt;/span&gt;
  &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12345678910&lt;/span&gt;
  &lt;span class="na"&gt;api_secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;abc315-VG8Ll8VG8Ll8L&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;note: Cloudinary API key is split up as per documentation.&lt;/p&gt;

&lt;p&gt;You are now all set. View credentials can run in the terminal.&lt;br&gt;
Run &lt;code&gt;bin/rails credentials:show.&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  4. How to Use Credentials in Multiple File Formats
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Ruby
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# nested key&lt;/span&gt;
&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:publishable_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;# single key&lt;/span&gt;
&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;google_api_key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  YML
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;cloudinary&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Cloudinary&lt;/span&gt;
  &lt;span class="na"&gt;api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= Rails.application.credentials.dig(:cloudinary, :api_key) %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;api_secret&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= Rails.application.credentials.dig(:cloudinary, :api_secret) %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;for Cloudinary an additional &lt;a href="https://gist.github.com/thomasvanholder/6ee92715274ad993f080db15ed3dd177"&gt;config/cloudinary.yml&lt;/a&gt; file is needed&lt;/p&gt;

&lt;h3&gt;
  
  
  JavaScript
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// ruby code only possible with js.erb format&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;abc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;%= Rails.application.credentials.google_api_key %&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ERB
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight erb"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- interpolate in script tag --&amp;gt;&lt;/span&gt; 
&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://maps.googleapis.com/maps/api/js?key=&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;google_api_key&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="err"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="na"&gt;script&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. How to Share Keys With a Team
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Share the key in &lt;code&gt;master.key&lt;/code&gt; with fellow developers to enable decryption.&lt;/li&gt;
&lt;li&gt;Each team member creates a &lt;code&gt;master.key&lt;/code&gt; file locally in the config folder and pastes it in the shared key.&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Coding is more fun without the hassle of chasing the correct API keys. Your app is up-to-date with security best practices. Share a master key once and be free of tedious copy-pasting.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>programming</category>
      <category>credentials</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
