<?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: Edwin Mak</title>
    <description>The latest articles on DEV Community by Edwin Mak (@edwinthinks).</description>
    <link>https://dev.to/edwinthinks</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%2F141569%2F9a509ae3-6266-4deb-a28c-714067d75ac2.jpeg</url>
      <title>DEV Community: Edwin Mak</title>
      <link>https://dev.to/edwinthinks</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/edwinthinks"/>
    <language>en</language>
    <item>
      <title>Skip turbo broadcasting to speed up seeding process in Rails</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Thu, 24 Nov 2022 11:08:47 +0000</pubDate>
      <link>https://dev.to/edwinthinks/skip-turbo-broadcasting-to-speed-up-seeding-process-in-rails-33cp</link>
      <guid>https://dev.to/edwinthinks/skip-turbo-broadcasting-to-speed-up-seeding-process-in-rails-33cp</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;We discovered that our seeding process for our rails application was getting very slow by turbo broadcasting via callbacks triggered by saving models. Although this works as intended, we certainly don't need to broadcast turbo frames in the seeding process and just serves to slow down the seeding process without any benefits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;We were able to speed up the seeding process by 3x (~140s to ~40s) by disabling turbo broadcasting in seeding.&lt;/em&gt; You can disable them too by inserting this code snippet before your seeding process:&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;Turbo::StreamsChannel&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:broadcast_append_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:broadcast_prepend_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:broadcast_replace_to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:broadcast_remove_to&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="nb"&gt;method&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;define_singleton_method&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="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kp"&gt;nil&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;span class="c1"&gt;# SEEDING PROCESS BEGINS&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;We were able to improve the developer experience by making the&lt;br&gt;
seeding process quicker with a short snippet of code. Shaving off about a minute of seeding seems insignificant, but it adds up!&lt;/p&gt;

&lt;p&gt;Hope this helps!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>seeding</category>
      <category>turbo</category>
    </item>
    <item>
      <title>How to find and identify a great mentor for me?</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Wed, 29 Jan 2020 20:39:55 +0000</pubDate>
      <link>https://dev.to/edwinthinks/how-to-find-and-identify-a-great-mentor-for-me-5dk4</link>
      <guid>https://dev.to/edwinthinks/how-to-find-and-identify-a-great-mentor-for-me-5dk4</guid>
      <description>&lt;p&gt;Hello DEV.to,&lt;/p&gt;

&lt;p&gt;I am currently looking for a mentor to guide &amp;amp; facilitate my growth as a technical professional &amp;amp; software engineer. What characteristics should I be looking for in a mentor? And where would be the best place to find this person?&lt;/p&gt;

&lt;p&gt;Most likely this is a very specific ask with different answers depending on my needs and preferences. In summary, I am a relatively new (less than 1 year) Lead Engineer on a tiny team with about 5 years of Ruby On Rails working experience. There are topics related to legacy code and hiring that I would like to talk with a more experienced person about.&lt;/p&gt;

&lt;p&gt;I would love to hear any advice on finding this person! Open to talking with any mentors that are reading this and is looking for an eager learner :)&lt;/p&gt;

</description>
      <category>help</category>
    </item>
    <item>
      <title>How to safely drop a deprecated database table</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Sat, 11 Jan 2020 16:24:16 +0000</pubDate>
      <link>https://dev.to/edwinthinks/how-to-safely-drop-a-deprecated-database-table-151</link>
      <guid>https://dev.to/edwinthinks/how-to-safely-drop-a-deprecated-database-table-151</guid>
      <description>&lt;h1&gt;
  
  
  Stop! Do not immediately drop a table because it appears unused or deprecated!
&lt;/h1&gt;

&lt;p&gt;I have a safer process for dropping deprecated tables that is less dangerous and mitigates issues!  Dropping a table can be very dangerous as you could lose all the historical data of that table if you don't have a backup. Also, you could be shooting yourself in the foot; if the table is still being used somewhere in your application, this undoubtedly introduces bugs. The later is more likely to happen if your application is not well tested. And most codebases that I've encountered are not well tested, so this process is likely applicable to you.&lt;/p&gt;

&lt;p&gt;Developers, including myself occasionally, have a terrible tendency to trust their memory and expertise of the application's internal workings. Just because you have a firm grasp of the application internals, you shouldn't just pull the trigger and drop the table. We are all human, we can forget and make mistakes. Do not rely on your memory instead rely on a process.&lt;/p&gt;

&lt;p&gt;Here is the process that I follow and highly recommend when dropping a deprecated table.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Steps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 - Determine if this table is indeed 'deprecated' and no other team is using it.
&lt;/h3&gt;

&lt;p&gt;You must be sure that the table in question is not being used anymore by anyone! Products like [Looker] have given non-technical people access to your database tables. The external team now has the power to analyze data and act on them. They might rely on it to perform their operations. You should reach out to other teams that you believe could be using it and get their consent on the deprecation process. If someone is relying on it, then stop and rethink the deprecation. Otherwise, let's move onto the next step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2 - Change the database table's name.
&lt;/h3&gt;

&lt;p&gt;Rename the table's name to &lt;code&gt;deprecated_{date}_tablename&lt;/code&gt; to see if you missed any issues referencing to that table. Bug reports (I recommend having a bug monitoring system in place first) will inform you of these issues. No worries. We can rollback to change the name back and handle the damage control. The damage incurred would be significantly less severe than actually dropping the table. Rollback and then start again from step (1).&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3 - Let the renamed deprecated table 'marinate' in production.
&lt;/h3&gt;

&lt;p&gt;You'll need to let the renamed deprecated table stay on production for enough time to indicate that it is safe to move on. Sometimes you'll have code that references to the table that doesn't execute very often. In this step, you'll need to decide how long is long enough. You can think about your applications usage profile to better help you decide. For instance, if you are a point of sales system that generates weekly reports to your clients then you might want to wait a week. This time can vary between different use cases, so I'd suggest using your best judgment here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4 - Drop the table! Boom!
&lt;/h3&gt;

&lt;p&gt;Now that we've gone through the precautionary steps 1, 2, and 3. You can drop that renamed table! Let's help that database shed some weight~&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;There you have it! These are the steps that I take when I am deprecating a database table (BTW also works for columns too). This process has saved me from headaches on numerous occasions. I had halted deprecation of a table after I discovered it was being used heavily by another team. In another case, I found that I didn't remove all references to the table and rolled back smoothly so that I could address them.&lt;/p&gt;

&lt;p&gt;The best thing about having steps and a process is that you can rely on and trust in the process. It is too much for a single developer to accurately memorize every detail of a niche part of your much broader application. &lt;/p&gt;

&lt;p&gt;Even if you choose not to use these steps, I still urge you to take extra precautions when dropping a database table for the sake of yourself and the other teams that rely on the database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Acknowledgement
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Thank you &lt;a href="https://www.linkedin.com/in/adammilligan/"&gt;Adam Milligan&lt;/a&gt; for teaching me this approach.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Featured image of the traffic light was downloaded from &lt;a href="https://www.claimsjournal.com/app/uploads/2012/09/bigstock-A-yellow-light-traffic-signal-35472008.jpg"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>deprecation</category>
    </item>
    <item>
      <title>A hilarious game to illustrate why UX is important!</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Mon, 08 Jul 2019 16:56:40 +0000</pubDate>
      <link>https://dev.to/edwinthinks/a-hilarious-game-to-illustrate-why-ux-is-important-2a05</link>
      <guid>https://dev.to/edwinthinks/a-hilarious-game-to-illustrate-why-ux-is-important-2a05</guid>
      <description>&lt;p&gt;As the title implies, this is the game developed by the cool people of &lt;a href="https://www.bagaar.be"&gt;Bagaar&lt;/a&gt; to show how UX is super important!&lt;/p&gt;

&lt;p&gt;You can play the game here:&lt;br&gt;
&lt;a href="https://userinyerface.com/"&gt;https://userinyerface.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Disclaimer:&lt;br&gt;
I'am not responsible for any thrown phones or smashed keyboards.&lt;/p&gt;

</description>
      <category>ux</category>
      <category>ui</category>
      <category>joke</category>
      <category>design</category>
    </item>
    <item>
      <title>Sprinkling StimulusJS - Light JS Without Heavy Choices.</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Sun, 07 Jul 2019 17:39:55 +0000</pubDate>
      <link>https://dev.to/edwinthinks/sprinkling-stimulusjs-light-js-without-heavy-choices-1nmm</link>
      <guid>https://dev.to/edwinthinks/sprinkling-stimulusjs-light-js-without-heavy-choices-1nmm</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;In today's state of web applications, it can be hard to choose the right tool to imbue your web pages with bits of interactivity. There is an immense number of options that you can take, but unfortunately, many of them require you to commit to a comprehensive javascript framework. This decision to commit I believe should not be taken lightly especially if you are making this choice for your team/company/business.&lt;/p&gt;

&lt;p&gt;The way I often handle these decisions is to not avoid making them at all. Decision fatigue and the stress it brings are real.&lt;/p&gt;

&lt;p&gt;In an evasive attitude of risk, I discovered &lt;a href="https://stimulusjs.org"&gt;StimulusJS&lt;/a&gt; as a possible option that fits some of the use cases. In this article, I share my experience with it in creating an interactive password input form with requirements being shown as being satisfied or not on user typing and my thoughts on it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Sprinkle Stimulus
&lt;/h1&gt;

&lt;p&gt;As the authors mentioned, the goal of Stimulus is to sprinkle pages with JS to make them sparkle. If you primarily have server-side rendered HTML pages and you want to imbue some interactivity on them, then it might be a good fit for your project. Otherwise, you might want to find another tool.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://stimulusjs.org/handbook/origin#the-three-core-concepts-in-stimulus"&gt;core concepts&lt;/a&gt; specifically mention that it is mainly meant to bind onto existing HTML and manipulating them. It is not concerned with creating HTML to render like &lt;a href="https://reactjs.org/"&gt;React&lt;/a&gt; does.&lt;/p&gt;

&lt;p&gt;For instance:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// In Stimulus
&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;data-controller=&lt;/span&gt;&lt;span class="s"&gt;"clipboard"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  PIN: &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;data-target=&lt;/span&gt;&lt;span class="s"&gt;"clipboard.source"&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;value=&lt;/span&gt;&lt;span class="s"&gt;"1234"&lt;/span&gt; &lt;span class="na"&gt;readonly&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;data-action=&lt;/span&gt;&lt;span class="s"&gt;"clipboard#copy"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Copy to Clipboard&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;// In React
&lt;span class="nt"&gt;&amp;lt;pin-input&amp;gt;&amp;lt;/pin-input&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the Stimulus approach, you'd see all the HTML up front and might avoid having to dig into another file to see what HTML would be. However, this could mean your HTML files can get larger and run the risk of being unmanageable.&lt;/p&gt;

&lt;h1&gt;
  
  
  StimulusJS Is Pretty Easy To Learn
&lt;/h1&gt;

&lt;p&gt;As a person who spends most of their time working in the backend, I found that the documentation was clear and easy to digest. I was able to get the main premise of it and enough information to use it fairly quickly. I spent about an hour (or so) with the documentation and was able to be productive with it.&lt;/p&gt;

&lt;h1&gt;
  
  
  Building An Interactive Password Input Field With Requirements
&lt;/h1&gt;

&lt;p&gt;In my pursuit of learning, I created a basic password input field that shows the requirements beneath it in an interactive manner. The requirements beneath are toggled to be satisfied or not satisfied upon user input. You can see the source code &lt;a href="https://github.com/edwinthinks/stimulus-password-requirements"&gt;here&lt;/a&gt; and test it live &lt;a href="https://stimulus-password-requirements.netlify.com/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A demo gif of it - &lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xjPOGzdf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y7fvk5dfm8htjvb3sfaq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xjPOGzdf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y7fvk5dfm8htjvb3sfaq.gif" alt="Demo of password requirements field" width="600" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is are snippets derived from the code that demonstrates it working together (with some code removed for brevity):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stimulus&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;PasswordInputController&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Controller&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;targets&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lowercaseLetter&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="c1"&gt;// Removed other targets for brevity.&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;

  &lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validatePassword&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;onInput&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;set&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validatePassword&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt; &lt;span class="o"&gt;=&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="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;validatePassword&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Validate lowercase letters&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lowerCaseLetters&lt;/span&gt; &lt;span class="o"&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;a-z&lt;/span&gt;&lt;span class="se"&gt;]&lt;/span&gt;&lt;span class="sr"&gt;/g&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lowerCaseLetters&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lowercaseLetterTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lowercaseLetterTarget&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;classList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;invalid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Removed code on other validations of brevity&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;PasswordInputController&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;data-controller=&lt;/span&gt;&lt;span class="s"&gt;"password-input"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"input"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"password"&lt;/span&gt; &lt;span class="na"&gt;data-action=&lt;/span&gt;&lt;span class="s"&gt;"input-&amp;gt;password-input#onInput"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/input&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;data-target=&lt;/span&gt;&lt;span class="s"&gt;"password-input.lowercaseLetter"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"password-requirements__requirement"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    At least one lowercase letter
  &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class="c"&gt;&amp;lt;!-- Remove Code For Brevity --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;PasswordInputController&lt;/code&gt; defines the logic that runs in relation to the HTML that it will be bound to. The &lt;code&gt;Controller&lt;/code&gt; class provided by Stimulus, gives us the ability to have sections of logic to run upon binding via &lt;code&gt;connect()&lt;/code&gt; and on user input defined by &lt;code&gt;onInput()&lt;/code&gt; and the &lt;code&gt;data-action="input-&amp;gt;password-input#onInput"&lt;/code&gt; attribute on the input element. A &lt;code&gt;validatePassword()&lt;/code&gt; function is defined to add/remove the &lt;code&gt;invalid&lt;/code&gt; CSS class of the corresponding &lt;code&gt;li&lt;/code&gt; elements via the &lt;code&gt;data-target&lt;/code&gt; attribute. This function is called initially by &lt;code&gt;connect()&lt;/code&gt; and also within the setter of &lt;code&gt;password&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Through this, I was able to produce a functional password input field.&lt;/p&gt;

&lt;h1&gt;
  
  
  Testing?
&lt;/h1&gt;

&lt;p&gt;I found that testing the controllers made via Stimulus was not as simple as I would have liked. &lt;/p&gt;

&lt;p&gt;I initially ran into some issues trying to get the stimulus controllers to run in due to missing &lt;code&gt;MutationObserver&lt;/code&gt;.  This was remedied by a &lt;a href="https://shime.sh/testing-stimulus"&gt;post by Hrvoje Šimić&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Unfortunately, there are not many resources related to how to testing. However, a &lt;a href="https://github.com/stimulusjs/stimulus/issues/260"&gt;issue&lt;/a&gt; had been opened recently to request added documentation on the official webpage.&lt;/p&gt;

&lt;p&gt;Admittedly, my struggles with getting the tests setup might be rooted in my inexperience.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Stimulus is a great tool that can be used to make your HTML pages "sparkle" with interactivity without having to commit to a framework. It was fairly easy and approachable to learn how to utilize the Stimulus.&lt;/p&gt;

&lt;p&gt;If you find yourself needing to add a little bit of interactivity onto your predominantly server-side HTML rendered application, you might find salvation in choosing to use Stimulus.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>stimulus</category>
    </item>
    <item>
      <title>Explain Selenium &amp; Webdrivers Like I'm Five</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Sun, 12 May 2019 16:42:52 +0000</pubDate>
      <link>https://dev.to/edwinthinks/explain-selenium-webdrivers-like-i-m-five-24me</link>
      <guid>https://dev.to/edwinthinks/explain-selenium-webdrivers-like-i-m-five-24me</guid>
      <description>&lt;p&gt;Hey there!&lt;/p&gt;

&lt;p&gt;I've been interested lately in applying end-to-end tests to my web application. I've seen several options available but I don't really understand the differences or how they work.&lt;/p&gt;

&lt;p&gt;For instances, how does a remote selenium server work in practice? How does the remote selenium server have access to say a server running on my local machine (if thats how it works?)&lt;/p&gt;

&lt;p&gt;This area is very new to me and am eager to learn more :)&lt;/p&gt;

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

</description>
      <category>explainlikeimfive</category>
      <category>selenium</category>
      <category>e2e</category>
    </item>
    <item>
      <title>Enhance your PostgreSQL practice on MacOSX with Postico</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Tue, 07 May 2019 14:30:05 +0000</pubDate>
      <link>https://dev.to/edwinthinks/enhance-your-postgresql-practice-on-macosx-with-postico-2g97</link>
      <guid>https://dev.to/edwinthinks/enhance-your-postgresql-practice-on-macosx-with-postico-2g97</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h4&gt;
  
  
  Disclaimer - Postico is only supported by MacOSX.
&lt;/h4&gt;

&lt;p&gt;I've noticed on numerous occasions of developers that might be giving themselves a more difficult time practicing or playing with their PostgresSQL database using the default interactive terminal. Admittedly, I was also one of these developers until my boss at the time offered me an alternative. He suggested using &lt;a href="https://eggerapps.at/postico/"&gt;Postico&lt;/a&gt;, a PostgresSQL client, and I've been happily using it since. Of course, there are &lt;a href="https://postgresapp.com/documentation/gui-tools.html"&gt;several PostgresSQL clients&lt;/a&gt; available with their various advantages &amp;amp; disadvantages. &lt;/p&gt;

&lt;p&gt;In terms of simplicity, ease of use, minimalism, I believe &lt;a href="https://eggerapps.at/postico/"&gt;Postico&lt;/a&gt; is a great fit for beginners or a basic user that just wants to wipe up some queries quick. Here are some of my reasons:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note - I am not financial tied with the success of Postico. I am just a web developer who thinks this can help others :).&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Free Version Is Useful
&lt;/h2&gt;

&lt;p&gt;The free version of Postico provides enough utility to be useful and is not super annoying. There are some products out on the market that makes their free edition very annoying to use as a sales tactic. The free edition of Postico does come with limitations but aren't those that would make you want to pull your hair out.&lt;/p&gt;

&lt;p&gt;Here are the limitations as per their &lt;a href="https://eggerapps.at/postico/"&gt;FAQ&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pDyxlHyj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xzk4f0znlh9kprweirzb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pDyxlHyj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/xzk4f0znlh9kprweirzb.png" alt="List Of Postico Free Trial Limitations" title="List Of Free Trial Limitations" width="880" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I feel like these limitations aren't the most annoying for most use-cases. Plus, you can use the free edition for as long as you want!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Please purchase their license to support them if you have the means to :)&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Their Minimalist UI
&lt;/h2&gt;

&lt;p&gt;Their biggest selling point is the minimalist UI in their product. On first load, you are presented with a few options that feel intuitive and easy to navigate.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ACBmkuCU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/18l178ppua77av4w7w2c.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ACBmkuCU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/18l178ppua77av4w7w2c.png" alt="Snapshot of Postico's minimalist UI" title="Snapshot of Postico's minimalist UI" width="880" height="715"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adding and saving configurations for accessing local or deployed databases is a breeze.&lt;/p&gt;

&lt;p&gt;The UI for the editor &amp;amp; query results is clear and intuitive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VkIkacle--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kng026f4vi5q9f0epdk8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VkIkacle--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kng026f4vi5q9f0epdk8.png" alt="Snapshot of Postico's minimalist UI for table &amp;amp; editor" title="Snapshot of Postico's minimalist UI for table &amp;amp; editor" width="880" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Saving &amp;amp; Loading Queries
&lt;/h2&gt;

&lt;p&gt;Fairly self-explanatory, but the ability to easily save and load your queries is a must have in these client tools. Nothing worst then building a super awesome query and then losing it!&lt;/p&gt;

&lt;h2&gt;
  
  
  Executing select highlighted portions of your SQL + 'Execute Statement' hotkey
&lt;/h2&gt;

&lt;p&gt;There have been times I find myself wanting to fiddle with multiple queries side-by-side. I found that having multiple tabs and windows can be distracting. Hence, being able to write out multiple queries and running them selectively has been a total game changer!&lt;/p&gt;

&lt;p&gt;Heres a quick gif of this feature in action (Press CMD + Return to trigger hotkey to "Execute Statement"):&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iy3QhhL1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jwup4oo53954noyp3eyj.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iy3QhhL1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jwup4oo53954noyp3eyj.gif" alt="Executing select highlighted portions of your SQL gif" title="Executing select highlighted portions of your SQL" width="600" height="375"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;I am obviously a big fan of using Postico. But that doesn't mean that this is the right tool for everybody forever. You may find that there are other tools that resonate with your needs more and you should reach for it! Wither you decide to use Postico or not, I hope that you've been encouraged to find tools that can improve your experience as a developer working with SQL.&lt;/p&gt;

&lt;h4&gt;
  
  
  Our jobs are difficult enough and filled with complexity, a little bit of convenience here and there goes a long way.
&lt;/h4&gt;

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

</description>
      <category>beginners</category>
      <category>sql</category>
      <category>postgres</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Convert YAML column data to JSONB in Rails and Postgres</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Sun, 05 May 2019 00:56:45 +0000</pubDate>
      <link>https://dev.to/edwinthinks/convert-yaml-column-data-to-jsonb-in-rails-and-postgres-4mko</link>
      <guid>https://dev.to/edwinthinks/convert-yaml-column-data-to-jsonb-in-rails-and-postgres-4mko</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;My team had wanted to take advantage of the incredibly useful &lt;a href="https://www.postgresql.org/docs/9.4/functions-json.html"&gt;JSON features&lt;/a&gt; provided by Postgres 9.4+ in working with data that our rails application was storing as YAML in a text column. We had installed a very useful gem called &lt;a href="https://github.com/collectiveidea/audited"&gt;audited&lt;/a&gt; that was responsible for keeping track of "when" &amp;amp; "what" changed in our ActiveRecord records. The "what" data was, unfortunately, being stored as YAML in a text column and makes querying this data more difficult than it needs to be. Here is a sample of that "what" data:&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="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;pilot&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is what I want it to be like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"pilot"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notably, the authors of the audited gem included the option to install it such that this data is stored in JSONB (default is YAML). &lt;/p&gt;

&lt;p&gt;Lately, we have been interested in building more advanced queries to search by the content of this "what" data. As a result, we aimed to create a migration that can transform the data safely back and forth from YAML to JSONB (reversible for good measure).&lt;/p&gt;

&lt;h2&gt;
  
  
  The Result
&lt;/h2&gt;

&lt;p&gt;Here is a migration file that we ended up generating that converts the &lt;code&gt;audited_changes&lt;/code&gt; column (that "what" data) on the &lt;code&gt;audits&lt;/code&gt; table from YAML to JSONB. You can also utilize this snippet of code to transform your YAML column to JSONB.&lt;/p&gt;

&lt;h4&gt;
  
  
  Disclaimer - Migrate at your own risk!
&lt;/h4&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;ChangeAuditedChangesFromYamlToJson&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;Migration&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;up&lt;/span&gt;
    &lt;span class="n"&gt;updated_records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_audit_records&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;r&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="ss"&gt;audited_changes: &lt;/span&gt;&lt;span class="n"&gt;escape_sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;safe_load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'audited_changes'&lt;/span&gt;&lt;span class="p"&gt;])))&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;remove_column&lt;/span&gt; &lt;span class="ss"&gt;:audits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:audited_changes&lt;/span&gt;
    &lt;span class="n"&gt;add_column&lt;/span&gt; &lt;span class="ss"&gt;:audits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:audited_changes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:jsonb&lt;/span&gt;

    &lt;span class="no"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;updated_records&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;ur&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="s2"&gt;"""
            UPDATE audits 
            SET audited_changes = '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;ur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:audited_changes&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'::jsonb 
            WHERE id = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;ur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
          """&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="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;down&lt;/span&gt;
    &lt;span class="n"&gt;updated_records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fetch_audit_records&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;r&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;id: &lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="ss"&gt;audited_changes: &lt;/span&gt;&lt;span class="n"&gt;escape_sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'audited_changes'&lt;/span&gt;&lt;span class="p"&gt;])))&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;remove_column&lt;/span&gt; &lt;span class="ss"&gt;:audits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:audited_changes&lt;/span&gt;
    &lt;span class="n"&gt;add_column&lt;/span&gt; &lt;span class="ss"&gt;:audits&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:audited_changes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:text&lt;/span&gt;

    &lt;span class="no"&gt;Transaction&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transaction&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="n"&gt;updated_records&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;ur&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="s2"&gt;"""
            UPDATE audits 
            SET audited_changes = '&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;ur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:audited_changes&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;'::text 
            WHERE id = &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;ur&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;
          """&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="k"&gt;end&lt;/span&gt;

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

  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# Returns the id &amp;amp; audit_changes column of the audits table.&lt;/span&gt;
  &lt;span class="c1"&gt;# @return [PG::Result]&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;fetch_audit_records&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="s1"&gt;'SELECT id, audited_changes FROM audits'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="c1"&gt;#&lt;/span&gt;
  &lt;span class="c1"&gt;# Returns the SQL escaped version of the string provided &lt;/span&gt;
  &lt;span class="c1"&gt;# For example, a "'" needs to be escaped by doubling it.&lt;/span&gt;
  &lt;span class="c1"&gt;# @param [String] the string to be converted&lt;/span&gt;
  &lt;span class="c1"&gt;# @return [String] the escaped version of the string provided&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;escape_sql&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"'"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"''"&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;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It took some trial and error and navigating through some 'gotchas' to arrive at our resultant migration. For instance, we had to escape single-quote characters by adding another single-quote next to every instance (See the &lt;code&gt;escape_sql&lt;/code&gt; method in the code snippet). Nonetheless, we are happy with the results and excited to start building queries with those super awesome JSON features given to us by Postgres.&lt;/p&gt;

&lt;p&gt;Hope this helps someone else =). Happy coding!&lt;/p&gt;

</description>
      <category>rails</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Seeking suggestions for leveling up web design skills</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Mon, 29 Apr 2019 15:03:57 +0000</pubDate>
      <link>https://dev.to/edwinthinks/seeking-suggestions-for-leveling-up-web-design-skills-1kld</link>
      <guid>https://dev.to/edwinthinks/seeking-suggestions-for-leveling-up-web-design-skills-1kld</guid>
      <description>&lt;p&gt;Hello DEV community,&lt;/p&gt;

&lt;p&gt;I am seeking to level up my abilities as a designer to be able to boost my confidence building visually pleasing (Sorry I know this is vague) websites &amp;amp; UI. &lt;/p&gt;

&lt;p&gt;I believe I exercise a good amount of HTML &amp;amp; CSS as I can take a design given to me and create it in code. I'd like to be able to start designing web UIs that I can myself translate into code. I was wondering if there are courses, resources, tips on how I can get better..&lt;/p&gt;

&lt;p&gt;Thanks a ton!&lt;/p&gt;

</description>
      <category>help</category>
      <category>design</category>
      <category>web</category>
    </item>
    <item>
      <title>Explain Required Sign In Forms For Wifi Access Like I'm Five</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Fri, 26 Apr 2019 14:56:14 +0000</pubDate>
      <link>https://dev.to/edwinthinks/explain-required-sign-in-forms-for-wifi-access-like-i-m-five-l6f</link>
      <guid>https://dev.to/edwinthinks/explain-required-sign-in-forms-for-wifi-access-like-i-m-five-l6f</guid>
      <description>&lt;p&gt;Hello there!&lt;/p&gt;

&lt;p&gt;I've always wondered how some wifi connections require you to sign in or fill out a form on a page before you can freely access the internet. How is this effect implemented?&lt;/p&gt;

&lt;p&gt;I know little about the actual hardware and the networking that may or may not be involved.&lt;/p&gt;

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

</description>
      <category>explainlikeimfive</category>
      <category>curious</category>
      <category>wifi</category>
      <category>how</category>
    </item>
    <item>
      <title>Rituals before bed for better work life balance &amp; sleep</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Thu, 25 Apr 2019 20:41:59 +0000</pubDate>
      <link>https://dev.to/edwinthinks/rituals-before-bed-for-better-work-life-balance-sleep-248l</link>
      <guid>https://dev.to/edwinthinks/rituals-before-bed-for-better-work-life-balance-sleep-248l</guid>
      <description>&lt;p&gt;Hey Community!&lt;/p&gt;

&lt;p&gt;I've been having issues with keeping my mind free from thoughts about work while trying to goto and staying asleep. I've been meaning to practice mediation more on a daily basis as a supplement.&lt;/p&gt;

&lt;p&gt;If you've had or have now a similar issue, what ways are you trying to get better rest?&lt;/p&gt;

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

</description>
      <category>discuss</category>
      <category>balance</category>
      <category>life</category>
    </item>
    <item>
      <title>The Useful &amp; Hidden '_' Command In IRB</title>
      <dc:creator>Edwin Mak</dc:creator>
      <pubDate>Thu, 07 Mar 2019 13:07:04 +0000</pubDate>
      <link>https://dev.to/edwinthinks/the-useful--hidden--command-in-ruby-dlo</link>
      <guid>https://dev.to/edwinthinks/the-useful--hidden--command-in-ruby-dlo</guid>
      <description>&lt;h2&gt;
  
  
  Introduction (TLDR sorta)
&lt;/h2&gt;

&lt;p&gt;As a developer, I am alway seeking for tools and tricks that allow me to be more efficient while working on projects. As a result, I've adopted some lesser known ruby interactive shell command. One of which is the underscore or &lt;code&gt;_&lt;/code&gt;. I found that this command when applied can be super beneficial and boost your productivity!&lt;/p&gt;

&lt;p&gt;The underscore simply gives you the return value of the last evaluation made in the console. I find this especially useful in the event I forget to assign the output of a block of code or when I perform a query via Rails that I’d rather not run again. Let me show you what I mean:&lt;/p&gt;

&lt;h2&gt;
  
  
  Example Use Case
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fl5u942ihb0m5dpxv7nws.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%2Fl5u942ihb0m5dpxv7nws.png" alt="Example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Above is a screenshot detailing an example use case. In that example, I evaluated a block of code with a 5-second pause (to simulate a slow operation) without assigning it to the variable animal. Nothing to worry about, you can just use the underscore to avoid having to execute that code again!&lt;/p&gt;

&lt;p&gt;Another fairly common situation were you might benefit from using the &lt;code&gt;_&lt;/code&gt; method is when you run a query in Rails... but forgot to assign it to a variable!&lt;/p&gt;

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

&lt;p&gt;The underscore is a useful tool to use when you are working in the ruby interactive shell. It may not seem like a lot of time to just re-run slow code… but it does add up!&lt;/p&gt;

&lt;p&gt;What other kinds of hidden ruby tricks are there out? Please comment on this post if you know any and are in a charitable mood.&lt;/p&gt;

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