<?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: Adam Rogers</title>
    <description>The latest articles on DEV Community by Adam Rogers (@rodreegez).</description>
    <link>https://dev.to/rodreegez</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%2F304009%2Fb3659e9d-ddd6-48d3-bda3-938ec55719cf.jpg</url>
      <title>DEV Community: Adam Rogers</title>
      <link>https://dev.to/rodreegez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rodreegez"/>
    <language>en</language>
    <item>
      <title>I’m on Team Good Commit Messages</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Sat, 04 Feb 2023 17:10:22 +0000</pubDate>
      <link>https://dev.to/rodreegez/im-on-team-good-commit-messages-57g3</link>
      <guid>https://dev.to/rodreegez/im-on-team-good-commit-messages-57g3</guid>
      <description>&lt;p&gt;There has been &lt;a href="https://twitter.com/ashleyrudland/status/1615011065611358211?s=46&amp;amp;t=jNTGPBtNc0-zxZGl2dUW7Q"&gt;some&lt;/a&gt; &lt;a href="https://podcasts.apple.com/gb/podcast/yagni/id1637538064?i=1000584645049"&gt;debate&lt;/a&gt; on the value of good commit messages, and if we need them at all. &lt;/p&gt;

&lt;p&gt;I’m on team good commit messages for a few reasons. &lt;/p&gt;

&lt;h3&gt;
  
  
  Good commit messages act as a sanity check for my changes
&lt;/h3&gt;

&lt;p&gt;I cannot count the number of times I’ve been writing out a commit message, thought to myself “this is a stupid way to do this”, binned it all off and started again. &lt;/p&gt;

&lt;h3&gt;
  
  
  Good commit messages help me prove to myself that I know what I’m doing
&lt;/h3&gt;

&lt;p&gt;If you understand something, you can explain it simply. If you can’t explain it simply, you don’t understand it. A good commit message is a simple explanation of the change, and I like to try to understand the changes I’m making to the code.&lt;/p&gt;

&lt;h3&gt;
  
  
  Good commit messages are integral to Git
&lt;/h3&gt;

&lt;p&gt;Git is based on commits and commits have messages. Using Git effectively means working with commits, and commit messages the key to working with Git. It isn’t an intuitive tool, but it is a powerful one. Learning to use it efficiently is worth while, and good commit messages make working with Git easier.&lt;/p&gt;

&lt;h3&gt;
  
  
  Good commit messages give context for code
&lt;/h3&gt;

&lt;p&gt;I have a plug-in for my text editor that makes it easy to view the commit associated with a given line of code, and the commit messages of the lines around it. The unfortunately named &lt;code&gt;git blame&lt;/code&gt; command can often give more context than a comment in the code that is more likely to be out of date, or a link to an issue or other URL that is similarly tired or even expired.&lt;/p&gt;

&lt;p&gt;In my experience, the value of good commit messages really becomes apparent when everyone on the team takes the time to write them. This is easiest to achieve if it’s just you, but wonderful to see when the whole team “gets it”.&lt;/p&gt;

&lt;p&gt;This isn’t to say that I &lt;em&gt;always&lt;/em&gt; write good commit messages. I don’t. Sometimes I have no idea what I’m doing, or I’m rushing a hot-fix into production, or a just can’t be bothered. I’m not a martyr. &lt;/p&gt;

&lt;p&gt;But, given the time and space, I’m on Team Good Commit Messages.&lt;/p&gt;

</description>
      <category>git</category>
    </item>
    <item>
      <title>Updating Rails applications with vimdiff</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Wed, 09 Nov 2022 14:30:42 +0000</pubDate>
      <link>https://dev.to/rodreegez/updating-rails-applications-with-vimdiff-3a75</link>
      <guid>https://dev.to/rodreegez/updating-rails-applications-with-vimdiff-3a75</guid>
      <description>&lt;p&gt;This is probably one of those things everyone knows about, but I only just figured it out, so here it is for the next person (likely me, six months from now).&lt;/p&gt;

&lt;p&gt;Ever run &lt;code&gt;bin/rails app:update&lt;/code&gt;, been greeted with this:&lt;/p&gt;

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

   identical  config/boot.rb
       exist  config
    conflict  config/application.rb
Overwrite /home/rodreegez/Projects/my-app/config/application.rb? &lt;span class="o"&gt;(&lt;/span&gt;enter &lt;span class="s2"&gt;"h"&lt;/span&gt; &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;help&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;Ynaqdhm]


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

&lt;/div&gt;

&lt;p&gt;...and wondered what to do?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Y&lt;/code&gt; will overwrite your existing file with the new one. &lt;code&gt;d&lt;/code&gt; will show you the &lt;code&gt;diff&lt;/code&gt; between your existing file and the new one. But what if you want the new stuff but &lt;em&gt;also keep your changes&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;&lt;code&gt;vimdiff&lt;/code&gt; to the rescue.&lt;/p&gt;

&lt;p&gt;The option we're looking for is &lt;code&gt;m&lt;/code&gt; for merge. To use it, we have to set the &lt;code&gt;THOR_MERGE&lt;/code&gt; environment variable and tell it which tool to use to show the diff.&lt;/p&gt;

&lt;p&gt;Let's cancel out of the update process we just started and try again, this time with &lt;code&gt;vimdiff&lt;/code&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;vimdiff bin/rails app:update


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

&lt;/div&gt;

&lt;p&gt;This time, when we press the &lt;code&gt;m&lt;/code&gt; key, &lt;code&gt;vimdiff&lt;/code&gt; will spring into life. It might look something like this:&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%2Fqx4xvxyj3axf471kyevc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx4xvxyj3axf471kyevc.png" alt="vimdiff in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the diff we can see that I have made some changes to &lt;code&gt;application.rb&lt;/code&gt; (on the right - my additions are highlighted in green) and I'd like to keep those.&lt;/p&gt;

&lt;p&gt;The goal of this exercise is to make both of these files the same. We do that by &lt;code&gt;:diffget&lt;/code&gt;ing and &lt;code&gt;:difput&lt;/code&gt;ing changes - &lt;code&gt;diffget&lt;/code&gt; "gets" the corresponding change from the other file, while &lt;code&gt;diffput&lt;/code&gt; "puts" the change from this file to the other one.&lt;/p&gt;

&lt;p&gt;Many changes will be of little consequence - strings being changed from single to double quotes, for example - but some will require a bit of thought.&lt;/p&gt;

&lt;p&gt;Both commands work from the perspective of the window we're currently in. I tend to think it's easier to think about if I &lt;code&gt;ctrl-w&lt;/code&gt; over to "my" version of the file and get and put changes from there.&lt;/p&gt;

&lt;p&gt;Every time we &lt;code&gt;diffget&lt;/code&gt; or &lt;code&gt;diffput&lt;/code&gt; a change, that change will disappear and we're free to cursor down to the next highlighted change. Once there are no more changes left we can &lt;code&gt;:wqa&lt;/code&gt; which will save and quit everything, and our update script will move on to the next file.&lt;/p&gt;

&lt;p&gt;Rinse and repeat with all the files that &lt;code&gt;bin/rails app:update&lt;/code&gt; touches and, by the end of it, you'll have a nice and up-to-date Rails application with all your customisations, personalisations and preferences still intact.&lt;/p&gt;

&lt;p&gt;Don't forget to configure any new &lt;a href="https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#configure-framework-defaults" rel="noopener noreferrer"&gt;framework defaults&lt;/a&gt; and check for any &lt;a href="https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-from-rails-6-1-to-rails-7-0" rel="noopener noreferrer"&gt;further changes you might need to make&lt;/a&gt;. And, of course, make sure your tests still pass.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>vim</category>
    </item>
    <item>
      <title>GeoJSON, PostGIS and the Right-Hand Rule</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Wed, 24 Aug 2022 08:21:00 +0000</pubDate>
      <link>https://dev.to/rodreegez/geojson-right-hand-rule-2idk</link>
      <guid>https://dev.to/rodreegez/geojson-right-hand-rule-2idk</guid>
      <description>&lt;p&gt;GeoJSON expects &lt;code&gt;Polygon&lt;/code&gt; and &lt;code&gt;MultiPolygon&lt;/code&gt; features are required to be "right-hand wound". I understand this to mean that the order of the coordinates that make up the polygon should move in a specific direction.&lt;/p&gt;

&lt;p&gt;Unsurprisingly, exactly &lt;em&gt;which&lt;/em&gt; specific direction is somewhat ambiguous. The &lt;a href="https://www.rfc-editor.org/rfc/rfc7946#appendix-B.1"&gt;GeoJSON spec&lt;/a&gt; says:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Polygon rings MUST follow the right-hand rule for orientation (counterclockwise external rings, clockwise internal rings).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, obviously, a simple 12-point &lt;code&gt;Polygon&lt;/code&gt; in the shape of a circle and following the right-hand rule starts at, say, noon and the next point will be at, say, position 11 on the clock face. &lt;/p&gt;

&lt;p&gt;In my book the primary direction of travel in that case above is, well, left. So "right-hand rule" means "goes left".&lt;/p&gt;

&lt;p&gt;So why are my polygons failing on &lt;a href="https://geojsonlint.com/"&gt;GeoJSONlint.com&lt;/a&gt;? I produce my polygons by exporting them from my Postgres database using PostGIS.&lt;/p&gt;

&lt;p&gt;PostGIS has a function to force polygons to follow the right-hand rule. The documentation for &lt;a href="https://postgis.net/docs/ST_ForceRHR.html"&gt;&lt;code&gt;ST_ForceRHR&lt;/code&gt;&lt;/a&gt; states:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Forces the orientation of the vertices in a polygon to follow a Right-Hand-Rule, in which the area that is bounded by the polygon is to the right of the boundary. In particular, the exterior ring is orientated in a clockwise direction and the interior rings in a counter-clockwise direction.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So "right-hand rule" in PostGIS-land means... exactly the opposite of the same rule in GeoJSON land. And also matches my intuitive interpretation of "right-hand rule" as applied to polygons. &lt;/p&gt;

&lt;p&gt;To create correctly "wound" polygons in GeoJSON when exported from PostGIS, the solution is (obviously) to apply &lt;a href="https://postgis.net/docs/ST_ForcePolygonCCW.html"&gt;ST_ForcePolygonCCW&lt;/a&gt; when exporting polygons as JSON from PostGIS.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;This Stack Overflow comment was key to understanding all of the above: &lt;a href="https://gis.stackexchange.com/questions/306567/postgis-geojson-query-not-validating#comment496061_306571"&gt;https://gis.stackexchange.com/questions/306567/postgis-geojson-query-not-validating#comment496061_306571&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>postgis</category>
      <category>geojson</category>
      <category>gis</category>
    </item>
    <item>
      <title>Connect a local Rails app to an RDS Instance via an SSH tunnel through a bastion server</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Mon, 13 Dec 2021 08:50:33 +0000</pubDate>
      <link>https://dev.to/rodreegez/connect-a-local-rails-app-to-an-rds-instance-via-an-ssh-tunnel-through-a-bastion-server-14f0</link>
      <guid>https://dev.to/rodreegez/connect-a-local-rails-app-to-an-rds-instance-via-an-ssh-tunnel-through-a-bastion-server-14f0</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Editor's note: this is supposed to be a bit tongue-in-cheek. We've all felt like this before!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Right, here's what we're doing; local Rails app connects to a local Postgres instance in the usual way. Fine. But because reasons it also connects to &lt;em&gt;another&lt;/em&gt; database that is massive and a total Pain In The Ass (PITA). &lt;/p&gt;

&lt;p&gt;Because "The Man" cares about security, the only way to access that second RDS instance is through a "bastion" server, which makes this a 10x PITA. Here's probably &lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/rds-connect-using-bastion-host-linux/"&gt;the worst guide in the world&lt;/a&gt; to setting up the sort of configuration we're working with.&lt;/p&gt;

&lt;p&gt;I can't believe I have to do this. I hate computers.&lt;/p&gt;

&lt;p&gt;Fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Connect to the bastion server
&lt;/h2&gt;

&lt;p&gt;The first thing we have to be able to do is to access the bastion server from our local machine. Let's assume you know how to do this. You basically want to run something like &lt;code&gt;ssh user@ip&lt;/code&gt; where &lt;code&gt;user&lt;/code&gt; is the username of the account you'll be accessing the machine as and &lt;code&gt;ip&lt;/code&gt; address is the IP address of the stupid computer getting in the way of you and your multi-database dreams. You'll want to add your ssh keys to the box and stuff. &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AccessingInstancesLinux.html"&gt;Figure it out&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then we have to connect from the freakin' bastion server to the RDS instance living inside it's ivory tower with no bloody internet access. Urgh.&lt;/p&gt;

&lt;p&gt;On the bastion server we should be able to run something like &lt;code&gt;psql -h "&amp;lt;a.very.long.hostname.us-east-1.rds.amazonaws.com&amp;gt;" name_of_database username&lt;/code&gt;. Fill in the blanks, smash that enter key and probably enter a password. You know the password, right? Right. &lt;/p&gt;

&lt;p&gt;Great. We can access the database. This is 10x engineering right here - accessing a sodding database. Welcome to the bleeding edge.&lt;/p&gt;

&lt;p&gt;Now we have our computer talking to the bastion server and the bastion server talking to the RDS. Wonderful. I'm so pleased. Now all we gotta do is get this box on our desk to talk to the RDS instance &lt;em&gt;through&lt;/em&gt; the bastion server. Joy.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tunnel from the bastion server to the RDS instance
&lt;/h2&gt;

&lt;p&gt;This is so annoying.&lt;/p&gt;

&lt;p&gt;What we want is to forward a port on our local machine to a port on the bastion server, which in turn forwards traffic on &lt;em&gt;that&lt;/em&gt; port through to the appropriate port on the RDS server, adding absolutely nothing of value on the way except "security".&lt;/p&gt;

&lt;p&gt;Here's how we do that. &lt;code&gt;ssh&lt;/code&gt; has a &lt;code&gt;-L&lt;/code&gt; flag that does... something. Basically you give it the local port you want the connection for forward, the host you want it forwarded to, and the port on that host that the traffic should end up on. Or something like that. I don't know. I didn't really read the &lt;code&gt;man&lt;/code&gt; page. &lt;/p&gt;

&lt;p&gt;For us, that makes the whole thing look something like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ssh -L 5433:a.very.long.hostname.us-east-1.rds.amazonaws.com:5432 username@bastion-ip-address&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Actually using it
&lt;/h2&gt;

&lt;p&gt;That's a bit of a mouthful to type out every time, so here's what we're going to do; we'll use the &lt;code&gt;~/.ssh/config&lt;/code&gt; file to set configure an ssh connection and specify the tunnel in there so that every time we &lt;code&gt;ssh&lt;/code&gt; into the box the tunnel will be set up and our connection to the remote database will Just Work™ (aye, right).&lt;/p&gt;

&lt;p&gt;Here's what our &lt;code&gt;~/.ssh/config&lt;/code&gt; file is going to look like:&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;# ~/.ssh/config&lt;/span&gt;

Host stupid-computer
  HostName &amp;lt;bastion IP address goes here&amp;gt;
  User &amp;lt;bastion username goes here&amp;gt;
  IdentityFile ~/.ssh/id_rsa
  LocalForward 5433 &amp;lt;a.very.long.hostname.us-east-1.rds.amazonaws.com&amp;gt;:5432
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(The &lt;code&gt;LocalForward&lt;/code&gt; bit isn't exactly the same as when we used the &lt;code&gt;-L&lt;/code&gt; flag. It's &lt;code&gt;LocalForward &amp;lt;local port&amp;gt; &amp;lt;remote database uri&amp;gt;:&amp;lt;remote port&amp;gt;&lt;/code&gt; with a space between the &lt;code&gt;&amp;lt;local port&amp;gt;&lt;/code&gt; and the rest of it.)&lt;/p&gt;

&lt;p&gt;This tells &lt;code&gt;ssh&lt;/code&gt; that when we run &lt;code&gt;ssh -Nf stupid-computer&lt;/code&gt;, it should connect to the bastion server &lt;em&gt;and&lt;/em&gt; forward any traffic on &lt;em&gt;local&lt;/em&gt; port 5433 to &lt;em&gt;remote&lt;/em&gt; port 5432 on the RDS instance.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-N&lt;/code&gt; tells &lt;code&gt;ssh&lt;/code&gt; not to execute any remote commands (just forward ports) and &lt;code&gt;-f&lt;/code&gt; tells ssh to fork into the background. This has the effect of you now not knowing what the h*ck &lt;code&gt;ssh&lt;/code&gt; is doing anymore, but we'll do something about that later. &lt;/p&gt;

&lt;p&gt;For now you can &lt;code&gt;ps aux | grep ssh&lt;/code&gt; to find the process id and then &lt;code&gt;kill &amp;lt;process id&amp;gt;&lt;/code&gt; when you want to stop the tunnel.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Rails
&lt;/h2&gt;

&lt;p&gt;Now we get to hook our Rails app to the database. Again, this is forefront of technology right here. Connecting a CRUD app to a database. Doesn't get any more exciting than 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="c1"&gt;# config/database.yml&lt;/span&gt;

&lt;span class="na"&gt;remmote_db&lt;/span&gt;&lt;span class="pi"&gt;:&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;name_of_the_actual_db&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;db_username&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;db_password&lt;/span&gt;
    &lt;span class="na"&gt;host&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localhost&lt;/span&gt; &lt;span class="c1"&gt;# may need to be 127.0.0.1 if using mysql&lt;/span&gt;
    &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5433&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if you're not an animal and prefer to connect to the database via a URL:&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/database.yml&lt;/span&gt;

&lt;span class="na"&gt;remote_db&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;%= ENV['REMOTE_DB_URL'] %&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and in yr &lt;code&gt;.env&lt;/code&gt; file (or however you go about managing that sort of thing):&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;# .env&lt;/span&gt;

REMOTE_DB_URL: postgres://&amp;lt;db_username&amp;gt;:&amp;lt;uri_encoded_db_password&amp;gt;@localhost:4533/&amp;lt;name_of_the_actual_database&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Hooking it all up
&lt;/h2&gt;

&lt;p&gt;Run &lt;code&gt;ssh stupid-computer&lt;/code&gt; and then boot yr Rails app. Assuming you have an Active Record model that looks a bit like this:&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;Whatever&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;establish_connection&lt;/span&gt; &lt;span class="ss"&gt;:remote_db&lt;/span&gt;
  &lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"whyyy"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should be able to &lt;code&gt;./bin/rails c&lt;/code&gt; and &lt;code&gt;Whatever.count&lt;/code&gt; should return the number of rows in the &lt;code&gt;whyyy&lt;/code&gt; table in the &lt;code&gt;public&lt;/code&gt; schema on &lt;code&gt;remote_db&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And that's about it. You need to have the &lt;code&gt;ssh&lt;/code&gt; connection to the bastion server up and running in order for your model to be able to access that database.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrangling that ssh process
&lt;/h2&gt;

&lt;p&gt;This is all fine and it works but we have to have the ssh process running and we're definitely going to forget to do that and then it'll all break and we'll wonder why and why oh why do we have to do these things?&lt;/p&gt;

&lt;p&gt;The main problem is that output of &lt;code&gt;ssh stupid-computer&lt;/code&gt; doesn't really give us any feedback, so we don't know if that's up and running.&lt;/p&gt;

&lt;p&gt;We can fix that with some more &lt;code&gt;~/.ssh/config&lt;/code&gt; and a couple shell aliases (shamelessly stolen from &lt;a href="https://mpharrigan.com/2016/05/17/background-ssh.html"&gt;this post&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;We're gonna tell ssh to connect and create a control socket (whatever that is) for our connection by passing it the &lt;code&gt;-M&lt;/code&gt; flag and updating our config.&lt;/p&gt;

&lt;p&gt;To make our lives easier, we'll create some aliases in &lt;code&gt;.bashrc&lt;/code&gt; (note the addition of the &lt;code&gt;M&lt;/code&gt; to the command we used above).&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;alias &lt;/span&gt;sc-up&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ssh -NfM stupid-computer"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;sc-status&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ssh -TO check stupid-computer"&lt;/span&gt;
&lt;span class="nb"&gt;alias &lt;/span&gt;sc-down&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"ssh -TO exit stupid-computer"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we'll specify where we want the control socket to live by adding a line to our &lt;code&gt;~/.ssh/config&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# ~/.ssh/config&lt;/span&gt;

Host stupid-computer
  HostName &amp;lt;bastion IP address goes here&amp;gt;
  User &amp;lt;bastion username goes here&amp;gt;
  IdentityFile ~/.ssh/id_rsa
  LocalForward 5433 &amp;lt;a.very.long.hostname.us-east-1.rds.amazonaws.com:5432
  ControlPath ~/.ssh/stupid-computer.ctl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we want to start the ssh tunnel we can simply &lt;code&gt;sc-up&lt;/code&gt;. When it blows up we can run &lt;code&gt;sc-status&lt;/code&gt;, see we didn't start the tunnel yet and run &lt;code&gt;sc-up&lt;/code&gt;, and we can kill it all off when we have given up on life with a simple &lt;code&gt;sc-down&lt;/code&gt;.&lt;/p&gt;

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

&lt;p&gt;Computers are rubbish. "The cloud" is just somebody else's computer, therefore is also rubbish. The struggle is real.&lt;/p&gt;

&lt;p&gt;Now if you'll excuse me I have some actual work to do.&lt;/p&gt;

&lt;h2&gt;
  
  
  References:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://myopswork.com/ssh-tunnel-for-rds-via-bastion-host-6659a48edc"&gt;https://myopswork.com/ssh-tunnel-for-rds-via-bastion-host-6659a48edc&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackoverflow.com/questions/26774264/how-do-i-configure-rails-for-password-less-access-to-remote-database"&gt;https://stackoverflow.com/questions/26774264/how-do-i-configure-rails-for-password-less-access-to-remote-database&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/thebenforce/connect-to-a-postgresql-server-via-ssh-tunnel-832"&gt;https://dev.to/thebenforce/connect-to-a-postgresql-server-via-ssh-tunnel-832&lt;/a&gt;&lt;br&gt;
&lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/rds-connect-using-bastion-host-linux/"&gt;https://aws.amazon.com/premiumsupport/knowledge-center/rds-connect-using-bastion-host-linux/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://codingsight.com/connecting-a-bastion-server-to-a-postgresql-server-via-secure-shell-tunnel/"&gt;https://codingsight.com/connecting-a-bastion-server-to-a-postgresql-server-via-secure-shell-tunnel/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://mpharrigan.com/2016/05/17/background-ssh.html"&gt;https://mpharrigan.com/2016/05/17/background-ssh.html&lt;/a&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>aws</category>
      <category>rails</category>
    </item>
    <item>
      <title>Rails System Tests with Headless Chrome on Heroku CI</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Fri, 04 Jun 2021 15:20:41 +0000</pubDate>
      <link>https://dev.to/rodreegez/rails-system-tests-with-headless-chrome-on-heroku-ci-349d</link>
      <guid>https://dev.to/rodreegez/rails-system-tests-with-headless-chrome-on-heroku-ci-349d</guid>
      <description>&lt;p&gt;Sometimes your Rails apps just need to execute JavaScript in a real browser. But you also want to run tests on CI, which typically doesn't have a UI. So you need to configure Google Chrome to run &lt;em&gt;headless&lt;/em&gt;, i.e. without popping up a browser window (but still exercising your app as if it were).&lt;/p&gt;

&lt;p&gt;Urgh.&lt;/p&gt;

&lt;p&gt;Having just worked through this now, here's what worked for us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Install &lt;a href="https://sites.google.com/chromium.org/driver/"&gt;chromedriver&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure test environment
&lt;/h2&gt;

&lt;p&gt;In your &lt;code&gt;app.json&lt;/code&gt;, add the &lt;code&gt;chromedriver&lt;/code&gt; and &lt;code&gt;google-chrome&lt;/code&gt; buildpacks, as well as the usual &lt;code&gt;ruby&lt;/code&gt; one. Our &lt;code&gt;app.json&lt;/code&gt; ended up looking 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;{
  "environments": {
    "test": {
     "buildpacks": [
        { "url": "https://github.com/heroku/heroku-buildpack-ruby" },
        { "url": "https://github.com/heroku/heroku-buildpack-chromedriver" },
        { "url": "https://github.com/heroku/heroku-buildpack-google-chrome" }
      ],
      "addons": [
        "heroku-postgresql"
      ],
      "scripts": {
        "test-setup": "bin/rails assets:precompile",
        "test": "bin/rspec"
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, set any environment variables you might need in your test env via the Heroku UI. You can set non-sensitive stuff in app.json if you want, though.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure Capybara with a headless driver
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# spec/rails_helper.rb

chrome_bin = ENV.fetch('GOOGLE_CHROME_SHIM', nil)

chrome_opts = chrome_bin ? { "chromeOptions" =&amp;gt; { "binary" =&amp;gt; chrome_bin } } : {}

opts = Selenium::WebDriver::Chrome::Options.new

chrome_args = %w[--headless --no-sandbox --disable-gpu]
chrome_args.each { |arg| opts.add_argument(arg)  }

Capybara.register_driver :headless do |app|
  Capybara::Selenium::Driver.new(
     app,
     browser: :chrome,
     options: opts,
     desired_capabilities: Selenium::WebDriver::Remote::Capabilities.chrome(chrome_opts)
  )
end

Capybara.javascript_driver = :headless
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and that's about it.&lt;/p&gt;

&lt;p&gt;The bit that we found we had to do that was different from other posts of this nature we found was setting &lt;code&gt;Selenium::WebDriver::Chrome::Options.new&lt;/code&gt;. Without this, everything we tried to tell Chrome to be headless was ignored.&lt;/p&gt;

&lt;p&gt;If you're reading this, I hope it helps!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://elements.heroku.com/buildpacks/heroku/heroku-buildpack-google-chrome"&gt;Heroku Buildpack Google Chrome&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;@fdoxyz &lt;a href="https://dev.to/fdoxyz/headless-chrome-dual-mode-tests-for-ruby-on-rails-4p6g"&gt;Headless Chrome - Dual mode tests for Ruby on Rails&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a class="mentioned-user" href="https://dev.to/ideasasylum"&gt;@ideasasylum&lt;/a&gt; &lt;a href="https://jamie.ideasasylum.com/2017/08/19/rails-testing-with-headless-chrome-on-heroku-ci/"&gt;Rails Testing with Headless Chrome on Heroku CI&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>heroku</category>
      <category>ci</category>
    </item>
    <item>
      <title>Password management on the command line</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Sat, 27 Feb 2021 21:52:24 +0000</pubDate>
      <link>https://dev.to/rodreegez/password-management-on-the-command-line-1285</link>
      <guid>https://dev.to/rodreegez/password-management-on-the-command-line-1285</guid>
      <description>&lt;p&gt;&lt;a href="https://www.passwordstore.org/"&gt;&lt;code&gt;pass&lt;/code&gt;&lt;/a&gt; is a command line password manager for Linux that embodies the UNIX philosophy. It's like 1Password, but it lives in your terminal. This comes with some drawbacks, certainly, but is also very powerful.&lt;/p&gt;

&lt;p&gt;Here we'll get &lt;code&gt;pass&lt;/code&gt; installed and then explore a couple reasons why you might like a Command Line Interface (CLI) to your password manager.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;I'm using Ubuntu 18.04 (I know), but these instructions should work for any &lt;code&gt;apt&lt;/code&gt; based distribution, and should be easily adaptable to your *nix of choice.&lt;/p&gt;

&lt;p&gt;First, we'll make sure we have &lt;code&gt;pass&lt;/code&gt; itself, &lt;code&gt;gpg&lt;/code&gt; which comes with Ubuntu by default and will be used to encrypt our passwords, and also xclip, which we'll use to copy passwords to the system clipboard.&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;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;pass gpg xclip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Getting started
&lt;/h2&gt;

&lt;p&gt;Before we can use &lt;code&gt;pass&lt;/code&gt;, we'll need a generate a GPG keypair. To do that, we'll kick off the keypair generation wizard like so:&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;$ &lt;/span&gt;gpg &lt;span class="nt"&gt;--full-generate-key&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Choose the default kind of key (RSA), and default keysize (3072). Set the expiry to &lt;code&gt;0&lt;/code&gt; (doesn't expire). Confirm these options with &lt;code&gt;y&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Next, it will ask you to create a user ID to associate with this key. First you'll be asked your name - I can't help you answer that. Next, you'll be asked for your email address - this is kinda like the "username" for your GPG key. Finally you'll be asked if you'd like to supply a comment - you can skip this by just hitting &lt;code&gt;enter&lt;/code&gt; or give your job title if you're very important. Choose &lt;code&gt;O&lt;/code&gt; to confirm your information.&lt;/p&gt;

&lt;p&gt;Next, you'll be asked to enter a passphrase. This should be 8+ characters long. You'll need to remember it, but it should be &lt;a href="https://xkcd.com/936/"&gt;secure&lt;/a&gt;. Think of something appropriate, enter it, then enter it again to confirm.&lt;/p&gt;

&lt;p&gt;GPG will now generate a random key. Wiggle your mouse around and mash the keyboard to generate entropy while it does this. I have no idea &lt;em&gt;how&lt;/em&gt; it does this or if this is a joke, but this is &lt;strong&gt;security&lt;/strong&gt; we're talking about here, so get mashing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialize &lt;code&gt;pass&lt;/code&gt;:
&lt;/h2&gt;

&lt;p&gt;Now we get to start using &lt;code&gt;pass&lt;/code&gt;. First we create the initial password store, passing it our GPG key ID (which is the email address we used above).&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;$ &lt;/span&gt;pass init the-email-address-you-used-for@your-gpg.key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using pass
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;pass&lt;/code&gt; stores passwords in a hierarchical directory structure. This structure is somewhat arbitrary, but basically follows the structure &lt;code&gt;service-name/username&lt;/code&gt;. If you have multiple accounts on the same service, you might nest those accounts under a parent folder, e.g. &lt;code&gt;aws/development/adam@example.com&lt;/code&gt; and &lt;code&gt;aws/production/adam@example.com&lt;/code&gt; - each of these paths will lead to a different password.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding passwords
&lt;/h3&gt;

&lt;p&gt;Add a new service and set the password (you'll be asked to type the password and then type again to confirm):&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;$ &lt;/span&gt;pass insert test-service/adam@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't know the password already (i.e. you're signing up for a new service), you can generate a random password instead of making one up yourself (where &lt;code&gt;16&lt;/code&gt; is the length you want the password to be):&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;$ &lt;/span&gt;pass generate test-service/adam@example.com 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Viewing passwords
&lt;/h3&gt;

&lt;p&gt;To view the password you just generated, or indeed any password in the vault, simply pass &lt;code&gt;pass&lt;/code&gt; the path to the value you'd like to retrieve (you'll be asked to enter your GPG password from earlier):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pass test-service/adam@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To view that generated password &lt;em&gt;and copy it to the system clipboard&lt;/em&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pass &lt;span class="nt"&gt;-c&lt;/span&gt; test-service/adam@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To list all available accounts (but not their passwords):&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;$ &lt;/span&gt;pass &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Removing passwords
&lt;/h3&gt;

&lt;p&gt;To remove a password (you'll be asked to confirm deletion):&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;$ &lt;/span&gt;pass &lt;span class="nb"&gt;rm &lt;/span&gt;test-service/adam@example.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Remove all passwords in a given directory (you'll be asked to confirm deletion):&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;$ &lt;/span&gt;pass &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; test-service
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...and because &lt;code&gt;pass&lt;/code&gt; follows the UNIX philosophy, you can find instructions for loads more knobs and whistles with &lt;code&gt;man pass&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Really using &lt;code&gt;pass&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;So far, so good. You're a l33t hacker and now use a CLI password manager. Your passwords are stored locally and you can only get to them from your terminal. Congratulations, you just made your life just a little more difficult.&lt;/p&gt;

&lt;p&gt;Or did you?&lt;/p&gt;

&lt;p&gt;Here's the thing. &lt;code&gt;pass&lt;/code&gt; doesn't have to store passwords. It can store any string at the end of those paths. And those paths don't have to map one-to-one with a username and password combination.&lt;/p&gt;

&lt;h3&gt;
  
  
  Use &lt;code&gt;pass&lt;/code&gt; to store secure API keys
&lt;/h3&gt;

&lt;p&gt;One of the most interesting uses of a CLI password manager is that it can integrate with your shell. That means if we can use &lt;code&gt;pass&lt;/code&gt; in our &lt;code&gt;bash&lt;/code&gt; scripts. This gets really useful when we combine that with e.g. loading ENV VARs for our projects.&lt;/p&gt;

&lt;p&gt;Say we had the following passwords set:&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;$ &lt;/span&gt;pass &lt;span class="nb"&gt;ls
&lt;/span&gt;Password Store
└── aws
    ├── secret_key
    └── access_key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We could then set these in a &lt;code&gt;.env&lt;/code&gt; file, and use &lt;code&gt;dotenv&lt;/code&gt; to read those values when booting our application (as described &lt;a href="https://dev.to/rodreegez/bridgetown-and-environment-variables-1123"&gt;elsewhere&lt;/a&gt;):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;AWS_SECRET_KEY: &lt;span class="si"&gt;$(&lt;/span&gt;pass aws/secret_key&lt;span class="si"&gt;)&lt;/span&gt;
AWS_ACCESS_KEY: &lt;span class="si"&gt;$(&lt;/span&gt;pass aws/access_key&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we boot our app, the &lt;code&gt;$()&lt;/code&gt; syntax will get expanded out, pass will be called, and our &lt;code&gt;secret_key&lt;/code&gt; and &lt;code&gt;access_key&lt;/code&gt; will be interpolated in place. Very cool. We can check this file into source control and no one will know what our AWS credentials actually are.&lt;/p&gt;

&lt;p&gt;If we have multiple credentials for the same service, we could separate them out however we like - &lt;code&gt;pass&lt;/code&gt; doesn't care. We could have &lt;code&gt;aws/staging/access_key&lt;/code&gt; and &lt;code&gt;aws/production/access_key&lt;/code&gt; (maybe don't store prod access keys locally though), or &lt;code&gt;aws/staging/client_a/access_key&lt;/code&gt; and &lt;code&gt;aws/staging/client_b/access_key&lt;/code&gt;. Whatever works for you.&lt;/p&gt;

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

&lt;p&gt;We've only just scratched the surface of what one can do when your credentials are managed on the command line. Next up I'd like to figure out how to get credentials shared between machines / teams through &lt;code&gt;git&lt;/code&gt;, ensuring only those with approved GPG keys can access the secrets held within. And you'll be surprised at how flexible having your passwords can be in practice, once you get your head around it. &lt;/p&gt;

&lt;p&gt;I still use a regular password manager for regular passwords, but for credentials like API keys and tokens, &lt;code&gt;pass&lt;/code&gt; is quickly becoming a handy tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wiki.archlinux.org/index.php/Pass"&gt;Pass on ArchWiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://wiki.archlinux.org/index.php/GnuPG"&gt;GnuPG on ArchWiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.passwordstore.org/"&gt;pass website&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blog.gruntwork.io/a-comprehensive-guide-to-managing-secrets-in-your-terraform-code-1d586955ace1"&gt;Managing secrets in Terraform&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>linux</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Rails FormBuilders with TailwindCSS</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Mon, 15 Feb 2021 22:11:03 +0000</pubDate>
      <link>https://dev.to/rodreegez/rails-formbuilders-with-tailwindcss-4a9b</link>
      <guid>https://dev.to/rodreegez/rails-formbuilders-with-tailwindcss-4a9b</guid>
      <description>&lt;p&gt;&lt;a href="https://tailwindcss.com/"&gt;TailwindCSS&lt;/a&gt; is all about adding lots of utility classes to your markup to style elements directly. The problem with that, of course, is that you end up adding lots of utility classes to your markup. Like, a &lt;em&gt;lot&lt;/em&gt; of classes. Dozens, sometimes, by the time you've accounted for the various break points and perhaps dark mode and what have you. &lt;/p&gt;

&lt;p&gt;This can become tiresome, especially in the case of forms, where each element of the form may have all those classes applied and these classes need to be repeated for a dozen of elements in the form. Nobody has got time for that, I'm sure.&lt;/p&gt;

&lt;p&gt;You want all the fields in your form to be consistent with each other, but you also want all the forms on your site to be consistent with each other, too. If you want to change how a &lt;code&gt;text_field&lt;/code&gt; tag looks you want to make that change in one place and see the change reflected everywhere. DRY, and all that.&lt;/p&gt;

&lt;p&gt;Tailwind encourages us to &lt;a href="https://tailwindcss.com/docs/extracting-components"&gt;extract components&lt;/a&gt; in our views as a way to reduce duplication. In Rails we also have the concept of &lt;a href="https://guides.rubyonrails.org/layouts_and_rendering.html#using-partials"&gt;partials&lt;/a&gt; that we can use to share view code between different contexts. If we have a form, we might extract it into a partial and use the same form in the &lt;code&gt;new&lt;/code&gt; and &lt;code&gt;edit&lt;/code&gt; views. &lt;/p&gt;

&lt;p&gt;That's cool, but we still have to duplicate all the utility classes on every element in that form, and we can't share elements between forms for different things. &lt;/p&gt;

&lt;p&gt;Not very DRY.&lt;/p&gt;

&lt;h2&gt;
  
  
  FormBuilders
&lt;/h2&gt;

&lt;p&gt;But Rails has been doing this stuff for years, and obviously there is a super easy and well thought out solution for solving this exact problem: &lt;a href="https://api.rubyonrails.org/v6.1.0/classes/ActionView/Helpers/FormBuilder.html"&gt;FormBuilders&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We can create our own &lt;code&gt;FormBuilder&lt;/code&gt;, supplement the default behaviour with our TailwindCSS utility classes, and then whenever we write &lt;code&gt;f.text_field :whatever&lt;/code&gt; we'll get a nicely styled text field that looks the same as every other text field on our site.&lt;/p&gt;

&lt;p&gt;Here's how to do that (presuming you already have TailwindCSS in your Rails application, which is beyond the scope of this article).&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the Tailwind forms plugin
&lt;/h2&gt;

&lt;p&gt;To get us off to a good start, &lt;a href="https://github.com/tailwindlabs/tailwindcss-forms"&gt;install the Tailwind forms plugin&lt;/a&gt;. This'll give us some nice forms out of the box, and allow us to style things further.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a form builder
&lt;/h2&gt;

&lt;p&gt;I like to create a folder in &lt;code&gt;app&lt;/code&gt; to keep form builders in. Files in subfolders of &lt;code&gt;app&lt;/code&gt; are automatically loaded, and if we decide to add more form builders later then there is a sensible place to put them.&lt;/p&gt;

&lt;p&gt;The basic form builder looks like this:&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;TailwindFormBuilder&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionView&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Helpers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;FormBuilder&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;text_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;
      &lt;span class="n"&gt;default_opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s2"&gt;"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="s1"&gt;'border-2 border-red-500'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@object&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;any?&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="n"&gt;merged_opts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;default_opts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;merged_opts&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 create a new class that inherits from &lt;code&gt;ActionView::Helpers::FormBuilder&lt;/code&gt; and then go ahead and override the &lt;code&gt;text_field&lt;/code&gt; method it provides. In our version, we're going to slam a bunch of Tailwind class names into the options hash we're given by default. This allows us to set different classes on a case by case basis but it's a fairly crude implementation so if we want to override one class we have to supply all the classes we want to see applied to the final element. Finally, we &lt;code&gt;super&lt;/code&gt; the original &lt;code&gt;method&lt;/code&gt; we were passed and our freshly mangled &lt;code&gt;opts&lt;/code&gt; hash up to the original &lt;code&gt;text_field&lt;/code&gt; method we're overriding and let it do its thing.&lt;/p&gt;

&lt;p&gt;A more sophisticated solution is left as an exercise to the reader.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use the FormBuilder
&lt;/h2&gt;

&lt;p&gt;We can then use the form builder very simply by passing it to &lt;code&gt;form_with&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="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"p-12 mx-auto text-gray-800 max-w-7xl"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;form_with&lt;/span&gt; &lt;span class="ss"&gt;model: &lt;/span&gt;&lt;span class="vi"&gt;@widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;builder: &lt;/span&gt;&lt;span class="no"&gt;TailwindFormBuilder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;class: &lt;/span&gt;&lt;span class="s2"&gt;"mt-6"&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;f&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;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;label&lt;/span&gt; &lt;span class="ss"&gt;:reference&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;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;text_field&lt;/span&gt; &lt;span class="ss"&gt;:reference&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;placeholder: &lt;/span&gt;&lt;span class="s2"&gt;"Your reference"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"pt-5"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&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;submit&lt;/span&gt; &lt;span class="s2"&gt;"Begin"&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/div&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;/main&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we render the form and take a look at our text field, we see all our wonderful TailwindCSS classes!&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;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indiogo-300 focus:ring focus:ring-indiogo-200 focus:ring-opacity-50 "&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Your reference"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"widget[reference]"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"widget_reference"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can rinse and repeat this process for any and every Rails form tag we want to apply sensible default TailwindCSS styles to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making TailwindFormBuilder the default
&lt;/h2&gt;

&lt;p&gt;Making our form builder the default is easy, too. In our &lt;code&gt;ApplicatioHelper&lt;/code&gt;, we can set it as the default like this:&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;ActionView&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;default_form_builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;TailwindFormBuilder&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can then remove &lt;code&gt;builder: TailwindFormBuilder&lt;/code&gt; from our call to &lt;code&gt;form_with&lt;/code&gt; in the view, and all forms will use our nicely styled &lt;code&gt;text_field&lt;/code&gt;s by default.&lt;/p&gt;

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

&lt;p&gt;This is obviously a super simple example of what you can do with FormBuilders in Rails and how they can help tuck those CSS utility classes out of the way. We can do some neat things like making the border of the &lt;code&gt;text_area&lt;/code&gt; red if the object has errors. We can even start cracking out &lt;code&gt;content_tag&lt;/code&gt;s to create chunks of HTML that include labels and inline error messages for each element. So far I'm still trying to find the balance between "everything is in the form builder" and "nothing is in the form builder". You'll notice above that the form is still managing a bit of it's own spacing, which may or may not be worth moving into the &lt;code&gt;TailwindFormBuilder&lt;/code&gt;, but I so far I've kept &lt;code&gt;label&lt;/code&gt; seperate from &lt;code&gt;text_field&lt;/code&gt;, for example, and I think I'm happy with that. &lt;/p&gt;

&lt;p&gt;I'm currently experimenting with appending a &lt;code&gt;ul&lt;/code&gt; of error messages to each element in the form as a way of displaying nicely styled inline error messages to the user. This seems to be a bit of a reach, at first, because the markup for the errors don't appear in the form itself. But because they are applied by the form builder, they are applied consistently and to every &lt;code&gt;text_field&lt;/code&gt; that the form is used for. That's just how errors are dealt with in this kind of form. I quite like that (so far).&lt;/p&gt;

&lt;p&gt;FormBuilders are a great way to tuck utility CSS classes away in Rails applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Refernces
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://api.rubyonrails.org/v6.1.0/classes/ActionView/Helpers/FormBuilder.html"&gt;The Rails FormBuilder documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://samuelmullen.com/articles/reduce-form-boilerplate-with-rails-formbuilder/"&gt;Samuel Mullen's excellent write up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tailwindcss-forms.vercel.app/"&gt;Tailwind Forms Examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>tailwindcss</category>
    </item>
    <item>
      <title>Bridgetown and Environment Variables</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Mon, 07 Dec 2020 19:57:11 +0000</pubDate>
      <link>https://dev.to/rodreegez/bridgetown-and-environment-variables-1123</link>
      <guid>https://dev.to/rodreegez/bridgetown-and-environment-variables-1123</guid>
      <description>&lt;p&gt;This afternoon I had a bit of a time getting environment variables working in my first real stab at a &lt;a href="https://www.bridgetownrb.com/"&gt;Bridgetown&lt;/a&gt; site. I'm not sure I've figured out the best way to do this, but here's what I came up with.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;It's worth pointing out a few related background details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I am a curmudgeon and I do not like change, so I switched the templating in my site to &lt;code&gt;erb&lt;/code&gt;, which I believe is a relatively new feature of Bridgetown, but a relatively old feature of Rails.&lt;/li&gt;
&lt;li&gt;I want to be able to set env vars locally, keep them out of my git repo, and set different ones in production in whatever way is apropriate for whatever production is.&lt;/li&gt;
&lt;li&gt;I don't want my application code to care about what environment it's running in.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  dotenv
&lt;/h2&gt;

&lt;p&gt;I usually make Rails applications, and with Rails applications I usually use &lt;a href="https://github.com/bkeepers/dotenv"&gt;dotenv&lt;/a&gt;. This allows me to have a &lt;code&gt;.env&lt;/code&gt; file that gets loaded when my Rails app boots. In Rails-land, we can use &lt;code&gt;dotenv-rails&lt;/code&gt; which will hook into the application boot process and bootstrap our environment variables for us. This mostly works fine, but you can mess with it if you need to. Yay for Rails, I guess.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bridgetown is not Rails
&lt;/h2&gt;

&lt;p&gt;How, then, to hook the loading of env vars into the build process? After a bit of messing about and a nudge from the nice people on the &lt;a href="https://discord.gg/V56yUWR"&gt;Bridgetown discord server&lt;/a&gt; I discovered that one can write "plugins" for Bridgetown. Getting &lt;code&gt;dotenv&lt;/code&gt; to play nice with bridgetown was as simple as &lt;code&gt;bundle add dotenv&lt;/code&gt; and then creating the file &lt;code&gt;/plugins/env.rb&lt;/code&gt; that required the gem:&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;# /plugins/env.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'dotenv/load'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting Env Vars
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;dotenv&lt;/code&gt; being required, any &lt;code&gt;key=value&lt;/code&gt; pairs we put in a file called &lt;code&gt;.env&lt;/code&gt; located at the route of the project will be loaded into the environment when Bridgetown builds.&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;# .env&lt;/span&gt;
&lt;span class="no"&gt;MY_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;ABC123&lt;/span&gt;
&lt;span class="no"&gt;SOME_OTHER_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="no"&gt;DEF246&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You're not limited to &lt;code&gt;.env&lt;/code&gt; files, either. &lt;code&gt;dotenv&lt;/code&gt; allows you to set key-value pairs in a whole bunch of different files, and will load each in &lt;a href="https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use"&gt;an order of precidence&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keeping API keys out of git
&lt;/h2&gt;

&lt;p&gt;Obviously the whole point of this exercise is to keep our precious API keys out of git. To do this, I like to add &lt;code&gt;.env&lt;/code&gt; to my &lt;code&gt;.gitignore&lt;/code&gt;, duplicate the file and rename it to &lt;code&gt;.env.example&lt;/code&gt; and then replace all the keys in &lt;code&gt;.env.example&lt;/code&gt; with nonsense. I do this on basically every project so when I see a &lt;code&gt;.example&lt;/code&gt; file I know I need to copy it to the real file, but you may want to add a reminder to your &lt;code&gt;README&lt;/code&gt; or similar.&lt;/p&gt;

&lt;p&gt;Pro tip: do this &lt;em&gt;before&lt;/em&gt; you commit any of your &lt;code&gt;dotenv&lt;/code&gt; stuff to git, else you'll have to look up how to make git forget about the original &lt;code&gt;.env&lt;/code&gt; file and who's got time for that kind of nonsense?&lt;/p&gt;

&lt;h2&gt;
  
  
  Reading Env Vars
&lt;/h2&gt;

&lt;p&gt;Now that we have Env Vars being set and loaded, we can read them in our views. As mentioned I'm using &lt;code&gt;erb&lt;/code&gt;, so that should look pretty familiar to anyone who's done a little Rails:&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;%# /src/_layouts/home.html.erb %&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="no"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'MY_API_KEY'&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;
  
  
  Why did you do this?
&lt;/h2&gt;

&lt;p&gt;Static sites generally and Bridgetown particularly allow us to build "Jamstack" sites that leverage third-party APIs from the client side, and eschew a server entierly. In order to access an API though, you'll typically need to access an API key. Think Stripe API keys, Google Analytics API keys, Mapbox API keys... anything like that. &lt;/p&gt;

&lt;p&gt;Bridgetown does have a mechanism, two in fact, for loading arbitrary key-value pairs at build time, but neither felt like a particularly suitable place to put API keys. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;config.bridgetown.yml&lt;/code&gt; exists and you could add keys there, however this is the global config for Bridgetown, which means you would find it trickier to do the whole &lt;code&gt;.example&lt;/code&gt; trick to keep your keys out of git, and if you did you'd have to copy your whole config across which seems like it'd be just itching to get out of sync.&lt;/p&gt;

&lt;p&gt;You can also add keys to the &lt;code&gt;site.data&lt;/code&gt; object in Bridgetown by creating e.g. &lt;code&gt;/src/_data/env.yml&lt;/code&gt;. This would make our keys available through e.g. &lt;code&gt;site.data.env.MY_API_KEY&lt;/code&gt;, but that felt like abusing a function meant for something else.&lt;/p&gt;

&lt;p&gt;At the end of the day, I only really need to dump the right value for a given key onto the page interpolated into some JS snippit or other, and Env Vars seem like the right place to do that.&lt;/p&gt;

&lt;p&gt;How do you load API keys into your Bridgetown site?&lt;/p&gt;

</description>
      <category>bridgetownrb</category>
      <category>ruby</category>
      <category>erb</category>
      <category>dotenv</category>
    </item>
    <item>
      <title>Re: Learning to code</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Wed, 01 Apr 2020 19:31:22 +0000</pubDate>
      <link>https://dev.to/rodreegez/re-learning-to-code-4kgn</link>
      <guid>https://dev.to/rodreegez/re-learning-to-code-4kgn</guid>
      <description>&lt;p&gt;&lt;em&gt;My dear brother emailed me asking how he could use all this free time he's got in "lockdown" to build an app he'd had an idea for. I'm sure he won't be the only person thinking along similar lines about now. Here's the response I wrote back:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Yo.&lt;/p&gt;

&lt;p&gt;Programming, eh?&lt;/p&gt;

&lt;p&gt;I am all for encouraging anyone to pick up programming, but I feel like we might need to adjust your expectations a little bit. What you're hoping to make is a pretty complex beast (there are more than a few moving parts) and I'm concerned that you'll be disheartened if you try to bite all that off at once. That &lt;a href="https://personalrecord.club/"&gt;Personal Record Club&lt;/a&gt; app I built took me like a month and I've been doing this shit for 10 years. I should be a lot better at it after 10 years and I'm not, and I'm certainly not suggesting it'll take 10 years before you could attempt to build your idea, but my point still stands - I didn't just knock it out overnight (despite appearances).&lt;/p&gt;

&lt;p&gt;I think the first thing you (or anyone else) should learn to build is a blog. You already understand the domain of blogging (on the homepage there is a list of post titles in reverse chronological order, you click on a title and it takes you to the full article) and you can make it progressively more complex as you do (add a user to author the posts, add many users, show the word count for each post, convert that word count into an estimated reading time, add the ability to upload pictures, add the ability to search an API for recommended pictures, etc. etc. etc.) so you can focus on learning the programming stuff incrementally without having to think about all the edge-cases in the domain as well.&lt;/p&gt;

&lt;p&gt;Of course nobody ever wants to build a blog, they want to build the whizzy app they thought up, so no one ever takes this advice. But it's good advice, David. Start with a blog.&lt;/p&gt;

&lt;p&gt;Demoralised? Great. Get used to it. Programming sucks. &lt;/p&gt;

&lt;p&gt;What stack you build you blog in is up to you. I will be able to help you if you choose Rails, but Rails isn't the new hotness it once was. All the cool kids are learning JavaScript. Obviously all the cool kids are wrong, so choose Rails. Or JavaScript, it's really up to you.&lt;/p&gt;

&lt;p&gt;There are loads of resources to learn how to program. &lt;a href="https://pragprog.com/book/rails6/agile-web-development-with-rails-6"&gt;Agile Web Development with Rails&lt;/a&gt; is the book I used way back when (you build a shopping cart app - they should've taken my advice) but there are loads of online schools for this and that as well. &lt;/p&gt;

&lt;p&gt;Codecademy has been around forever and their &lt;a href="https://www.codecademy.com/learn/paths/web-development"&gt;webdev course&lt;/a&gt; looks like it goes down the JS-heavy route in a pretty sane way. I've seen a lot of people talk about &lt;a href="https://www.theodinproject.com/courses/ruby-on-rails"&gt;The Odin Project&lt;/a&gt; for learning Rails these days. I'm sure you can find similar resources for Python (which is basically Ruby without a few keywords but has some awesome data science libraries so all the machine learning and AI kids love it), or any one of a number of other languages.&lt;/p&gt;

&lt;p&gt;All I would say is pick a language and stick with it. Try and pick something that is a bit framework-agnostic. At the end of the day, Rails is just a bunch of Ruby, so I think that counts, and while you could say the same for any of the JavaScript frameworks, I think you'll get more mileage out of learning JavaScript at least a bit before diving into something like React, Vue or Angular (do people still use Angular?) which all require a bunch of tooling to get going with and you'll spend half your time learning configuration and not-programming stuff. Which you'll no doubt have to do at some point but maybe not right off the bat, eh?&lt;/p&gt;

&lt;p&gt;Hope that helps. I think my main point is that I can help you with Rails but everyone will tell you to do JavaScript. They are probably right, but they should also get off my lawn.&lt;/p&gt;

&lt;p&gt;Spoke to mom the other day. Hope the rash is better.&lt;/p&gt;

&lt;p&gt;Cheers,&lt;/p&gt;

&lt;p&gt;Adam&lt;/p&gt;

</description>
      <category>learning</category>
      <category>isolation</category>
      <category>rails</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Immutable ActiveRecord Models</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Mon, 10 Feb 2020 12:28:54 +0000</pubDate>
      <link>https://dev.to/rodreegez/immutable-activerecord-models-11dp</link>
      <guid>https://dev.to/rodreegez/immutable-activerecord-models-11dp</guid>
      <description>&lt;p&gt;I've just implemented something that I think is pretty neat in &lt;a href="https://deskbeers.com/"&gt;DeskBeers&lt;/a&gt; - an immutable ActiveRecord model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;Why would you want an immutable ActiveRecord model? In our case, the model in question was &lt;code&gt;Subscription&lt;/code&gt;. &lt;code&gt;Subscription&lt;/code&gt;, in the DeskBeers sense, holds on to the products a customer wants, and the frequency with which a customer wants them. A customer can update the products in their &lt;code&gt;Subscription&lt;/code&gt; and the frequency with which they receive them any time, for example this week you might not want your usual order of wine, or you might have a bit of a backlog so might choose to dial deliveries down to being fortnightly for a while. That's totally cool, we got you.&lt;/p&gt;

&lt;p&gt;From the information we hold in a customer's &lt;code&gt;Subscription&lt;/code&gt;, we then create &lt;code&gt;Order&lt;/code&gt; records at the appropriate time. Because a &lt;code&gt;Subscription&lt;/code&gt; can change but an &lt;code&gt;Order&lt;/code&gt; (once processed, at least) shouldn't, we have to take a copy of the products requested by the &lt;code&gt;Subscription&lt;/code&gt; and duplicate that onto the &lt;code&gt;Order&lt;/code&gt;. This way, when we look back at past orders, they retain the information of what was sent to the customer and when, regardless of changes in the parent &lt;code&gt;Subscription&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;By making &lt;code&gt;Subscription&lt;/code&gt; immutable, we get rid of the requirement for the order to know what the customer requested. When the customer makes a change to their &lt;code&gt;Subscription&lt;/code&gt;, we create a &lt;em&gt;new&lt;/em&gt; &lt;code&gt;Subscription&lt;/code&gt; for them, based off the old &lt;code&gt;Subscription&lt;/code&gt;, with the required changes. The &lt;code&gt;Order&lt;/code&gt; records that pertain to the old &lt;code&gt;Subscription&lt;/code&gt; still hang onto the old &lt;code&gt;Subscription&lt;/code&gt;, and new ones take their information from the new &lt;code&gt;Subscription&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This allows us to massively simplify &lt;code&gt;Order&lt;/code&gt; and make it way more flexible - anything can be added to an &lt;code&gt;Order&lt;/code&gt; (anything &lt;code&gt;skuable&lt;/code&gt;, that is) and we can add new &lt;code&gt;LineItems&lt;/code&gt; to &lt;code&gt;Order&lt;/code&gt; way more easily. I'm going off-track a bit here and, not wanting to get into the weeds, let's just say this is a huge win for the flexibility of the DeskBeers platform, honest.&lt;/p&gt;

&lt;p&gt;A nice side effect of this change is that, if a customer so wanted to, they can roll back a change made to &lt;code&gt;Subscription&lt;/code&gt; as we now maintain a history of the model, which is cool. Or they could treat these different versions as templates, e.g. have one with wine and one without, and alternate between these presets as they saw fit. If they wanted to. Which I'm not sure is a requirement anyone has actually asked for. But it's basically a free feature, perhaps it'll come in useful.&lt;/p&gt;

&lt;h1&gt;
  
  
  How?
&lt;/h1&gt;

&lt;p&gt;Largely thanks to &lt;a href="http://strikingly.github.io/blog/2015/09/14/Simple-rails-history-pattern-ActiveRecord/"&gt;this post&lt;/a&gt; on the Strikingly blog, I created a module like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;ActiveRecord&lt;/span&gt;
  &lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Immutable&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;UpdateImmutableException&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Exception&lt;/span&gt;
      &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Immutable model can't be updated"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

    &lt;span class="kp"&gt;extend&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;Concern&lt;/span&gt;

    &lt;span class="n"&gt;included&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;before_update&lt;/span&gt; &lt;span class="ss"&gt;:prevent_update&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;

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

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;prevent_update&lt;/span&gt;
      &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;UpdateImmutableException&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;        
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and included it into &lt;code&gt;Subscription&lt;/code&gt; like this:&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;Subscription&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="kp"&gt;include&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;Immutable&lt;/span&gt;
  &lt;span class="c1"&gt;# ... code from what is definitely a God model omitted&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This caused &lt;em&gt;hundreds&lt;/em&gt; of test failures. Working through them has proved to be super-interesting, and I've learned a lot about our codebase in fixing them. Making &lt;code&gt;Subscription&lt;/code&gt; immutable really highlighted where &lt;code&gt;Subscription&lt;/code&gt; and &lt;code&gt;Order&lt;/code&gt; were tightly coupled, and fixing the tests has lead me to what I believe will be a way more flexible and ultimately easier to understand codebase.&lt;/p&gt;

&lt;p&gt;Do you have any models in your Rails app that could potentially benefit from being immutable?&lt;/p&gt;

</description>
      <category>rails</category>
      <category>activerecord</category>
      <category>immutable</category>
    </item>
    <item>
      <title>Creating and updating users with omniauth</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Fri, 03 Jan 2020 21:57:07 +0000</pubDate>
      <link>https://dev.to/rodreegez/creating-and-updating-users-with-omniauth-4b08</link>
      <guid>https://dev.to/rodreegez/creating-and-updating-users-with-omniauth-4b08</guid>
      <description>&lt;p&gt;There are a number of tutorials, including the &lt;a href="https://github.com/plataformatec/devise/wiki/OmniAuth:-Overview"&gt;omniauth overview&lt;/a&gt;, that suggest having a method along the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_omniauth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;provider: &lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;uid: &lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;first_or_create&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;user&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;friendly_token&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="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;   &lt;span class="c1"&gt;# assuming the user model has a name&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt; &lt;span class="c1"&gt;# assuming the user model has an image&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;first_or_create&lt;/code&gt; will try to find a user by the &lt;code&gt;auth.provider&lt;/code&gt; (e.g. &lt;code&gt;twitter&lt;/code&gt;) and &lt;code&gt;auth.uid&lt;/code&gt; (e.g. &lt;code&gt;rodreegez&lt;/code&gt;) and create one with those attributes if one isn't found. What it &lt;em&gt;doesn't&lt;/em&gt; do is update a found user if the user &lt;em&gt;is&lt;/em&gt; found. &lt;/p&gt;

&lt;p&gt;So, in the example above if, when an existing user signs in with Twitter having updated their name, our app won't get the new name of the user.&lt;/p&gt;

&lt;p&gt;Instead, we should do something like this to ensure we are updating our user information when the user logs in:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_omniauth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;find_or_initialize_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;provider: &lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;uid: &lt;/span&gt;&lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;email&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Devise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;friendly_token&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="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;name&lt;/span&gt;   &lt;span class="c1"&gt;# assuming the user model has a name&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image&lt;/span&gt; &lt;span class="c1"&gt;# assuming the user model has an image&lt;/span&gt;

    &lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
    &lt;span class="n"&gt;user&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;That &lt;code&gt;find_or_initialize_by&lt;/code&gt; behaves more like we expect it in this situation. Or at least, it behaves in a way that is more appropriate to the task we have at hand - it either finds an existing record or initializes a new one, but doesn't try to save the record. We are then able to set the attributes of the found-or-initialized user, save it, and return the saved-or-updated user to the caller.&lt;/p&gt;

&lt;p&gt;Hope that helps.&lt;/p&gt;

&lt;p&gt;🍻&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>omniauth</category>
    </item>
    <item>
      <title>Switching to Zeitwerk</title>
      <dc:creator>Adam Rogers</dc:creator>
      <pubDate>Mon, 30 Dec 2019 08:46:58 +0000</pubDate>
      <link>https://dev.to/rodreegez/switching-to-zeitwerk-366n</link>
      <guid>https://dev.to/rodreegez/switching-to-zeitwerk-366n</guid>
      <description>&lt;p&gt;I’ve just bumped &lt;a href="https://www.deskbeers.com/"&gt;DeskBeers&lt;/a&gt; up to Rails 6.0. One of the new things in this release of Rails is the new way files get autoloaded. &lt;a href="https://github.com/fxn/zeitwerk"&gt;zeitwerk&lt;/a&gt; is very cool, and you should check it out. I won’t go into the pros, cons, whys and wherefores of the change in this post — many folks smarter than I have attested to those — however I do want to bring up a gotcha and solution that bit me while rolling out the change.&lt;/p&gt;

&lt;h2&gt;
  
  
  Zeitwerk loads constants based on paths
&lt;/h2&gt;

&lt;p&gt;Again, without wanting to go too much into how stuff works, you need to know that, basically, Zeitwerk sees the path &lt;code&gt;app/models/user.rb&lt;/code&gt; and from that knows to autoload the constant (class) &lt;code&gt;User&lt;/code&gt;. Which is fine, except when it isn’t.&lt;/p&gt;

&lt;p&gt;For example, DeskBeers charges people VAT, and is old enough to have lived through a change in the applicable VAT rate. So, for better or worse, we now have a model in a file called &lt;code&gt;app/models/vat.rb&lt;/code&gt;. Zeitwerk sees this and tries to autoload the constant &lt;code&gt;Vat&lt;/code&gt;. But because the concept being described is an acronym, the constant (class name) defined in the file isn’t &lt;code&gt;Vat&lt;/code&gt;, it’s &lt;code&gt;VAT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After switching to zeitwerk, we get the error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Zeitwerk::NameError (expected file /.../app/models/vat.rb to define constant Vat, 
but didn't)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That’s the error, but it’s easy enough to fix.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make sure all your acronyms are properly inflected
&lt;/h2&gt;

&lt;p&gt;Rails provides a simple way for you to let it know about acronyms used in your codebase. By adding them to &lt;code&gt;config/initializers/inflections.rb&lt;/code&gt;, Zeitwerk will pick up any acronyms like this and load VAT instead of Vat. DeskBeers (now) defines the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ActiveSupport::Inflector.inflections do |inflect|
  inflect.acronym 'VAT'
  inflect.acronym 'CSV'
  inflect.acronym 'PDF'
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you’ve done this, you’ll need to grep your project for all occurrences of Vat and replace them with VAT. Note: this applies to partial class names, too, e.g. &lt;code&gt;VatCalculator&lt;/code&gt; will need to be updated to &lt;code&gt;VATCalculator&lt;/code&gt; and of course every reference to these classes need to be updated as well — time to break out that &lt;em&gt;find and replace in project&lt;/em&gt; function.&lt;/p&gt;

&lt;p&gt;I think this is a Good Thing, as it’s made us be deliberate about naming things. For instance, in our case, VAT was always inflected, but PDF wasn’t and CSV had clearly been inflected at some point before today but after it was first used, so we had a mix of &lt;code&gt;CSVWhatever&lt;/code&gt; and &lt;code&gt;CsvWhatever&lt;/code&gt; classes. After fixing this issue, all our acronyms are now properly inflected and consistently referenced across our codebase.&lt;/p&gt;

&lt;p&gt;You can also create an initializer for Zeitwerk itself, and for some files that might be appropriate, but in the case where we’re using acronyms, using the Rails inflections initializer, of which Zeitwerk is aware out of the box, forces us to properly name classes so that they can be loaded, without the need for an extra initializer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding problem classes
&lt;/h2&gt;

&lt;p&gt;The best way to make sure Zeitwerk can load all your classes is to have Zeitwerk load all your classes. This won’t happen by default in development mode in Rails, but you can force it by booting up a console and running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Zeitwerk::Loader.eager_load_all
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have any sketchy classes, you’ll get an error like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Zeitwerk::NameError (expected file /.../app/models/csv_whatever.rb to define constant CSVWhatever, 
but didn't)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hope that helps.&lt;/p&gt;

&lt;p&gt;🍻&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>zeitwerk</category>
    </item>
  </channel>
</rss>
