<?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: Mario</title>
    <description>The latest articles on DEV Community by Mario (@lxxxvi).</description>
    <link>https://dev.to/lxxxvi</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%2F189448%2Fec7724b8-11a8-4afa-894d-fe9ed5ae55c2.png</url>
      <title>DEV Community: Mario</title>
      <link>https://dev.to/lxxxvi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lxxxvi"/>
    <language>en</language>
    <item>
      <title>Boolean Validator for Rails</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Sat, 17 Jun 2023 09:57:39 +0000</pubDate>
      <link>https://dev.to/lxxxvi/boolean-validator-for-rails-191l</link>
      <guid>https://dev.to/lxxxvi/boolean-validator-for-rails-191l</guid>
      <description>&lt;p&gt;Rails doesn't come with a built-in boolean validator.&lt;br&gt;
That means  if we have boolean attribute and we set it to &lt;code&gt;nil&lt;/code&gt;, it defaults to &lt;code&gt;false&lt;/code&gt;, which is not necessarily what we want.&lt;/p&gt;

&lt;p&gt;For example a &lt;code&gt;SchrodingersCat&lt;/code&gt; model with a &lt;code&gt;alive&lt;/code&gt; boolean attribute:&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;cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SchrodingersCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;alive: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valid?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To solve that problem we can add a custom validator:&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;# app/validators/boolean_validator.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BooleanValidator&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;EachValidator&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;validate_each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;in?&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="n"&gt;record&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add&lt;/span&gt; &lt;span class="n"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:boolean&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then we can use that validator the same way as the built-in ones:&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;# app/models/schrodingers_cat.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SchrodingersCat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class="n"&gt;validates&lt;/span&gt; &lt;span class="ss"&gt;:alive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;boolean: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error message can be defined for example in &lt;code&gt;activerecord.errors.messages.boolean&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="c1"&gt;# config/locales/en.yml&lt;/span&gt;
&lt;span class="ss"&gt;en:
  activerecord:
    errors:
      messages:
        boolean: &lt;/span&gt;&lt;span class="s2"&gt;"must be boolean"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result:&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;cat&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;SchrodingersCat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;alive: &lt;/span&gt;&lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;valid?&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; false&lt;/span&gt;
&lt;span class="n"&gt;cat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;errors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_a&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; ["Alive must be boolean"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>rails</category>
      <category>ruby</category>
      <category>activerecord</category>
    </item>
    <item>
      <title>GitHub Action using pre-installed Postgres</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Sun, 22 Jan 2023 14:05:25 +0000</pubDate>
      <link>https://dev.to/lxxxvi/github-action-using-pre-installed-postgres-5144</link>
      <guid>https://dev.to/lxxxvi/github-action-using-pre-installed-postgres-5144</guid>
      <description>&lt;p&gt;Until now I used something like this for Postgres in GitHub Actions:&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;the_job_that_needs_postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:latest&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.POSTGRES_PASSWORD }}&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
          &lt;span class="s"&gt;--health-cmd pg_isready&lt;/span&gt;
          &lt;span class="s"&gt;--health-interval 10s&lt;/span&gt;
          &lt;span class="s"&gt;--health-timeout 5s&lt;/span&gt;
          &lt;span class="s"&gt;--health-retries 5&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5432:5432&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;# your steps&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I saw that the &lt;a href="https://github.com/actions/runner-images/" rel="noopener noreferrer"&gt;GitHub's Ubuntu Runner Image&lt;/a&gt; actually comes with a pre-installed Postgres version, but the service is not activated by default.&lt;/p&gt;

&lt;p&gt;So instead of using the &lt;code&gt;postgres:latest&lt;/code&gt; image as a service, we could use that pre-installed Postgres.&lt;/p&gt;

&lt;p&gt;In order to make that work, we have to add one step to the CI job that starts the &lt;code&gt;postgresql.service&lt;/code&gt; and one step that creates a &lt;code&gt;runner&lt;/code&gt; user in the database, so that the workflow's session user can connect to the database.&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;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;the_job_that_needs_postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Start PostgreSQL&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;sudo systemctl start postgresql.service&lt;/span&gt;
          &lt;span class="s"&gt;pg_isready&lt;/span&gt;
          &lt;span class="s"&gt;sudo -u postgres createuser -s -d -r -w runner&lt;/span&gt;

      &lt;span class="c1"&gt;# your steps&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's what the &lt;code&gt;createuser&lt;/code&gt; flags do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-s&lt;/code&gt; : User will be a superuser&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-d&lt;/code&gt; : User can &lt;code&gt;CREATE DATABASE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-r&lt;/code&gt; : User can &lt;code&gt;CREATE ROLE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-w&lt;/code&gt; : It won't prompt for a password.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This approach &lt;strong&gt;takes only a few seconds (3 - 5 seconds) to startup&lt;/strong&gt; whereas the former setup takes between 20 - 30 seconds.&lt;/p&gt;

&lt;p&gt;On the downside &lt;strong&gt;you can't specify the Postgres version&lt;/strong&gt;, you have to live with the version that comes with the runner image.&lt;/p&gt;

&lt;p&gt;At the time of writing &lt;code&gt;ubuntu-22.04&lt;/code&gt; contains Postgres &lt;code&gt;14.6&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Database config for Rails
&lt;/h2&gt;

&lt;p&gt;For Rails projects this is how a minimal &lt;code&gt;database.yml&lt;/code&gt; could look like using the setup above:&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;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;adapter&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgresql&lt;/span&gt;
  &lt;span class="na"&gt;encoding&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unicode&lt;/span&gt;
  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;github_actions_ci_db&lt;/span&gt;
  &lt;span class="na"&gt;pool&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;runner&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Behold:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;username&lt;/code&gt; is set to &lt;code&gt;runner&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hostname&lt;/code&gt; is not required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(It might even &lt;strong&gt;not&lt;/strong&gt; work if you provide the &lt;code&gt;hostname&lt;/code&gt;, like &lt;code&gt;localhost&lt;/code&gt; or &lt;code&gt;127.0.0.1&lt;/code&gt;.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;(Cover photo by &lt;a href="https://unsplash.com/@nathan030997?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Nathan Queloz&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/peXYfMaIDh8?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>programming</category>
      <category>learning</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Auto-reload `config_for` files in Rails</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Fri, 31 Dec 2021 10:34:17 +0000</pubDate>
      <link>https://dev.to/lxxxvi/auto-reload-configfor-files-in-rails-1ljg</link>
      <guid>https://dev.to/lxxxvi/auto-reload-configfor-files-in-rails-1ljg</guid>
      <description>&lt;p&gt;In Rails projects I often use YAML files to organize app-wide values or configurations.&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="c1"&gt;# config/settings.yml&lt;/span&gt;
&lt;span class="na"&gt;shared&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;important_value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;42&lt;/span&gt;

&lt;span class="na"&gt;development&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default_from_email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;development@example.com'&lt;/span&gt;

&lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default_from_email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test@example.com'&lt;/span&gt;

&lt;span class="na"&gt;production&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;default_from_email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;production@example.com'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the application configuration we create a new configuration:&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/application.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;RailsApp&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&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;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:settings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can access these values using  &lt;code&gt;Rails.configuration.settings&lt;/code&gt;, for example:&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;# $ RAILS_ENV=test bin/rails c&lt;/span&gt;
&lt;span class="c1"&gt;# Loading test environment (Rails 7.0.0)&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;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:important_value&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;    &lt;span class="c1"&gt;# =&amp;gt; 42&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;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:default_from_email&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="c1"&gt;# =&amp;gt; "test@example.com"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately the configuration is &lt;strong&gt;not&lt;/strong&gt; reloaded automatically. If we change the &lt;code&gt;important_value&lt;/code&gt; and refresh the page, we'd still see the old value. In order to see the value, we'd need to restart the server first. This can be confusing and tedious, particularly in development.&lt;/p&gt;

&lt;p&gt;Here's a way to reload the configuration every time the file changes.&lt;/p&gt;

&lt;p&gt;Create a new file &lt;code&gt;config/initializers/config_for_reloader.rb&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="c1"&gt;# config/initializers/config_for_reloader.rb&lt;/span&gt;
&lt;span class="k"&gt;if&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;development?&lt;/span&gt;
  &lt;span class="n"&gt;config_for_reloader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FileUpdateChecker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="s2"&gt;"config/settings.yml"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;do&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;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;settings&lt;/span&gt; &lt;span class="o"&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;config_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:settings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="no"&gt;ActiveSupport&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Reloader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_prepare&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;config_for_reloader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute_if_updated&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ActiveSupport::FileUpdateChecker&lt;/code&gt; takes an &lt;strong&gt;Array&lt;/strong&gt; of file paths and a block containing the instructions to be executed on change. (&lt;a href="https://api.rubyonrails.org/classes/ActiveSupport/FileUpdateChecker.html"&gt;Documentation for &lt;code&gt;ActiveSupport::FileUpdateChecker&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In our case the block contains the same instruction as in &lt;code&gt;config/application.rb&lt;/code&gt; for loading the YAML file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ActiveSupport::Reloader.to_prepare&lt;/code&gt; registers a callback that will run once at application startup and every time the code is reloaded. (&lt;a href="https://api.rubyonrails.org/classes/ActiveSupport/Reloader.html#method-c-to_prepare"&gt;Documentation for &lt;code&gt;ActiveSupport::Reloader.to_prepare&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At this point, I would have expected that Rails picks up the changes automatically after the file &lt;code&gt;config/settings.yml&lt;/code&gt; is modififed, but for some reason it does not. It only reloads the file and sets the configuration after an "application file" (a model, template, controller, routes, etc.) is modified.&lt;/p&gt;

&lt;p&gt;We can workaround this by adding &lt;code&gt;config/settings.yml&lt;/code&gt; to the &lt;code&gt;eager_load_paths&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="c1"&gt;# config/application.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;RailsApp&lt;/span&gt;
  &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Application&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&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;settings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:settings&lt;/span&gt;&lt;span class="p"&gt;)&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;eager_load_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;"config/settings.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(If anybody knows why that is necessary, I'd be interested.)&lt;/p&gt;

&lt;p&gt;Now, the configuration file is reloaded after changing it and a page refresh would show the latest value.&lt;/p&gt;

&lt;p&gt;(Cover image by &lt;a href="https://unsplash.com/@kriztheman?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Christopher Alvarenga&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/dark-alley?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>rails</category>
    </item>
    <item>
      <title>Create views to display all data managed by apartment gem</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Wed, 17 Nov 2021 08:39:46 +0000</pubDate>
      <link>https://dev.to/lxxxvi/create-views-to-display-all-data-managed-by-apartment-gem-4jm9</link>
      <guid>https://dev.to/lxxxvi/create-views-to-display-all-data-managed-by-apartment-gem-4jm9</guid>
      <description>&lt;p&gt;One strategy of the &lt;a href="https://github.com/influitive/apartment"&gt;apartment gem&lt;/a&gt; is to store tenant data in dedicated schemas in a Postgres database.&lt;/p&gt;

&lt;p&gt;If we have a model &lt;code&gt;Contract&lt;/code&gt; and tenants &lt;code&gt;company_a&lt;/code&gt; and &lt;code&gt;company_b&lt;/code&gt;, we will find these tables in the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"public"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;-- is supposed to be empty&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"company_a"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"company_b"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"contracts"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(The actual tenant schema names may differ)&lt;/p&gt;

&lt;p&gt;Having the data distributed in multiple schemas makes "cross-tenant-analysis" quite tricky.&lt;br&gt;
To solve this problem we could create views that collects all data from all tenant tables, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;REPLACE&lt;/span&gt; &lt;span class="k"&gt;VIEW&lt;/span&gt; &lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;all_contracts&lt;/span&gt; &lt;span class="k"&gt;AS&lt;/span&gt;
          &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"company_a"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"contracts"&lt;/span&gt;
&lt;span class="k"&gt;UNION&lt;/span&gt; &lt;span class="k"&gt;ALL&lt;/span&gt; &lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="nv"&gt;"company_b"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;"contracts"&lt;/span&gt;
&lt;span class="c1"&gt;-- UNION ALL ...&lt;/span&gt;
&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can query all data using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;all_contracts&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Following Ruby script creates these views automatically:&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;# we want to exclude all "public" models, since these data is not distributed&lt;/span&gt;
&lt;span class="n"&gt;public_table_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Apartment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;excluded_models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;constantize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;/^public\./&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# create and execute an SQL query to collect all tables from all schemas (= tenants)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PgTable&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="n"&gt;tenants_table_names_sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;PgTable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:schemaname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:tablename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;schemaname: &lt;/span&gt;&lt;span class="no"&gt;Apartment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tenant_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;not&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;tablename: &lt;/span&gt;&lt;span class="n"&gt;public_table_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:tablename&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                                 &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_sql&lt;/span&gt;

&lt;span class="n"&gt;all_pg_tables_rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tenants_table_names_sql&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# The next lines builds and executes the "CREATE OR REPLACE VIEW" query, which is described at the beginning of the article&lt;/span&gt;
&lt;span class="n"&gt;all_pg_tables_rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;group_by&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'tablename'&lt;/span&gt;&lt;span class="p"&gt;]&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;table_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;pg_tables_rows&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="n"&gt;selects_sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pg_tables_rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;pg_table_row&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="s2"&gt;"SELECT * FROM &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pg_table_row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'schemaname'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;pg_table_row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'tablename'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="n"&gt;unioned_selects_sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;selects_sql&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="s1"&gt;' UNION ALL '&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="n"&gt;create_view_sql&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"CREATE OR REPLACE VIEW public.all_&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;table_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; AS &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;unioned_selects_sql&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connection&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;create_view_sql&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Disclaimer: Obviously this is a hacky script and &lt;strong&gt;should probably not be used in production&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;If we want to query these views using ActiveRecord we could create corresponding models.&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;AllContract&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActiveRecord&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;AllContract&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# go crazy here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that these are &lt;code&gt;VIEWS&lt;/code&gt; and cannot (?) be used to insert, modify or delete data.&lt;/p&gt;

&lt;p&gt;(Cover image by &lt;a href="https://unsplash.com/@aleks_marinkovic?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Aleks Marinkovic&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/apartments?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>rails</category>
      <category>postgres</category>
      <category>ruby</category>
    </item>
    <item>
      <title>I18n in StimulusReflex</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Wed, 14 Apr 2021 06:45:00 +0000</pubDate>
      <link>https://dev.to/lxxxvi/i18n-in-stimulusreflex-54g2</link>
      <guid>https://dev.to/lxxxvi/i18n-in-stimulusreflex-54g2</guid>
      <description>&lt;p&gt;How do you use I18n in your Reflexes?&lt;/p&gt;

&lt;p&gt;There is an official approach in the &lt;a href="https://docs.stimulusreflex.com/rtfm/patterns#internationalization"&gt;Documentation of StimulusReflex&lt;/a&gt; to do that.&lt;/p&gt;

&lt;p&gt;However, here's another one:&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;# ./app/reflexes/application_reflex.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationReflex&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;StimulusReflex&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Reflex&lt;/span&gt;
  &lt;span class="n"&gt;around_reflex&lt;/span&gt; &lt;span class="ss"&gt;:switch_locale&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;switch_locale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# replace `session[:locale]` with your custom logic&lt;/span&gt;
    &lt;span class="n"&gt;locale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;session&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:locale&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="no"&gt;I18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;default_locale&lt;/span&gt;
    &lt;span class="no"&gt;I18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;with_locale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Yes, it is basically the same thing as Rails suggests for &lt;a href="https://guides.rubyonrails.org/i18n.html#managing-the-locale-across-requests"&gt;Managing the Locale across Requests&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This way I like that all reflexes have the locale set &lt;strong&gt;by default&lt;/strong&gt;, and I do not have to care about it anymore when adding new reflexes.&lt;/p&gt;

&lt;p&gt;What's your experience/opinion regarding I18n in StimulusReflex?&lt;/p&gt;

&lt;p&gt;(Cover image by &lt;a href="https://unsplash.com/@splashabout?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Nareeta Martin on unsplash&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>stimulusreflex</category>
      <category>i18n</category>
    </item>
    <item>
      <title>Maintaining `.rubocop.yml`</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Fri, 11 Sep 2020 13:28:54 +0000</pubDate>
      <link>https://dev.to/lxxxvi/maintaining-rubocop-yml-2obh</link>
      <guid>https://dev.to/lxxxvi/maintaining-rubocop-yml-2obh</guid>
      <description>&lt;p&gt;For a while now, every time I update &lt;code&gt;rubocop&lt;/code&gt; gem to the latest version in my projects and then run &lt;code&gt;bundle exec rubocop&lt;/code&gt; I would get a message that looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;The following cops were added to RuboCop, but are not configured. Please set Enabled to either `true` or `false` in your `.rubocop.yml` file.

Please also note that can also opt-in to new cops by default by adding this to your config:
  AllCops:
    NewCops: enable

Lint/DuplicateRequire: # (new in 0.90)
  Enabled: true
Lint/EmptyFile: # (new in 0.90)
  Enabled: true
Lint/TrailingCommaInAttributeDeclaration: # (new in 0.90)
  Enabled: true
Lint/UselessMethodDefinition: # (new in 0.90)
  Enabled: true
Style/CombinableLoops: # (new in 0.90)
  Enabled: true
Style/KeywordParametersOrder: # (new in 0.90)
  Enabled: true
Style/RedundantSelfAssignment: # (new in 0.90)
  Enabled: true
Style/SoleNestedConditional: # (new in 0.89)
  Enabled: true
Rails/AfterCommitOverride: # (new in 2.8)
  Enabled: true
Rails/SquishedSQLHeredocs: # (new in 2.8)
  Enabled: true
Rails/WhereNot: # (new in 2.8)
  Enabled: true
For more information: https://docs.rubocop.org/rubocop/versioning.html
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am not the &lt;em&gt;"opt-in to new cops by default"&lt;/em&gt;-guy and prefer to add and configure new cops manually.&lt;/p&gt;

&lt;p&gt;I also like to have the cops in alphabetical order.&lt;br&gt;
However, manually putting new cops into order would take me some time and was an annoying task, so I wrote a script that did this work for me.&lt;/p&gt;

&lt;p&gt;Eventually I put the script into a gem named &lt;code&gt;ruboclean&lt;/code&gt; so anyone with the same "fetish" can use it.&lt;/p&gt;

&lt;p&gt;Today, all I do is copy-paste the new cops into &lt;code&gt;.rubocop.yml&lt;/code&gt; and then run &lt;code&gt;ruboclean&lt;/code&gt;... done.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qZDtlFj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d0iluihf25fnc0vft460.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qZDtlFj9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d0iluihf25fnc0vft460.png" alt="Screenshot of the resulting rubocop.yml file after running ruboclean" width="880" height="1136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Satisfying. 🙂&lt;/p&gt;

&lt;p&gt;For more information, please visit &lt;a href="https://github.com/lxxxvi/ruboclean/"&gt;https://github.com/lxxxvi/ruboclean/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;(Cover image by &lt;a href="https://unsplash.com/@nicotitto?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;nrd on unsplash&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>ruby</category>
    </item>
    <item>
      <title>How to use GraphiQL in Rails</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Thu, 13 Aug 2020 07:52:35 +0000</pubDate>
      <link>https://dev.to/lxxxvi/how-to-use-graphiql-in-rails-42kf</link>
      <guid>https://dev.to/lxxxvi/how-to-use-graphiql-in-rails-42kf</guid>
      <description>&lt;p&gt;I recently wanted to use &lt;code&gt;graphiql-rails&lt;/code&gt; gem to play around with a GraphQL endpoint that I was running in a Rails project.&lt;/p&gt;

&lt;p&gt;For some reasons, I was not able to set it up properly since the gem doesn't seem to be working without Rails Asset Pipeline... or may be I was just too lazy to look it up how to make it work.&lt;/p&gt;

&lt;p&gt;So I came up with a workaround:&lt;/p&gt;




&lt;p&gt;If exists, remove &lt;code&gt;graphiql-rails&lt;/code&gt; from &lt;code&gt;Gemfile&lt;/code&gt;, then run &lt;code&gt;bundle&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If exist, remove these lines from &lt;code&gt;./config/routes.rb&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;if&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;development?&lt;/span&gt;
  &lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="no"&gt;GraphiQL&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;at: &lt;/span&gt;&lt;span class="s2"&gt;"/graphiql"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;graphql_path: &lt;/span&gt;&lt;span class="s2"&gt;"/your/endpoint"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These things may have been auto-generated if you followed the installation instructions from the &lt;code&gt;graphql&lt;/code&gt; gem.&lt;/p&gt;




&lt;p&gt;Add to &lt;code&gt;./config/routes.rb&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;get&lt;/span&gt; &lt;span class="s1"&gt;'/graphiql'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;to: &lt;/span&gt;&lt;span class="s1"&gt;'graphiql#index'&lt;/span&gt; &lt;span class="k"&gt;if&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;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;development?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This adds a new route &lt;code&gt;/graphiql&lt;/code&gt; and maps it to the &lt;code&gt;index&lt;/code&gt; action of controller &lt;code&gt;GraphiqlController&lt;/code&gt;, which we are going to define next...&lt;/p&gt;




&lt;p&gt;Create &lt;code&gt;./app/controllers/graphiql_controller.rb&lt;/code&gt; with this content:&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;GraphiqlController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
  &lt;span class="n"&gt;layout&lt;/span&gt; &lt;span class="kp"&gt;false&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;index&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can leave the &lt;code&gt;index&lt;/code&gt; method empty, and continue with the view...&lt;/p&gt;




&lt;p&gt;Create &lt;code&gt;./app/views/graphiql/index.html.erb&lt;/code&gt; with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Simple GraphiQL&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/graphiql/graphiql.min.css"&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;csrf_meta_tags&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"margin: 0;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"graphiql"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"height: 100vh;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;crossorigin&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/react/umd/react.production.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;crossorigin&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/react-dom/umd/react-dom.production.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;crossorigin&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://unpkg.com/graphiql/graphiql.min.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;graphqlEndpointUrl&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;%= graphql_url %&amp;gt;&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;graphQLFetcher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graphQLParams&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graphqlEndpointUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;post&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;headers&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;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;X-CSRF-Token&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`meta[name="csrf-token"]`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;graphQLParams&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
      &lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GraphiQL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;fetcher&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;graphQLFetcher&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;graphiql&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="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That content originally comes from the official &lt;a href="https://github.com/graphql/graphiql/tree/main/packages/graphiql#cdn-bundle"&gt;GraphiQL README Page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It loads the GraphiQL source from a CDN, so you need to be connected to the internet in order to use it.&lt;/p&gt;

&lt;p&gt;However, the file has been enriched in 3 locations in order to work with Rails:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;%= csrf_meta_tags %&amp;gt;&lt;/code&gt; : This writes the CSRF token as a &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt;-tag, which we are going to use in the AJAX request below.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;const graphqlEndpointUrl = "&amp;lt;%= graphql_url %&amp;gt;";&lt;/code&gt; : If your Rails application runs the GraphQL endpoint, its URL will automatically be defined here.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'X-CSRF-Token': document.querySelector(`meta[name="csrf-token"]`).content&lt;/code&gt; : This reads the CSRF token from the &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt;-tag and sends it together with the GraphQL query to the Rails server. If this is missing, Rails will refuse the request with the error &lt;code&gt;ActionController::InvalidAuthenticityToken&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;Finally, start the rails server &lt;code&gt;bin/rails s&lt;/code&gt; and go to &lt;code&gt;http://localhost:3000/graphiql&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n_w5IAqi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ujyswbupw2r4d9x65o7z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n_w5IAqi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ujyswbupw2r4d9x65o7z.png" alt="Alt Text" width="880" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>rails</category>
      <category>graphql</category>
      <category>graphiql</category>
    </item>
    <item>
      <title>TIL Tuples vs Arrays in Crystal</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Thu, 06 Aug 2020 08:26:25 +0000</pubDate>
      <link>https://dev.to/lxxxvi/til-tuples-vs-arrays-in-crystal-3693</link>
      <guid>https://dev.to/lxxxvi/til-tuples-vs-arrays-in-crystal-3693</guid>
      <description>&lt;p&gt;Today I played around with Crystal... the programming language (🥁 &lt;em&gt;ba-dum-tss&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Coming from Ruby, Crystal isn't a mystery in many cases, but in the end, I don't know much about it at all.&lt;/p&gt;

&lt;p&gt;However, I learned something about Tuples and Arrays today.&lt;/p&gt;




&lt;p&gt;It starts simple with a class that takes a &lt;code&gt;String&lt;/code&gt; as an argument.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TupleVsArray&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@text&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Text: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@text&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Now let's decomposit an array into two variables, and then pass the first variable, &lt;code&gt;foo&lt;/code&gt;, into the class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"bar"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;TupleVsArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# Text: foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This works fine.&lt;br&gt;
All elements in the array are of type &lt;code&gt;String&lt;/code&gt;.&lt;br&gt;
It compiles, it runs!&lt;/p&gt;



&lt;p&gt;Let's change the second element in the array into a &lt;code&gt;Symbol&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="no"&gt;TupleVsArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This fails during compiling with this error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: no overload matches 'TupleVsArray.new' with type (String | Symbol)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To me, having little to 0 experience with type checking, this is fascinating... and confusing, because &lt;code&gt;foo&lt;/code&gt; is allegedly &lt;em&gt;never&lt;/em&gt; going to be a &lt;code&gt;Symbol&lt;/code&gt;. Allegedly...&lt;/p&gt;

&lt;p&gt;Then I realized that the array &lt;em&gt;could&lt;/em&gt; be changed in the meantime, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="ss"&gt;:foo&lt;/span&gt;
&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;
&lt;span class="no"&gt;TupleVsArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Error: no overload matches 'TupleVsArray.new' with type (String | Symbol)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This time, the error makes absolutely sense.&lt;/p&gt;




&lt;p&gt;Then I also learned, that in Crystal we cannot change an array's element to an &lt;em&gt;not-yet-existing type&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;
&lt;span class="no"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;no&lt;/span&gt; &lt;span class="n"&gt;overload&lt;/span&gt; &lt;span class="n"&gt;matches&lt;/span&gt; &lt;span class="s1"&gt;'='&lt;/span&gt; &lt;span class="n"&gt;with&lt;/span&gt; &lt;span class="n"&gt;types&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;Int32&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want to change any element in &lt;code&gt;row&lt;/code&gt;, we must only use &lt;code&gt;String&lt;/code&gt; or &lt;code&gt;Symbol&lt;/code&gt;.&lt;/p&gt;




&lt;p&gt;So, in order to resolve the original problem, we need to use a &lt;a href="https://crystal-lang.org/api/Tuple.html"&gt;Tuple&lt;/a&gt;, which is a&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[...] fixed-size, immutable, stack-allocated sequence of values of &lt;strong&gt;possibly different types&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight crystal"&gt;&lt;code&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bar&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;"foo"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:bar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="no"&gt;TupleVsArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;     &lt;span class="c1"&gt;# Text: foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alright, got it. 😊&lt;/p&gt;

&lt;p&gt;(Photo by &lt;a href="https://unsplash.com/@cristofer?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Cristofer Jeschke&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/forest-fog?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>crystal</category>
      <category>todayilearned</category>
      <category>beginners</category>
    </item>
    <item>
      <title>TIL Using Postgres in GitHub Actions</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Fri, 24 Jul 2020 14:10:33 +0000</pubDate>
      <link>https://dev.to/lxxxvi/til-using-postgres-in-github-actions-3j</link>
      <guid>https://dev.to/lxxxvi/til-using-postgres-in-github-actions-3j</guid>
      <description>&lt;p&gt;I recently made my first experiences with GitHub Actions.&lt;/p&gt;

&lt;p&gt;Setting up Postgres took me several attempts because of a misunderstanding with variables in the service's &lt;code&gt;env&lt;/code&gt; block.&lt;/p&gt;

&lt;p&gt;I thought that I could just define &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt; in the global &lt;code&gt;env&lt;/code&gt; block and this would then be available and used in Postgres' service. However, not having set &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt; in &lt;code&gt;services.postgres.env&lt;/code&gt; gave me this nice, quite unhelpful error message:&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;##[error]Failed to initialize, postgres service is unhealthy.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a while I learned that the environment variable &lt;code&gt;POSTGRES_PASSWORD&lt;/code&gt; in &lt;code&gt;services.postgres.env&lt;/code&gt; is &lt;strong&gt;mandatory&lt;/strong&gt; and &lt;strong&gt;must not be blank&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Also, the variables defined in &lt;code&gt;services.postgres.env&lt;/code&gt; are &lt;strong&gt;passed into the docker image&lt;/strong&gt;, thus they are &lt;em&gt;somewhat different&lt;/em&gt; compared to regular &lt;code&gt;env&lt;/code&gt; blocks in Github Action Workflow syntax... I guess?&lt;/p&gt;

&lt;p&gt;However, my final result looks like this.&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;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="c1"&gt;# ...&lt;/span&gt;
  &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mysecretpassword&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;a-job-that-uses-postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
    &lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;postgres&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:latest&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ env.POSTGRES_PASSWORD }}&lt;/span&gt;
        &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;&amp;gt;-&lt;/span&gt;
          &lt;span class="s"&gt;--health-cmd pg_isready&lt;/span&gt;
          &lt;span class="s"&gt;--health-interval 10s&lt;/span&gt;
          &lt;span class="s"&gt;--health-timeout 5s&lt;/span&gt;
          &lt;span class="s"&gt;--health-retries 5&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;5432:5432&lt;/span&gt;
    &lt;span class="c1"&gt;# ...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is being translated into this command, which makes  it clear what happens with the variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker create&lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="c"&gt;# many others\&lt;/span&gt;
  &lt;span class="nt"&gt;-p&lt;/span&gt; 5432:5432&lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--health-cmd&lt;/span&gt; pg_isready&lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--health-interval&lt;/span&gt; 10s&lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--health-timeout&lt;/span&gt; 5s&lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--health-retries&lt;/span&gt; 5&lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"POSTGRES_PASSWORD=mysecretpassword"&lt;/span&gt;&lt;span class="se"&gt;\ &lt;/span&gt;   &lt;span class="c"&gt;# &amp;lt;= 💡&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;GITHUB_ACTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;CI&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
  postgres:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My learning may be trivial, but I hope that this helps someone having the same issue.&lt;/p&gt;

&lt;p&gt;(Photo by &lt;a href="https://unsplash.com/@andrewricegolf?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Andrew Rice&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>githubactions</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Middleman + TailwindCSS + Webpack</title>
      <dc:creator>Mario</dc:creator>
      <pubDate>Tue, 02 Jul 2019 16:27:26 +0000</pubDate>
      <link>https://dev.to/lxxxvi/middleman-tailwindcss-webpack-ap3</link>
      <guid>https://dev.to/lxxxvi/middleman-tailwindcss-webpack-ap3</guid>
      <description>&lt;p&gt;I really enjoy using &lt;a href="https://middlemanapp.com/" rel="noopener noreferrer"&gt;Middleman&lt;/a&gt; for some websites that I maintain. For one of my projects I wanted to include &lt;a href="https://tailwindcss.com/" rel="noopener noreferrer"&gt;TailwindCSS&lt;/a&gt; and started googling how to do that. I found &lt;a href="https://vcavallo.github.io/css/static_site_generator/how_to/2017/12/06/setting-up-middleman-with-tailwind-css.html" rel="noopener noreferrer"&gt;this guide&lt;/a&gt; but it seemed bit outdated.&lt;/p&gt;

&lt;p&gt;This got me inspired to write an updated version.&lt;/p&gt;

&lt;p&gt;So, in this guide I'm trying to describe how I managed setting up a middleman project and integrate TailwindCSS using Webpack.&lt;/p&gt;

&lt;p&gt;It uses these versions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Middleman &lt;code&gt;4.3.4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Tailwind &lt;code&gt;1.0.4&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Webpack &lt;code&gt;4.35.2&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: &lt;em&gt;I am not an expert with Webpack etc&lt;/em&gt;. So the following instructions may be inaccurate, incomplete or misleading. I hope it's not too bad though, please comment if you feel something is terribly wrong.&lt;/p&gt;

&lt;p&gt;Here we go...&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup a Middleman project
&lt;/h2&gt;

&lt;p&gt;Firstly, install Middleman and create a project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gem &lt;span class="nb"&gt;install &lt;/span&gt;middleman
middleman init project
&lt;span class="nb"&gt;cd&lt;/span&gt; ./project
middleman serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once &lt;code&gt;middleman serve&lt;/code&gt; is running you should see a default page on &lt;code&gt;http://localhost:4567&lt;/code&gt;. You may abort the process again since we're going to change some configurations now...&lt;/p&gt;

&lt;p&gt;Also, from now on this guide assumes that the working directory is the project's root directory.&lt;/p&gt;

&lt;p&gt;(These instructions were taken from the &lt;a href="https://middlemanapp.com/basics/install/" rel="noopener noreferrer"&gt;Middleman installation page&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;
  
  
  Add Livereload (Optional)
&lt;/h3&gt;

&lt;p&gt;Livereload automatically reloads the page in the browser every time we change something in the code, which can be useful later.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Add &lt;code&gt;gem 'middleman-livereload'&lt;/code&gt; to &lt;code&gt;./Gemfile&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;activate :livereload&lt;/code&gt; to &lt;code&gt;./config.rb&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Run &lt;code&gt;bundle install&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(These instructions were taken from the &lt;a href="https://middlemanapp.com/basics/development-cycle/#livereload" rel="noopener noreferrer"&gt;Middleman Basics page&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Add npm packages
&lt;/h2&gt;

&lt;p&gt;Now we get to the first part where I don't have much knowledge about. After some experimenting I concluded this list of packages&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn init
yarn add autoprefixer css-loader mini-css-extract-plugin postcss postcss-import postcss-loader style-loader tailwindcss webpack webpack-cli
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(You may substitute &lt;code&gt;yarn&lt;/code&gt; with &lt;code&gt;npm&lt;/code&gt;. Use &lt;code&gt;npm install&lt;/code&gt; instead of &lt;code&gt;yarn add&lt;/code&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Prepare CSS file
&lt;/h2&gt;

&lt;p&gt;Middleman comes with SCSS, but I decided to not use SCSS together with Tailwind. That's why I renamed the stylesheet's filename:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;mv&lt;/span&gt; ./source/stylesheets/site.css.scss ./source/stylesheets/site.css
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then I changed the content of &lt;code&gt;./source/stylesheets/site.css&lt;/code&gt; to this:&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;"tailwindcss/utilities"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nt"&gt;body&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;bg-red-500;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This imports the Tailwind definitions and applies a rule to the &lt;code&gt;body&lt;/code&gt; tag using Tailwind's &lt;code&gt;@apply&lt;/code&gt; directive. At the end of this guide we expect the background color of the page to be red(-ish).&lt;/p&gt;

&lt;p&gt;(This instruction was taken from the &lt;a href="https://tailwindcss.com/docs/installation#2-add-tailwind-to-your-css" rel="noopener noreferrer"&gt;Tailwind's installation page&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Create &lt;code&gt;postcss.config.js&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Next we're going to create a file &lt;code&gt;./postcss.config.js&lt;/code&gt; with this content:&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;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="nf"&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="nf"&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="nf"&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;p&gt;(This instruction was taken from the &lt;a href="https://tailwindcss.com/docs/installation#using-tailwind-with-postcss" rel="noopener noreferrer"&gt;Tailwind's installation page&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure webpack
&lt;/h2&gt;

&lt;p&gt;To me, configuring webpack was the most difficult part. There are a lot of examples for this on the interwebs and as a JS-noob I couldn't make clear which way is the best. But here's what I came up with.&lt;/p&gt;

&lt;p&gt;Create a file &lt;code&gt;./webpack.config.js&lt;/code&gt; with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MiniCssExtractPlugin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&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;mini-css-extract-plugin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;MiniCssExtractPlugin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./source/javascripts/site.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./source/stylesheets/site.css&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;output&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;__dirname&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/.tmp/dist&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;[name].js&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;module&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;rules&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;test&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="sr"&gt;css$/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/node_modules/&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;use&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;loader&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MiniCssExtractPlugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;hmr&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;development&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;css-loader&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;postcss-loader&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;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While I created this file I made several observations that I'd like to share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The keys in &lt;code&gt;entry: { ... }&lt;/code&gt; (&lt;code&gt;application&lt;/code&gt; and &lt;code&gt;styles&lt;/code&gt;) will be used as filenames. So there will be a file named &lt;code&gt;application.js&lt;/code&gt; and one named &lt;code&gt;styles.js&lt;/code&gt; (yes... the styles file's extension is going to be &lt;code&gt;.js&lt;/code&gt;, I guess it won't be used though, may be I can get rid of it somehow?)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;output.path&lt;/code&gt; apparently has to be &lt;code&gt;/.tmp/dist&lt;/code&gt; (!), otherwise Middleman won't use it in development?&lt;/li&gt;
&lt;li&gt;Lastly, the rule for &lt;code&gt;.css&lt;/code&gt; files is more or less copy/pasted from &lt;code&gt;MiniCssExtractPlugin&lt;/code&gt; &lt;a href="https://github.com/webpack-contrib/mini-css-extract-plugin#minimal-example" rel="noopener noreferrer"&gt;project page&lt;/a&gt;. I assume this plugin is responsible for processing/creating a &lt;code&gt;styles.css&lt;/code&gt; file in the output path? Note that this plugin replaces a plugin named &lt;code&gt;extract-text-webpack-plugin&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You see, in this area I have multiple question marks. So if you have corrections, I invite you to post them in the comments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Activate Webpack as &lt;code&gt;:external_pipeline&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Now let's hook up webpack to the Middleman pipeline.&lt;/p&gt;

&lt;p&gt;Add these lines to &lt;code&gt;./config.rb&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;activate&lt;/span&gt; &lt;span class="ss"&gt;:external_pipeline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;name: :webpack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;command: &lt;/span&gt;&lt;span class="n"&gt;build?&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s1"&gt;'./node_modules/webpack/bin/webpack.js --bail'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'./node_modules/webpack/bin/webpack.js --watch -d --color'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;source: &lt;/span&gt;&lt;span class="s2"&gt;".tmp/dist"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="ss"&gt;latency: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures that webpack runs as soon as anything changes in the project during development or when we build the project.&lt;/p&gt;

&lt;p&gt;(This instruction was taken from the &lt;a href="https://middlemanapp.com/advanced/external-pipeline/#webpack-example" rel="noopener noreferrer"&gt;Middleman Documentation&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;
  
  
  Change stylesheet and javascript paths in &lt;code&gt;./source/layouts/layout.erb&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Remember that we configured webpack so we get a file named &lt;code&gt;application.js&lt;/code&gt; and one named &lt;code&gt;styles.css&lt;/code&gt; as outputs? We need to change these filenames in the &lt;code&gt;head&lt;/code&gt; section of the page.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;./source/layouts/layout.rb&lt;/code&gt; change&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;"site"&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;javascript_include_tag&lt;/span&gt; &lt;span class="s2"&gt;"site"&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;to&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;"styles"&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;javascript_include_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;h2&gt;
  
  
  Moment of truth...
&lt;/h2&gt;

&lt;p&gt;Run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;middleman serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check whether the background of the page at &lt;code&gt;http://localhost:4567&lt;/code&gt; is red(-ish). If so, this guide is trustworthy and you can happily start using Tailwind in your project. If not, put the blame on me and share your experience.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fo5age2s4t98nm5ljic6c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fo5age2s4t98nm5ljic6c.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.flickr.com/photos/30478819@N08/46074804494" rel="noopener noreferrer"&gt;Cover image&lt;/a&gt; by Marco Verch&lt;/p&gt;

</description>
      <category>middlemanapp</category>
      <category>tailwindcss</category>
      <category>webpack</category>
      <category>css</category>
    </item>
  </channel>
</rss>
