<?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: Tyler Scott Williams</title>
    <description>The latest articles on DEV Community by Tyler Scott Williams (@ogdenstudios).</description>
    <link>https://dev.to/ogdenstudios</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%2F331439%2F2cd09369-4f80-44fc-a988-9dd60f9c898c.jpeg</url>
      <title>DEV Community: Tyler Scott Williams</title>
      <link>https://dev.to/ogdenstudios</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ogdenstudios"/>
    <language>en</language>
    <item>
      <title>Duplicate Zeros - Optimal Solution in Ruby</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Mon, 19 Apr 2021 00:47:55 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/leetcode-duplicate-zeros-optimal-solution-in-ruby-1igk</link>
      <guid>https://dev.to/ogdenstudios/leetcode-duplicate-zeros-optimal-solution-in-ruby-1igk</guid>
      <description>&lt;h2&gt;
  
  
  Description
&lt;/h2&gt;

&lt;p&gt;Given a fixed length array &lt;code&gt;arr&lt;/code&gt; of integers, duplicate each occurrence of zero, shifting the remaining elements to the right.&lt;/p&gt;

&lt;p&gt;Note that elements beyond the length of the original array are not written.&lt;/p&gt;

&lt;p&gt;Do the above modifications to the input array in place, do not return anything from your function.&lt;/p&gt;

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

&lt;p&gt;It took me a few days to wrap my head around this solution, which modifies the array in-place. I understood the &lt;a href=""&gt;naive solution&lt;/a&gt; a little easier to start. The naive solution takes up extra space by using a reference array to reconstruct the array. &lt;/p&gt;

&lt;p&gt;But we can solve it without using extra space, which is good, because using a reference array would use twice the space.&lt;/p&gt;

&lt;p&gt;First, think about what the array might look like if we extended it to contain all the elements, including the duplicate zeros. It would be an array of length &lt;code&gt;arr.length + number_of_zeros_in_the_array&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Take this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[1,0,2,3,0,4,5,0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we had an array that could contain the dulicate zeros and the existing elements, it would look 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;[1,0,0,2,3,0,0,4,5,0,0]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The length of the first array is 8. The length of the second array is 11. There are 3 zeros in the original array, and 11 - 8 = 3. &lt;/p&gt;

&lt;p&gt;So the "return" value (in quotes, since we're modifying in place and not really returning anything), would look 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;[1,0,0,2,3,0,0,4]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which is the first 8 (remember: the length of the input array) elements of our thought-exercise array #2 (the one that was 11 elements long). &lt;/p&gt;

&lt;p&gt;So we can modify the array in-place without overwriting values by walking backwards from the "end" of our "imaginary array". We have to keep track of three things: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An iterator that starts at the "end" of the "imaginary" array and moves towards the beginning of the input array. Call that &lt;code&gt;j&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;An iterator that starts at the end of the input array. Call that &lt;code&gt;i&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;For convenience, let's keep track of the length of the original array. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We'll set up a loop that decrements &lt;code&gt;i&lt;/code&gt;, and writes to the array in position &lt;code&gt;j&lt;/code&gt;, but &lt;strong&gt;only if &lt;code&gt;j&lt;/code&gt; is pointing to an position that exists within the input array&lt;/strong&gt;. It will write the value at &lt;code&gt;arr[i]&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Each time we perform this action, we check if that value is &lt;code&gt;0&lt;/code&gt;. If it is, we need to duplicate the &lt;code&gt;0&lt;/code&gt; value in our writing to the original array. We can do that by decrementing the &lt;code&gt;j&lt;/code&gt; iterator &lt;em&gt;one more time&lt;/em&gt;. This means that &lt;code&gt;j&lt;/code&gt; will move faster than &lt;code&gt;i&lt;/code&gt; (assuming there are 1 or more &lt;code&gt;0&lt;/code&gt;s in the array), and eventually catch up with it - writing the appropriate duplicate &lt;code&gt;0&lt;/code&gt; values. &lt;/p&gt;

&lt;p&gt;All along the way, we use &lt;code&gt;n&lt;/code&gt; to make sure we never try and write to the array at a position in the longer, imaginary array. We decrement both &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; each time to keep moving backwards through the array until we hit position &lt;code&gt;0&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I found it a little hard to keep the two iterators straight in my head, so here's a table that illustrates the process for &lt;code&gt;[1,0,2,3,0,4,5,0]&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Iteration&lt;/th&gt;
&lt;th&gt;i&lt;/th&gt;
&lt;th&gt;j&lt;/th&gt;
&lt;th&gt;Write to arr[j]?&lt;/th&gt;
&lt;th&gt;Decrement j twice?&lt;/th&gt;
&lt;th&gt;Write 0 twice?&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;No, j &amp;gt; 7&lt;/td&gt;
&lt;td&gt;Yes, arr[7] == 0&lt;/td&gt;
&lt;td&gt;No, j &amp;gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;No, j &amp;gt; 7&lt;/td&gt;
&lt;td&gt;No, arr[6] != 0&lt;/td&gt;
&lt;td&gt;No, arr[6] != 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;Yes, j == 7&lt;/td&gt;
&lt;td&gt;No, arr[5] != 0&lt;/td&gt;
&lt;td&gt;No, arr[5] != 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;Yes, j &amp;lt; 7&lt;/td&gt;
&lt;td&gt;Yes, arr[4] == 0&lt;/td&gt;
&lt;td&gt;Yes, arr[4] == 0 &amp;amp;&amp;amp; j &amp;lt; 7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;Yes, j &amp;lt; 7&lt;/td&gt;
&lt;td&gt;No, arr[3] != 0&lt;/td&gt;
&lt;td&gt;No arr[3] != 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Yes, j &amp;lt; 7&lt;/td&gt;
&lt;td&gt;No, arr[2] != 0&lt;/td&gt;
&lt;td&gt;No arr[2] != 0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;6&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;Yes, j &amp;lt; 7&lt;/td&gt;
&lt;td&gt;Yes, arr[1] == 0&lt;/td&gt;
&lt;td&gt;Yes, arr[1] == 0 &amp;amp;&amp;amp; j &amp;lt; 7&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;0&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two things to notice in the last row of this table: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;i == j&lt;/code&gt;, which is important. Since &lt;code&gt;j&lt;/code&gt; moves faster than &lt;code&gt;i&lt;/code&gt;, but we move through the array backwards with &lt;code&gt;i&lt;/code&gt; which started at a position closer to the beginning, we eventually need the two of these values to converge. &lt;/li&gt;
&lt;li&gt;We don't actually need to take any action in the final iteration, because the first element of the array will always be the same. We can loop until we hit that first element with &lt;code&gt;j&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# @param {Integer[]} arr&lt;/span&gt;
&lt;span class="c1"&gt;# @return {Void} Do not return anything, modify arr in-place instead.&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;duplicate_zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Determine the number of zeros in the array &lt;/span&gt;
    &lt;span class="n"&gt;number_of_zeros&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&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="c1"&gt;# Set up a variable to represent the length of the array&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;

    &lt;span class="c1"&gt;# Initialize iterator i to the end of the array&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Initialize iterator j to be the end of the array + number of zeros&lt;/span&gt;
    &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;number_of_zeros&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

    &lt;span class="c1"&gt;# Count backwards from j to the beginning of the array&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
    &lt;span class="c1"&gt;# arr[j] = arr[i] if j is within the range of the array (less than n)&lt;/span&gt;
        &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="c1"&gt;# If that number is 0, decrement j an extra time&lt;/span&gt;
        &lt;span class="c1"&gt;# This means j will move faster than i until they meet&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; 
            &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="c1"&gt;# This is where we duplicate the zero - &lt;/span&gt;
            &lt;span class="c1"&gt;# write to arr[j] if j is within the range of the array.&lt;/span&gt;
            &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="c1"&gt;# Decrement both i and j during each loop - &lt;/span&gt;
    &lt;span class="c1"&gt;# we want both of them to be counting down.&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>algorithms</category>
      <category>computerscience</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Duplicate Zeroes, Naive Solution</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Sun, 18 Apr 2021 18:27:41 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/solve-duplicate-zeroes-naive-solution-322b</link>
      <guid>https://dev.to/ogdenstudios/solve-duplicate-zeroes-naive-solution-322b</guid>
      <description>&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;Given a fixed length array arr of integers, duplicate each occurrence of zero, shifting the remaining elements to the right.&lt;/p&gt;

&lt;p&gt;Note that elements beyond the length of the original array are not written.&lt;/p&gt;

&lt;p&gt;Do the above modifications to the input array in place, do not return anything from your function.&lt;/p&gt;

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

&lt;p&gt;This is the brute force solution, expressed in Ruby. &lt;/p&gt;

&lt;p&gt;I figured this out by doing a few examples by hand and thinking to myself what was going on in my brain. Since I wrote the original input, and then wrote to a "new" array, I realized I needed to duplicate the input array and use it as a reference. &lt;/p&gt;

&lt;p&gt;Once you duplicate the array for reference, you'll want two iterators: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;i&lt;/code&gt; iterates through the input array, modifying its values &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;j&lt;/code&gt; iterates through the reference array, providing values for reference. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For ease of use, I also set the variable &lt;code&gt;n&lt;/code&gt; to equal &lt;code&gt;arr.length&lt;/code&gt;. We'll use that in the while loop. &lt;/p&gt;

&lt;p&gt;Start both at &lt;code&gt;0&lt;/code&gt;. Make &lt;code&gt;arr[i]&lt;/code&gt; = &lt;code&gt;reference[j]&lt;/code&gt; to start. Each step of the way, check if &lt;code&gt;reference[j]&lt;/code&gt; is &lt;code&gt;0&lt;/code&gt;. If it is, you want to &lt;em&gt;do that again&lt;/em&gt;, because the solution tells you to duplicate zeros. In order to do it again, we increment &lt;code&gt;i&lt;/code&gt; by 1, and we &lt;em&gt;leave &lt;code&gt;j&lt;/code&gt; alone&lt;/em&gt;. I originally had trouble wrapping my head around which iterator to increment and how to "duplicate" the &lt;code&gt;0&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Next, you'll want to increment both &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;j&lt;/code&gt; by 1. You need to do this regardless of whether or not the number was &lt;code&gt;0&lt;/code&gt;, because we need to keep moving through both arrays. &lt;/p&gt;

&lt;p&gt;The one gotcha to look out for is that in the &lt;code&gt;0&lt;/code&gt; check, we increment &lt;code&gt;i&lt;/code&gt;, but it's possible that the last element is &lt;code&gt;0&lt;/code&gt;, in which case you'll end up with a larger array (in languages like Ruby, which have dynamically-resizing arrays. In other languages, you may have actual runtime errors). So we can check that &lt;code&gt;i&lt;/code&gt; &amp;lt; &lt;code&gt;n&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The while loop should terminate when &lt;code&gt;i == n&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# @param {Integer[]} arr&lt;/span&gt;
&lt;span class="c1"&gt;# @return {Void} Do not return anything, modify arr in-place instead.&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;duplicate_zeros&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Create a reference array &lt;/span&gt;
    &lt;span class="n"&gt;reference&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dup&lt;/span&gt;

    &lt;span class="c1"&gt;# Set up iterator i, to move through the input array&lt;/span&gt;
    &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; 
    &lt;span class="c1"&gt;# Set up iterator j, to move through the reference array&lt;/span&gt;
    &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="c1"&gt;# Set up n as a convenience to represent the length of the input array&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;

    &lt;span class="c1"&gt;# Loop and increment `i` until we've gone through the entire input array.&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; 
        &lt;span class="c1"&gt;# First up, overwrite the array at position i with our reference value at position j&lt;/span&gt;
        &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
        &lt;span class="c1"&gt;# Then, check if that value was 0.&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; 
            &lt;span class="c1"&gt;# If so, increment i by one. This is how we "duplicate" the zero.&lt;/span&gt;
            &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; 
            &lt;span class="c1"&gt;# You'll need to write that 0 to arr[i]. But be careful - if reference[j] == 0, and j == n -1 (i.e. the last reference value is 0)&lt;/span&gt;
            &lt;span class="c1"&gt;# then you'll overflow. So use `unless` to make sure `i &amp;lt; n`.&lt;/span&gt;
            &lt;span class="n"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reference&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="c1"&gt;# We will always need to increment i and j at each step, to continue moving the loop forward.&lt;/span&gt;
        &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="k"&gt;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;
  
  
  Analysis
&lt;/h2&gt;

&lt;p&gt;This solution take O(n) time and O(n^2) space, since you have to loop through the input array just once, but you'll need to duplicate it in the reference variable. There's a better way that uses constant space, but I wanted to explore the naive solution in depth, because it honestly threw me for a loop for a bit!&lt;/p&gt;

</description>
      <category>algorithms</category>
      <category>ruby</category>
      <category>computerscience</category>
    </item>
    <item>
      <title>Heuristics for Object-Oriented Design in Ruby</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Fri, 04 Dec 2020 04:39:26 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/heuristics-for-object-oriented-design-in-ruby-1ip2</link>
      <guid>https://dev.to/ogdenstudios/heuristics-for-object-oriented-design-in-ruby-1ip2</guid>
      <description>&lt;p&gt;Any Rubyist should read and study &lt;a href="https://www.poodr.com/"&gt;Practical Object Oriented Design, An Agile Primer Using Ruby (POODR)&lt;/a&gt;, by Sandi Metz. &lt;/p&gt;

&lt;p&gt;Personally, I've read through the book three times. Each time I read it, I find new insights that improve my work as a Ruby programmer, and as a software engineer in general. POODR walks through fundamental object-oriented concepts and pairs them with practical examples in Ruby. Over the course of the book, Metz builds and refactors a sample program that demonstrates these principles.&lt;/p&gt;

&lt;p&gt;Despite the book's clarity and practicality (it's a short, to-the-point read), it's hard to keep all of the lessons in your head when you sit down to apply them in your own work. To help myself accomplish that very task, I put together a checklist I call &lt;em&gt;Heuristics for Object-Oriented Design in Ruby&lt;/em&gt;. Here's how I use it: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;I do my work and solve the challenge at hand&lt;/li&gt;
&lt;li&gt;I take a break, and step away from the code I've written&lt;/li&gt;
&lt;li&gt;Before making a pull request, I go over my changes and run through this checklist, evaluating my code against each item.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It's not always clean and simple, and not all of the checklist always applies, hence "heuristics". But overall, this systematic review of my Ruby code has given me a more concrete understanding of the lessons contained in POODR. I hope it will be of similar value to you.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Heuristics
&lt;/h2&gt;

&lt;p&gt;Starting with (what I consider) the simplest items, work you way towards the more complex and philosophical line items.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code smells
&lt;/h3&gt;

&lt;p&gt;These items can be identified in any Ruby file. They are often the most straightforward to resolve. At the very least, these items may prompt you to consult with an item further down in the list.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use named args to remove order dependencies (Metz, 2019, p. 48).&lt;/li&gt;
&lt;li&gt;Hide all instance variables behind methods (Metz, 2019, p. 24).&lt;/li&gt;
&lt;li&gt;Isolate new instances of objects behind methods (Metz, 2019, p. 44).&lt;/li&gt;
&lt;li&gt;If an object must send messages to any object other than &lt;code&gt;self&lt;/code&gt;, isolate sending that message in one single method (Metz, 2019, p. 45).&lt;/li&gt;
&lt;li&gt;Obey the Law of Demeter (Metz, 2019, p. 81).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Code organization
&lt;/h3&gt;

&lt;p&gt;These items are harder to identify in code alone, but looking for them will help you find opportunities to improve the structure of your program holistically. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use the &lt;code&gt;private&lt;/code&gt; keyword to create intentionally designed public interfaces (Metz, 2019, p. 64).&lt;/li&gt;
&lt;li&gt;Use simple dependency injection by passing collaborating objects as arguments to methods (Metz, 2019, p. 43).&lt;/li&gt;
&lt;li&gt;Use duck typing when you see: case statements that switch on &lt;code&gt;class&lt;/code&gt;, or methods that ask &lt;code&gt;is_a?&lt;/code&gt; or &lt;code&gt;kind_of?&lt;/code&gt; (Metz, 2019, p. 95). &lt;/li&gt;
&lt;li&gt;Use inheritance when you are conditionally sending messages to &lt;code&gt;self&lt;/code&gt; based on some attribute of &lt;code&gt;self&lt;/code&gt; (Metz, 2019, p. 134).&lt;/li&gt;
&lt;li&gt;Promote code up to superclasses rather than down to subclasses (Metz, 2019, p. 143).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Abstraction considerations
&lt;/h3&gt;

&lt;p&gt;These items are concerned with the way in which your code models the problem domain at hand. They are more subjective, but remain useful even in quick code reviews. &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Every class should have a one sentence description, no conjunctions allowed (Metz, 2019, p. 22).&lt;/li&gt;
&lt;li&gt;If you rephrase your class methods as questions to the object, each question should make sense; it should be related to the purpose of the class (Metz, 2019, p. 22).&lt;/li&gt;
&lt;li&gt;Messages should ask for "what" instead of dictating "how" (Metz, 2019, p. 70).&lt;/li&gt;
&lt;li&gt;Enforce good dependency direction (Metz, 2019, p. 55).&lt;/li&gt;
&lt;li&gt;Depend on abstractions before depending on concrete classes (Metz, 2019, p. 57).&lt;/li&gt;
&lt;li&gt;Default to composition over inheritance (Metz, 2019, p. 209).&lt;/li&gt;
&lt;li&gt;Create shallow hierarchies (Metz, 2019, p. 183).&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Use named args to remove order dependencies
&lt;/h2&gt;

&lt;p&gt;Knowing the required ordering of method arguments is a type of dependency, and it's an easy dependency to avoid.&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;# Bad &lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deal_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;cards: &lt;/span&gt;&lt;span class="n"&gt;cards&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;# Good &lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deal_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
    &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;cards: &lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the first example, if you pass the arguments in the incorrect order, bad or unexpected things might happen, and it could be unclear why. More importantly - if the argument order changes (or you add more, etc.), changing the code where you use the old version gets messy. &lt;/p&gt;

&lt;p&gt;In the second example, you can change the ordering of the arguments any way you like, and it will work. You get the added nicety that Ruby will tell you precisely what arguments you're missing, should you forget to pass them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Hide all instance variables behind methods
&lt;/h2&gt;

&lt;p&gt;When a class accesses an instance variable directly, that's a dependency. If the instance variable has to change, you have to change many lines of code.&lt;/p&gt;

&lt;p&gt;Ruby provides an excellent solution for this, &lt;a href="https://ruby-doc.org/core-2.0.0/Module.html#method-i-attr_accessor"&gt;attr_accessor&lt;/a&gt;, and its siblings: &lt;code&gt;attr_reader&lt;/code&gt;, and &lt;code&gt;attr_writer&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Bad &lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BettingRound&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
        &lt;span class="vi"&gt;@bets&lt;/span&gt; &lt;span class="o"&gt;=&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;0&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;0&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;0&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;0&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="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pot&lt;/span&gt; 
        &lt;span class="vi"&gt;@bets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&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;high_bet&lt;/span&gt;
        &lt;span class="vi"&gt;@bets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&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;# Good&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BettingRound&lt;/span&gt;
    &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:bets&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
        &lt;span class="vi"&gt;@bets&lt;/span&gt; &lt;span class="o"&gt;=&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;0&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;0&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;0&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;0&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="k"&gt;end&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;pot&lt;/span&gt; 
        &lt;span class="n"&gt;bets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sum&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;high_bet&lt;/span&gt;
        &lt;span class="n"&gt;bets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;max&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;It's a subtle change, but by wrapping the &lt;code&gt;@bets&lt;/code&gt; instance variable in an accessor, we get the option to override the method should we wish to, like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bets&lt;/span&gt; 
    &lt;span class="vi"&gt;@bets&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;bet&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;bet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_f&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The idea here is that now &lt;code&gt;bets&lt;/code&gt; is a message to which &lt;code&gt;BettingRound&lt;/code&gt; responds, rather than being a piece of data &lt;code&gt;BettingRound&lt;/code&gt; knows about and manipulates. &lt;/p&gt;

&lt;h2&gt;
  
  
  Isolate new instances of objects behind methods
&lt;/h2&gt;

&lt;p&gt;When an object knows the name of another object, that's a dependency we can avoid. When an object also knows the names of methods on a different object, that's an additional dependency. &lt;/p&gt;

&lt;p&gt;Still, objects need to collaborate with other objects. Sometimes you can't avoid it, like if a &lt;code&gt;Game&lt;/code&gt; needs to know about a &lt;code&gt;BettingRound&lt;/code&gt;. Instantiating a new instance of &lt;code&gt;BettingRound&lt;/code&gt; has to happen somewhere. You may choose to do so inside the &lt;code&gt;Game&lt;/code&gt; class. Regardless of the best possible decision, if you have existing code where this happens, you can provide some good abstraction by wrapping instantiation in method calls.&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;# Bad&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:current_betting_round&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;start_new_hand&lt;/span&gt;
        &lt;span class="n"&gt;current_betting_round&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BettingRound&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="c1"&gt;# Good&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:current_betting_round&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_new_betting_round&lt;/span&gt;
        &lt;span class="n"&gt;current_betting_round&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BettingRound&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;def&lt;/span&gt; &lt;span class="nf"&gt;start_new_hand&lt;/span&gt;
        &lt;span class="n"&gt;create_new_betting_round&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the constructor signature changes for &lt;code&gt;BettingRound&lt;/code&gt;, now &lt;code&gt;Game&lt;/code&gt; only needs to make a change in one place. Or if we change out to a different object from &lt;code&gt;BettingRound&lt;/code&gt; entirely, we only need to change it once. When an instance of &lt;code&gt;Game&lt;/code&gt; wants a betting round, it just asks itself to &lt;code&gt;create_new_betting_round&lt;/code&gt;, and we hand wave the details of precisely how that gets done. &lt;/p&gt;

&lt;h2&gt;
  
  
  If an object must send messages to any object other than &lt;code&gt;self&lt;/code&gt;, isolate sending that message in one single method
&lt;/h2&gt;

&lt;p&gt;As an extension of the previous point, &lt;em&gt;any time&lt;/em&gt; an object sends a message to another object, other than &lt;code&gt;self&lt;/code&gt;, consider wrapping that behind a method.&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;# Bad&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:current_betting_round&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_new_betting_round&lt;/span&gt;
        &lt;span class="n"&gt;current_betting_round&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BettingRound&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;def&lt;/span&gt; &lt;span class="nf"&gt;start_new_hand&lt;/span&gt;
        &lt;span class="n"&gt;create_new_betting_round&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;pot_odds&lt;/span&gt;
        &lt;span class="n"&gt;current_betting_round&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pot&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;current_betting_round&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;high_bet&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;# Good&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:current_betting_round&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_new_betting_round&lt;/span&gt;
        &lt;span class="n"&gt;current_betting_round&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;BettingRound&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;def&lt;/span&gt; &lt;span class="nf"&gt;pot&lt;/span&gt;
        &lt;span class="n"&gt;current_betting_round&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pot&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;high_bet&lt;/span&gt;
        &lt;span class="n"&gt;current_betting_round&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;high_bet&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;start_new_hand&lt;/span&gt;
        &lt;span class="n"&gt;create_new_betting_round&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;pot_odds&lt;/span&gt;
        &lt;span class="n"&gt;pot&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;high_bet&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;Here, we turn &lt;code&gt;pot&lt;/code&gt; and &lt;code&gt;high_bet&lt;/code&gt; into messages to which &lt;code&gt;Game&lt;/code&gt; will respond, even though they represent messages sent to the &lt;code&gt;current_betting_round&lt;/code&gt;. &lt;code&gt;Game&lt;/code&gt; can still collaborate with &lt;code&gt;BettingRound&lt;/code&gt;, but those collaboration points are isolated, which protects us from dependency problems. &lt;/p&gt;

&lt;h2&gt;
  
  
  Obey the Law of Demeter
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Law_of_Demeter"&gt;Law of Demeter&lt;/a&gt; instructs us that objects should really only talk to themselves, or, in limited capacity, to their direct collaborators. They should not send messages to objects that collaborate with their collaborating objects.&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;# Bad &lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt; 
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:players&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
        &lt;span class="vi"&gt;@players&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;players&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;player_ranks&lt;/span&gt;
        &lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;performance_history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rank&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;class&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; 
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:performance_history&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_history&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
        &lt;span class="vi"&gt;@performance_history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;performance_history&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;class&lt;/span&gt; &lt;span class="nc"&gt;PerformanceHistory&lt;/span&gt; 
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rank&lt;/span&gt; 
        &lt;span class="c1"&gt;# Maybe some database queries for determining rank&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;# Good&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt; 
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:players&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
        &lt;span class="vi"&gt;@players&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;players&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;player_ranks&lt;/span&gt;
        &lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rank&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;class&lt;/span&gt; &lt;span class="nc"&gt;Player&lt;/span&gt; 
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:performance_history&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;performance_history&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
        &lt;span class="vi"&gt;@performance_history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;performance_history&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;rank&lt;/span&gt;
        &lt;span class="n"&gt;performance_history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;rank&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;class&lt;/span&gt; &lt;span class="nc"&gt;PerformanceHistory&lt;/span&gt; 
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;rank&lt;/span&gt; 
        &lt;span class="c1"&gt;# Maybe some database queries for determining rank&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;Here, in the bad example, the &lt;code&gt;Game&lt;/code&gt; object violates the Law of Demeter by reaching beyond its direct collaborator, an instance of &lt;code&gt;Player&lt;/code&gt;, and asking the player's &lt;code&gt;PerformanceHistory&lt;/code&gt; to provide some ranking. &lt;/p&gt;

&lt;p&gt;By allowing &lt;code&gt;Player&lt;/code&gt; to respond to the request for &lt;code&gt;rank&lt;/code&gt;, if we ever change the implementation of those rankings, we only have to change it in &lt;code&gt;PerformanceHistory&lt;/code&gt;, and adapt to it in &lt;code&gt;Player&lt;/code&gt; (notice the message to &lt;em&gt;its&lt;/em&gt; collaborator is isolated in a method). &lt;code&gt;Game&lt;/code&gt; never needs to know the change has happened. &lt;/p&gt;

&lt;h2&gt;
  
  
  Use the &lt;code&gt;private&lt;/code&gt; keyword to create intentionally designed public interfaces
&lt;/h2&gt;

&lt;p&gt;One of the easiest things you can do to improve your overall design is communicate your public interfaces clearly. Ruby provides the &lt;code&gt;private&lt;/code&gt; keyword to aid you in this pursuit. Any methods defined after &lt;code&gt;private&lt;/code&gt; can only be called by an instance of that class. This simple delineation in your class definition tells other developers (including yourself-from-the-future) that the following methods are internal only, and should not be used or depended upon elsewhere in the codebase.&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;# Bad&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dealer&lt;/span&gt;
    &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:deck&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
        &lt;span class="c1"&gt;# Assume we set the deck to some full set of playing cards&lt;/span&gt;
        &lt;span class="n"&gt;deck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;card1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;card52&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;def&lt;/span&gt; &lt;span class="nf"&gt;next_card&lt;/span&gt;
        &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&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;shuffle_deck&lt;/span&gt;
        &lt;span class="c1"&gt;# Shuffle deck with Fisher-Yates&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="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;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tempi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;tempj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempj&lt;/span&gt;
            &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempi&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;# Good&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dealer&lt;/span&gt;
    &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:deck&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;
        &lt;span class="c1"&gt;# Assume we set the deck to some full set of playing cards&lt;/span&gt;
        &lt;span class="n"&gt;deck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;card1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;card52&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;def&lt;/span&gt; &lt;span class="nf"&gt;next_card&lt;/span&gt;
        &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pop&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;shuffle_deck&lt;/span&gt;
        &lt;span class="c1"&gt;# Shuffle deck with Fisher-Yates&lt;/span&gt;
        &lt;span class="c1"&gt;# https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="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;i&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;rand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tempi&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;tempj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempj&lt;/span&gt;
            &lt;span class="n"&gt;deck&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempi&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;Here, the &lt;code&gt;Dealer&lt;/code&gt; object is responsible for maintaining the deck, shuffling the deck, and providing the &lt;code&gt;next_card&lt;/code&gt;. However, we don't want to allow other objects to instruct a &lt;code&gt;Dealer&lt;/code&gt; to shuffle the deck. The &lt;code&gt;Dealer&lt;/code&gt; should be fully in charge of when it shuffles the deck. By defining &lt;code&gt;shuffle_deck&lt;/code&gt; after &lt;code&gt;private&lt;/code&gt;, we make this intention clear, and we set up some language-level restrictions on which objects can send the &lt;code&gt;shuffle_deck&lt;/code&gt; method to a &lt;code&gt;Dealer&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Moreover, we communicate to other developers not to rely on the logic in &lt;code&gt;shuffle_deck&lt;/code&gt; elsewhere. Today we shuffle using Fisher-Yates. Tomorrow we may choose some new method of doing so. Regardless of those implementation details, a &lt;code&gt;Dealer&lt;/code&gt;'s public interface should always respond to &lt;code&gt;next_card&lt;/code&gt;. That's much less likely to change, and other developers can rest easy asking &lt;code&gt;Dealer&lt;/code&gt; objects for the &lt;code&gt;next_card&lt;/code&gt; long into the future. &lt;/p&gt;

&lt;h2&gt;
  
  
  Use dependency injection by passing collaborating objects as arguments to methods
&lt;/h2&gt;

&lt;p&gt;The term "dependency injection" is a loaded one. I'll be honest - I've avoided reading about it whenever it comes up. Sandi Metz makes the concept approachable. I hope to do the same. Here's what dependency injection means to me. &lt;/p&gt;

&lt;p&gt;If a &lt;code&gt;Game&lt;/code&gt; object needs to collaborate with a &lt;code&gt;Dealer&lt;/code&gt; object, the &lt;code&gt;Game&lt;/code&gt; object shouldn't directly instantiate the &lt;code&gt;Dealer&lt;/code&gt;. Rather, we should pass some object to the &lt;code&gt;Game&lt;/code&gt; object that &lt;em&gt;represents&lt;/em&gt; the &lt;code&gt;Dealer&lt;/code&gt; object.&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;# Bad&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;
    &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:dealer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:players&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_dealer&lt;/span&gt;
        &lt;span class="vi"&gt;@dealer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Dealer&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;def&lt;/span&gt; &lt;span class="nf"&gt;deal_hole_cards&lt;/span&gt;
        &lt;span class="n"&gt;create_dealer&lt;/span&gt;
        &lt;span class="n"&gt;players&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;p&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;first_card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next_card&lt;/span&gt;
            &lt;span class="n"&gt;second_card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next_card&lt;/span&gt;
            &lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;hole_cards: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;first_card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second_card&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="c1"&gt;# Good&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deal_hole_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dealer&lt;/span&gt;&lt;span class="p"&gt;:,&lt;/span&gt; &lt;span class="n"&gt;players&lt;/span&gt;&lt;span class="p"&gt;:)&lt;/span&gt;
        &lt;span class="n"&gt;players&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;p&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;first_card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next_card&lt;/span&gt;
            &lt;span class="n"&gt;second_card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next_card&lt;/span&gt;
            &lt;span class="nb"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;hole_cards: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;first_card&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;second_card&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the bad example, we follow an earlier directive by wrapping an object instantiation inside a method. That's good. But then we set that instance as an instance variable, and access it directly from the &lt;code&gt;deal_hole_cards&lt;/code&gt; method. However, this approach leaves us with a dependency. &lt;code&gt;Game&lt;/code&gt; needs to know about the &lt;code&gt;dealer&lt;/code&gt; object it stored in the instance variable. It also needs to know about the &lt;code&gt;players&lt;/code&gt; it stores as an instance variable&lt;/p&gt;

&lt;p&gt;In the good example, we design &lt;code&gt;Game&lt;/code&gt; to expect some &lt;code&gt;dealer&lt;/code&gt; and &lt;code&gt;players&lt;/code&gt; arguments to its &lt;code&gt;deal_hole_cards&lt;/code&gt; method. Now we can call that method and provide any objects that respond to &lt;code&gt;next_card&lt;/code&gt; (for the dealer argument) and &lt;code&gt;update!&lt;/code&gt; (for the players). It provides us with flexibility, and we &lt;em&gt;inject&lt;/em&gt; those object dependencies into the &lt;code&gt;Game&lt;/code&gt; class. &lt;/p&gt;

&lt;h2&gt;
  
  
  Use duck typing when you see: case statements that switch on &lt;code&gt;class&lt;/code&gt;, or methods that ask &lt;code&gt;is_a?&lt;/code&gt; or &lt;code&gt;kind_of?&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Duck typing is useful for designing different classes that respond to the same message in order to treat them similarly. "Duck" comes from the saying "if it looks like a duck, walks like a duck, and quacks like a duck", with the implication being "it's a duck". &lt;/p&gt;

&lt;p&gt;Sometimes you want similar classes to respond to a message slightly differently based on what they are. Say you have a &lt;code&gt;TexasHoldEm&lt;/code&gt; class, which deals two cards to each player for their hole cards, and a &lt;code&gt;FiveCardDraw&lt;/code&gt; class, which deals five cards. Here are two ways you could implement that:&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;# Bad&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Table&lt;/span&gt; 
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:game&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;begin_hand&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kind_of?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;TexasHoldEm&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deal_two_hole_cards&lt;/span&gt;
        &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kind_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;FiveCardDraw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deal_five_hole_cards&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;# Good&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Table&lt;/span&gt; 
    &lt;span class="nb"&gt;attr_accessor&lt;/span&gt; &lt;span class="ss"&gt;:game&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;begin_hand&lt;/span&gt;
        &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deal_hole_cards&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;Here we replaced two different, but similar, methods with one duck type. In the bad example, we ask the &lt;code&gt;game&lt;/code&gt; object to &lt;code&gt;deal_two_hole_cards&lt;/code&gt; if it's a &lt;code&gt;TexasHoldEm&lt;/code&gt; object, or to &lt;code&gt;deal_five_hole_cards&lt;/code&gt; if it's a &lt;code&gt;FiveCardDraw&lt;/code&gt; object. We can make that cleaner by defining one method on each class, with the same name: &lt;code&gt;deal_hole_cards&lt;/code&gt;, and deal the appropriate number of cards in each class-specific implementation. &lt;/p&gt;

&lt;h2&gt;
  
  
  Use inheritance when you are conditionally sending messages to &lt;code&gt;self&lt;/code&gt; based on some attribute of &lt;code&gt;self&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Duck typing is good way to improve your design when you already have multiple objects that respond to similar messages. But sometimes you end up with a class that could benefit from inheritance. One sign your design might be in need of inheritance is when messages are being conditionally sent based on some internal attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Bad&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt; 
    &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:dealer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:game_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:players&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deal_hole_cards&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;game_type&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;'texas_hold_em'&lt;/span&gt;
            &lt;span class="n"&gt;number_of_cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;
        &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;game_type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'five_card_draw'&lt;/span&gt;
            &lt;span class="n"&gt;number_of_cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
        &lt;span class="k"&gt;end&lt;/span&gt;
        &lt;span class="n"&gt;players&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;player&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deal_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;number_of_cards&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;hole_cards: &lt;/span&gt;&lt;span class="n"&gt;cards&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="c1"&gt;# Good &lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Game&lt;/span&gt; 
    &lt;span class="nb"&gt;attr_reader&lt;/span&gt; &lt;span class="ss"&gt;:dealer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:players&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TexasHoldEm&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Game&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deal_hole_cards&lt;/span&gt;
        &lt;span class="n"&gt;players&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;player&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deal_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;hole_cards: &lt;/span&gt;&lt;span class="n"&gt;cards&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;class&lt;/span&gt; &lt;span class="nc"&gt;FiveCardDraw&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Game&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;deal_hole_cards&lt;/span&gt;
        &lt;span class="n"&gt;players&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;player&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
            &lt;span class="n"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dealer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deal_cards&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;hole_cards: &lt;/span&gt;&lt;span class="n"&gt;cards&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we start with a &lt;code&gt;Game&lt;/code&gt; class that could benefit from some refactoring. It conditionally deals a different number of cards based on whether or not its &lt;code&gt;game_type&lt;/code&gt; is &lt;code&gt;texas_hold_em&lt;/code&gt; or &lt;code&gt;five_card_draw&lt;/code&gt;. By creating a &lt;code&gt;TexasHoldEm&lt;/code&gt; class and a &lt;code&gt;FiveCardDraw&lt;/code&gt; class, we can implement their respective &lt;code&gt;deal_hole_cards&lt;/code&gt; methods appropriately for each type of game, and track one less instance variable in the &lt;code&gt;Game&lt;/code&gt; superclass. &lt;/p&gt;

&lt;h2&gt;
  
  
  Promote code up to superclasses rather than down to subclasses
&lt;/h2&gt;

&lt;p&gt;In the previous example, I hand-waved the restructuring of the classes. If you're going through the process of creating inheritance in your project where there was none to begin, keep in mind it is much easier to identify shared functions from subclasses and move them up, rather than figure out what might be different for subclasses by looking at the parent class. &lt;/p&gt;

&lt;p&gt;All that to say, if you're creating inheritance, build out one new empty abstract class and move up what you need instead of adapting an existing class to be the superclass. &lt;/p&gt;

&lt;h2&gt;
  
  
  Every class should have a one sentence description, no conjunctions allowed
&lt;/h2&gt;

&lt;p&gt;The first of the &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID&lt;/a&gt; design principles is the &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle"&gt;single-responsibility principle&lt;/a&gt;. Volumes have been written about this principle alone. For these object-oriented heuristics, here's what you should ask yourself while reviewing your code: &lt;/p&gt;

&lt;p&gt;"Can I describe what this class does in one sentence, without using any conjunctions?"&lt;/p&gt;

&lt;p&gt;If the answer is no, your class could likely benefit from being split up into separate objects. It is probably responsible for too many things.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you rephrase your class methods as questions to the object, each question should make sense; it should be related to the purpose of the class
&lt;/h2&gt;

&lt;p&gt;Once you feel confident your class can be described with a single sentence, you can take the single-responsibility principle one step further by inspecting each method and rephrasing the method as a question to that class. Say it out loud and ask yourself: "does it make sense for me to ask this specific question of this specific object, given its purpose?" &lt;/p&gt;

&lt;p&gt;If the answer is no, you should consider moving this method to a different class. Or perhaps your class could still benefit from being separated into different objects. &lt;/p&gt;

&lt;h2&gt;
  
  
  Messages should ask for "what" instead of dictating "how"
&lt;/h2&gt;

&lt;p&gt;The prior exercise, rephrasing methods into questions, sets us up for this next item: methods should represent messages sent &lt;em&gt;to&lt;/em&gt; the object. The object should receive the method call, and then &lt;em&gt;answer the question&lt;/em&gt;. T&lt;/p&gt;

&lt;p&gt;In order for your object to determine the response, it should have freedom to do so however it likes. Method calls should not dictate the internal behavior of the object. They should work as interfaces for other objects to retrieve relevant information. Keep in mind the distinction between public and private methods. An object's public methods should represent a set of questions it will respond to. Its &lt;code&gt;private&lt;/code&gt; methods are an appropriate place to store implementation details, which are more likely to change than the kinds of questions the object will be asked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforce good dependency direction
&lt;/h2&gt;

&lt;p&gt;In earlier heuristics, we've looked at how to eliminate dependencies, or manage them responsibly. In any non-trivial software, it's impossible to eliminate &lt;em&gt;all&lt;/em&gt; dependencies. Objects must collaborate and rely on one another. When you identify these necessary dependencies (and put safe guards around them), you will need to decide which object depends on which. This is the &lt;em&gt;direction&lt;/em&gt; of your dependencies. &lt;/p&gt;

&lt;p&gt;Generally speaking, objects should not depend on other objects that are likely to change more than themselves. When you use a framework liek Rails, you can remain somewhat assured that framework APIs will change less frequently than your code. It's responsible for your models to inherit from &lt;a href="https://guides.rubyonrails.org/active_record_basics.html"&gt;ActiveRecord&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Evaluate your own objects and determine which seem most stable. Have other objects depend on them, and so forth. &lt;/p&gt;

&lt;h2&gt;
  
  
  Depend on abstractions before depending on concrete classes
&lt;/h2&gt;

&lt;p&gt;For a more practical application of good dependency direction, consider the difference between abstract classes and concrete classes. In &lt;code&gt;Game&lt;/code&gt; inheritance example, we had &lt;code&gt;TexasHoldEm&lt;/code&gt; and &lt;code&gt;FiveCardDraw&lt;/code&gt; depend on &lt;code&gt;Game&lt;/code&gt;, rather than one another. If you are having trouble identifying which classes are most stable and best to depend on, look for the superclasses in your inheritance hierarchy to guide you. &lt;/p&gt;

&lt;h2&gt;
  
  
  Default to composition over inheritance
&lt;/h2&gt;

&lt;p&gt;Duck typing and other methods of composition are easier to maintain and reason about than inheritance. When you are refactoring your code and splitting up objects into smaller pieces, you should strive to create small, composable objects, rather than an overly-nested inheritance tree. &lt;/p&gt;

&lt;h2&gt;
  
  
  Create shallow hierarchies
&lt;/h2&gt;

&lt;p&gt;When you &lt;em&gt;do&lt;/em&gt; find that inheritance is the right choice for your design, do your best to keep your inheritance hierarchy shallow. As a general guideline, it's good to stop at one or two levels of inheritance. Any deeper should be an indication to you that you may have missed some opportunity for composition somewhere along the line. &lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks
&lt;/h2&gt;

&lt;p&gt;Thanks for reading! I hope my heuristics are useful to you. I find that by rigorously applying them during code review, I've developed a better sensibility around object oriented design. And a special thanks to Sandi Metz, for all her thought leadership and pioneering in object oriented design and Ruby programming.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>codequality</category>
      <category>books</category>
      <category>objectoriented</category>
    </item>
    <item>
      <title>A Nifty Use Case for Rails Virtual Attributes</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Mon, 17 Aug 2020 19:26:50 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/a-nifty-use-case-for-rails-virtual-attributes-5eba</link>
      <guid>https://dev.to/ogdenstudios/a-nifty-use-case-for-rails-virtual-attributes-5eba</guid>
      <description>&lt;p&gt;I work on a Rails project uses models to represent some front end components, which gives us access to clever tricks, including using &lt;a href="http://railscasts.com/episodes/16-virtual-attributes-revised"&gt;virtual attributes&lt;/a&gt; for custom styling. &lt;/p&gt;

&lt;h2&gt;
  
  
  The base component class
&lt;/h2&gt;

&lt;p&gt;All of these components inherit from a &lt;code&gt;Component&lt;/code&gt; model that 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;Component&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="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;css_class_list&lt;/span&gt;
    &lt;span class="n"&gt;class_string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&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;class&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&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;style_list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;class_string&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&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;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;style&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;class_string&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;The &lt;code&gt;css_class_list&lt;/code&gt; method spits out a class list for use in our ERB templates, like so:&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;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="cp"&gt;&amp;lt;%=&lt;/span&gt; &lt;span class="n"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;css_class_list&lt;/span&gt; &lt;span class="cp"&gt;%&amp;gt;&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we want to build out some &lt;code&gt;EventComponent&lt;/code&gt; that inherits from the &lt;code&gt;Component&lt;/code&gt; class, its rendered template would come out like this:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Customize the event component styles
&lt;/h2&gt;

&lt;p&gt;Let's say we want to add some different flavors to the &lt;code&gt;EventComponent&lt;/code&gt;. We can add additional CSS classes using the &lt;code&gt;style_list&lt;/code&gt; method:&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;EventComponent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Component&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:page&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;style_list&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="ss"&gt;:description_enabled&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;The parent class, &lt;code&gt;Component&lt;/code&gt;, grabs &lt;code&gt;style_list&lt;/code&gt; and sends each symbol to the instance of the &lt;code&gt;EventComponent&lt;/code&gt;. If it returns true, it adds the symbol to the final class list. &lt;/p&gt;

&lt;p&gt;In this case, if we have an &lt;code&gt;EventComponent&lt;/code&gt; with &lt;code&gt;description_enabled&lt;/code&gt;, the rendered template would be:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Generate CSS classes with virtual attributes
&lt;/h2&gt;

&lt;p&gt;This works well for model attributes that are boolean values, but what if we want to style based on a non-boolean attribute? This is where virtual attributes really shine. &lt;/p&gt;

&lt;p&gt;Here's a version of &lt;code&gt;EventComponent&lt;/code&gt; that we can style based on the number of attendees:&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;EventComponent&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;Component&lt;/span&gt;
  &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:page&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;over_capacity&lt;/span&gt; &lt;span class="c1"&gt;# This is the virtual attribute&lt;/span&gt;
    &lt;span class="n"&gt;rsvp_count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1000&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;style_list&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="ss"&gt;:description_enabled&lt;/span&gt;
      &lt;span class="ss"&gt;:over_capacity&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;Now if we render out an &lt;code&gt;EventComponent&lt;/code&gt; with more than 1000 RSVPs, the output will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"EventComponent description_enabled over_capacity"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we can go on to target &lt;code&gt;.EventComponent&lt;/code&gt;, &lt;code&gt;.description_enabled&lt;/code&gt;, and &lt;code&gt;.over_capacity&lt;/code&gt; with our CSS! &lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>html</category>
      <category>css</category>
    </item>
    <item>
      <title>Clients, Servers, and the Single Responsibility Principle</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Sat, 15 Aug 2020 21:31:29 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/clients-servers-and-the-single-responsibility-principle-561e</link>
      <guid>https://dev.to/ogdenstudios/clients-servers-and-the-single-responsibility-principle-561e</guid>
      <description>&lt;p&gt;I'm working on a poker application and just found a nice refactor that taught me a little bit about the &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle"&gt;single responsibility principle&lt;/a&gt; in practice. &lt;/p&gt;

&lt;h2&gt;
  
  
  Modelling the desired behavior
&lt;/h2&gt;

&lt;p&gt;Say you're playing a game of poker. The flop has just been dealt and it's your action. In this position, you can fold, check, or bet. Let's focus on betting. &lt;/p&gt;

&lt;p&gt;If you've got 300 chips and bet 100, the action moves to the next player and they have to fold, call 100, or raise. If everyone calls your bet of 100, the turn will be dealt, and your action comes around again. Now you can fold, check, or bet (up to 200). &lt;/p&gt;

&lt;p&gt;But if you had originally bet 300 chips after the flop, everyone called, and it became your turn again, you would be skipped over. A player who is all in has no action to take - they just wait until the hand wraps up and the showdown happens. &lt;/p&gt;

&lt;p&gt;Since an &lt;code&gt;all_in&lt;/code&gt; player has a restricted set of actions, we want to set up some indicators to represent when players go all in. &lt;/p&gt;

&lt;h2&gt;
  
  
  The &lt;code&gt;bet&lt;/code&gt; function
&lt;/h2&gt;

&lt;p&gt;Consider a &lt;code&gt;bet&lt;/code&gt; method that looks something 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;def&lt;/span&gt; &lt;span class="nf"&gt;bet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrement!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;move_to_next_player&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 is a simple version of what a bet function might need to accomplish. If a players has 300 chips and calls &lt;code&gt;bet(100)&lt;/code&gt;, everything works out great. &lt;/p&gt;

&lt;p&gt;But what if they call &lt;code&gt;bet(300)&lt;/code&gt;? We have to mark them &lt;code&gt;all_in&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;So maybe we do something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;all_in: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chips&lt;/span&gt; 
  &lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrement!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;move_to_next_player&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 might work if going all in only happened on bets. But it can also happen when calling or raising. There are also a few other pieces of data we want to track, like which betting round a player went all in on, and how much they went all in with. So we can abstract it out to something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;go_all_in&lt;/span&gt;
  &lt;span class="vi"&gt;@game&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;increment!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chips&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;all_in: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;all_in_round: &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;all_in_amount: &lt;/span&gt;&lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chips&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;chips: &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;move_to_next_player&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now our &lt;code&gt;bet&lt;/code&gt; function could look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;bet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chips&lt;/span&gt; 
    &lt;span class="n"&gt;go_all_in&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="vi"&gt;@player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;chips&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decrement!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;move_to_next_player&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;
  
  
  The front end code
&lt;/h2&gt;

&lt;p&gt;The game client is built with React. The betting button looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt; &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;updateBetValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="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="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Bet &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;betValue&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's an input that changes the value of the bet, and a button that fires off a betting action to the server through the &lt;code&gt;handleClick&lt;/code&gt; function. &lt;/p&gt;

&lt;h2&gt;
  
  
  When handleClick does too much
&lt;/h2&gt;

&lt;p&gt;Here's where I went wrong. Initially, I duplicated my server-side logic that checked for an all in bet in the front end as well. It looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;betValue&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;player&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;chips&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;goAllIn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Fires off a websocket action to run the `go_all_in` ruby function &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="nx"&gt;bet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;betValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Fires off a websocket action to run the `bet` ruby function. &lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It works, and when I first made this choice, I decided it was a &lt;em&gt;good&lt;/em&gt; idea to have duplication of the chip check. I figured it couldn't hurt to have additional checks around it. But I ran into two problems that the single responsibility principle would have warned me of: &lt;/p&gt;

&lt;h3&gt;
  
  
  One change, two files
&lt;/h3&gt;

&lt;p&gt;Checking for chip equality isn't enough. It's possible that a user might try to be &lt;em&gt;more&lt;/em&gt; chips than they have, not just the actual number. To catch this, I had to update the &lt;code&gt;amount == @player.chips&lt;/code&gt; check to &lt;code&gt;amount &amp;gt;= @player.chips&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I forgot to update the JS equivalent, and unit tests began to fail. &lt;/p&gt;

&lt;h3&gt;
  
  
  Confusing signals
&lt;/h3&gt;

&lt;p&gt;When a player clicks the &lt;code&gt;BetButton&lt;/code&gt;, they're indicating to the server "I would like to make a bet, here is the amount I'd like to bet". &lt;/p&gt;

&lt;p&gt;Even if their desired bet amount is invalid, it's important to see what users are trying to do, because it keeps fidelity of information when I'm debugging. &lt;/p&gt;

&lt;p&gt;With logic checks in the front end, if the user attempts to submit an invalid bet amount to the server, their message to the server gets intercepted and changed to a &lt;code&gt;goAllIn()&lt;/code&gt; call. I lose the full set of information and it makes tracking bugs harder. &lt;/p&gt;

&lt;h2&gt;
  
  
  A pretty quick fix
&lt;/h2&gt;

&lt;p&gt;The fix on this one was pretty quick. I refactored &lt;code&gt;handleClick()&lt;/code&gt; to something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleClick&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;bet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;betValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It cleaned up my &lt;code&gt;BetButton&lt;/code&gt; component and helped me track user activity with ease. I also know now that when I get bugs related to invalid bets, I can get the full information about what React was sending to the server, and if I need to adjust my logic around when a &lt;code&gt;bet&lt;/code&gt; turns into a &lt;code&gt;go_all_in&lt;/code&gt; call, I know that it lives in the ruby &lt;code&gt;bet&lt;/code&gt; function and nowhere else. &lt;/p&gt;

&lt;p&gt;It was a fun lesson in clean code for me. A simple change made my code easier to reason about, debug, and maintain. &lt;/p&gt;

</description>
      <category>ruby</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Build a Rails Engine to Accept Stripe One-time Payments</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Wed, 13 May 2020 15:52:00 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/build-a-rails-engine-to-accept-stripe-one-time-payments-4j0b</link>
      <guid>https://dev.to/ogdenstudios/build-a-rails-engine-to-accept-stripe-one-time-payments-4j0b</guid>
      <description>&lt;p&gt;I maintain a handful of Ruby on Rails applications for my clients. Most of them need to handle payments. My go-to payment processor is &lt;a href="https://stripe.com/"&gt;Stripe&lt;/a&gt;. Stripe makes payments easy, but still requires some setup and configuration. I've written the same one-time payment feature about five times with slight variations, so I wanted to make it easier to repeat.&lt;/p&gt;

&lt;p&gt;This sort of abstraction is a good candidate for a &lt;a href="https://guides.rubyonrails.org/engines.html"&gt;Rails engine&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Engines are basically sub-applications that provide functionality to a host application. They're great if you have some set of features that could reasonably be separated into their own application, but require a high amount of interoperability with your main application. (Thanks to &lt;a href="https://codefol.io/"&gt;Noah Gibbs&lt;/a&gt; for the phrasing on that one).&lt;/p&gt;

&lt;p&gt;I wrote a proof-of-concept engine that: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Takes custom payment amounts&lt;/li&gt;
&lt;li&gt;Takes credit cards from customers&lt;/li&gt;
&lt;li&gt;Creates charges using Stripe&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With that engine in hand, I can include it in any future project, provide the Stripe credentials, and save quite a bit of time. &lt;/p&gt;

&lt;p&gt;Here's how you can do something similar.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generate the engine
&lt;/h2&gt;

&lt;p&gt;In the command line, run the &lt;a href="https://guides.rubyonrails.org/engines.html#generating-an-engine"&gt;rails plugin generator&lt;/a&gt; with the &lt;code&gt;--mountable&lt;/code&gt; flag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rails plugin new payments &lt;span class="nt"&gt;--mountable&lt;/span&gt; 
&lt;span class="nb"&gt;cd &lt;/span&gt;payments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Update the gemspec
&lt;/h2&gt;

&lt;p&gt;The engine gemspec will have some &lt;code&gt;TODO&lt;/code&gt; items in &lt;code&gt;payments.gemspec&lt;/code&gt;. Fill them 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="c1"&gt;# payments.gemspec&lt;/span&gt;
&lt;span class="c1"&gt;# . . . other config here&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;homepage&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://ogdenstudios.xyz"&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;summary&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Adds Stripe one-time payment capability"&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Adds Stripe one-time payment capability"&lt;/span&gt;
&lt;span class="c1"&gt;# . . . the rest of the gemspec &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run &lt;code&gt;bundle&lt;/code&gt;. Once the installation is complete, check the engine is running by running &lt;code&gt;rails s&lt;/code&gt; in the console and visiting &lt;code&gt;localhost:3000&lt;/code&gt;. The standard Rails welcome page should appear. &lt;/p&gt;

&lt;h2&gt;
  
  
  Add the Stripe gem
&lt;/h2&gt;

&lt;p&gt;Adding gems to a Rails engine is a little different than adding them to a Rails app. We have to use the &lt;code&gt;gemspec&lt;/code&gt; instead of a &lt;code&gt;Gemfile&lt;/code&gt;. To add the &lt;a href="https://github.com/stripe/stripe-ruby"&gt;Stripe gem&lt;/a&gt; to the engine, update &lt;code&gt;payments.gemspec&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# payments.gemspec &lt;/span&gt;
&lt;span class="c1"&gt;# . . . other configuration here&lt;/span&gt;
  &lt;span class="n"&gt;spec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_dependency&lt;/span&gt; &lt;span class="s2"&gt;"stripe"&lt;/span&gt;
&lt;span class="c1"&gt;# . . . the rest of the gemspec&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then &lt;code&gt;bundle&lt;/code&gt; again. &lt;/p&gt;

&lt;h2&gt;
  
  
  Create the payment_intents controller
&lt;/h2&gt;

&lt;p&gt;Stripe uses &lt;a href="https://stripe.com/docs/api/payment_intents"&gt;PaymentIntents&lt;/a&gt; to process payments. The idea is to take some information from the customer, combine it with your credentials, and pass back an object that represents an intent to make a payment. Then we submit that intention to Stripe. Stripe verifies all the information is correctly formatted, and handles the final processing. &lt;/p&gt;

&lt;p&gt;Let's make a &lt;code&gt;PaymentIntentsController&lt;/code&gt;. This controller will only have one method for now, the &lt;code&gt;create&lt;/code&gt; method. We'll use it to create a PaymentIntent and return it as a JSON response to our engine's view, which will then pass that PaymentIntent to Stripe for processing.&lt;/p&gt;

&lt;p&gt;Create a file at &lt;code&gt;app/controllers/payments/payment_intents_controller.rb&lt;/code&gt;. Inside:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/controllers/payments/payment_intents_controller.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'Stripe'&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Payments&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PaymentIntentsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
        &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create&lt;/span&gt; 
            &lt;span class="no"&gt;Stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;api_key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;secret&lt;/span&gt;
            &lt;span class="vi"&gt;@intent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Stripe&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;PaymentIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                &lt;span class="ss"&gt;amount: &lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:amount&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="ss"&gt;currency: &lt;/span&gt;&lt;span class="s1"&gt;'usd'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
            &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="vi"&gt;@intent&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;This method configures the &lt;code&gt;Stripe&lt;/code&gt; object, available through the Stripe gem, with the secret key. It creates a PaymentIntent from the supplied &lt;code&gt;params&lt;/code&gt; hash and returns the intent as a JSON response. &lt;/p&gt;

&lt;h2&gt;
  
  
  Add the PaymentIntent create route
&lt;/h2&gt;

&lt;p&gt;We have to provide access to the controller method through our routing. In &lt;code&gt;config/routes.rb&lt;/code&gt;, add the &lt;code&gt;create&lt;/code&gt; route for &lt;code&gt;payment_intents&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="c1"&gt;# config/routes.rb&lt;/span&gt;
&lt;span class="no"&gt;Payments&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:payment_intents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add a checkout controller
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;PaymentIntentsController&lt;/code&gt; only handles creating the PaymentIntent. We also need a view for users to interact with the engine and make payments. We can call that a &lt;code&gt;Checkout&lt;/code&gt;, and manage it through a &lt;code&gt;CheckoutsController&lt;/code&gt;. Create a file at &lt;code&gt;app/controllers/payments/checkouts_controller.rb&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/controllers/payments/checkouts_controller.rb&lt;/span&gt;
&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Payments&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CheckoutsController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationController&lt;/span&gt;
        &lt;span class="k"&gt;def&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;This controller is only responsible for rendering the view that creates a new checkout, so we only need the &lt;code&gt;new&lt;/code&gt; method. &lt;/p&gt;

&lt;h2&gt;
  
  
  Route to the checkouts controller
&lt;/h2&gt;

&lt;p&gt;Update &lt;code&gt;config/routes.rb&lt;/code&gt; so it 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="c1"&gt;#config/routes.rb&lt;/span&gt;
&lt;span class="no"&gt;Payments&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:checkouts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:new&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;resources&lt;/span&gt; &lt;span class="ss"&gt;:payment_intents&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;only: &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:create&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Create a view for new checkout
&lt;/h2&gt;

&lt;p&gt;This is where users will make payments. Create a file at &lt;code&gt;app/views/payments/checkouts/new.html.erb&lt;/code&gt; and use the boilerplate form provided through the &lt;a href="https://stripe.com/docs/payments/accept-a-payment"&gt;Stripe docs&lt;/a&gt;. Stripe assumes you have hard-coded prices for your one-time payments. This engine allows users to provide a custom amount, so we add the &lt;code&gt;amount&lt;/code&gt; input, which we'll use to create the PaymentIntent. It also has a custom &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/pattern"&gt;pattern&lt;/a&gt; to format the input and require only numbers (with up to two decimal places).&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="c"&gt;&amp;lt;!-- app/views/payments/checkouts/new.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"payment-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"amount"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Amount (USD)&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
        &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"amount"&lt;/span&gt;
        &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"tel"&lt;/span&gt;
        &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"100.00"&lt;/span&gt;
        &lt;span class="na"&gt;required=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;
        &lt;span class="na"&gt;autocomplete=&lt;/span&gt;&lt;span class="s"&gt;"tel"&lt;/span&gt;
        &lt;span class="na"&gt;pattern=&lt;/span&gt;&lt;span class="s"&gt;"(?=.*?\d)^\$?(([1-9]\d{0,2}(\d{3})*)|\d+)?(\.\d{1,2})?$"&lt;/span&gt;
    &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"card-element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="c"&gt;&amp;lt;!-- Elements will create input elements here --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="c"&gt;&amp;lt;!-- We'll put the error messages in this element --&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"card-errors"&lt;/span&gt; &lt;span class="na"&gt;role=&lt;/span&gt;&lt;span class="s"&gt;"alert"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Pay&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add Stripe Elements to the application layout
&lt;/h2&gt;

&lt;p&gt;In order for Stripe to work on the client side, we need to include &lt;a href="https://stripe.com/docs/stripe-js"&gt;Stripe Elements&lt;/a&gt; in the view. We can set that up in &lt;code&gt;app/views/layouts/payments/application.html.erb&lt;/code&gt;&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="c"&gt;&amp;lt;!-- app/views/layouts/payments.application.html.erb --&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Payments&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;csrf_meta_tags&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;csp_meta_tag&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;stylesheet_link_tag&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;payments&lt;/span&gt;&lt;span class="err"&gt;/&lt;/span&gt;&lt;span class="na"&gt;application&lt;/span&gt;&lt;span class="err"&gt;",&lt;/span&gt; &lt;span class="na"&gt;media:&lt;/span&gt; &lt;span class="err"&gt;"&lt;/span&gt;&lt;span class="na"&gt;all&lt;/span&gt;&lt;span class="err"&gt;"&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://js.stripe.com/v3/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"stripePublishableKey"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;%= Rails.configuration.x.stripe.publishableKey %&amp;gt;"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="err"&gt;%=&lt;/span&gt; &lt;span class="na"&gt;yield&lt;/span&gt; &lt;span class="err"&gt;%&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also add a &lt;code&gt;meta&lt;/code&gt; tag to embed the Stripe publishable key. We'll use that in our client-side JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  The client-side JavaScript
&lt;/h2&gt;

&lt;p&gt;We'll add a &lt;code&gt;script&lt;/code&gt; tag at the bottom of &lt;code&gt;app/views/payments/checkouts/new.html.erb&lt;/code&gt;. The script will provide a basic user story for the checkout: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Get the publishable key from the &lt;code&gt;meta&lt;/code&gt; tag &lt;/li&gt;
&lt;li&gt;Get the &lt;a href="https://guides.rubyonrails.org/security.html#csrf-countermeasures"&gt;CSRF token&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Initialize Stripe Elements&lt;/li&gt;
&lt;li&gt;Mount Stripe Elements to the &lt;code&gt;card&lt;/code&gt; element&lt;/li&gt;
&lt;li&gt;Set up error checking on the &lt;code&gt;card-element&lt;/code&gt; to provide feedback if users don't provide well formatted card information&lt;/li&gt;
&lt;li&gt;Set up an event listener for the form &lt;code&gt;submit&lt;/code&gt; event &lt;/li&gt;
&lt;li&gt;Tell the &lt;code&gt;submit&lt;/code&gt; handler to POST to the &lt;code&gt;/payments/payment_intents&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Receive the &lt;code&gt;PaymentIntent&lt;/code&gt; from the &lt;code&gt;PaymentIntentsController&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Submit the &lt;code&gt;PaymentIntent&lt;/code&gt; to Stripe &lt;/li&gt;
&lt;li&gt;Alert the user based on errors or successes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After the closing &lt;code&gt;form&lt;/code&gt; tag, add:&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;script&amp;gt;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;publishableKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stripePublishableKey&lt;/span&gt;&lt;span class="dl"&gt;'&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="nx"&gt;content&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;csrftoken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementsByName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;csrf-token&lt;/span&gt;&lt;span class="dl"&gt;"&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="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Stripe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;publishableKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;base&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#32325d&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;card&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#card-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-element&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="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="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;displayError&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;card-errors&lt;/span&gt;&lt;span class="dl"&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="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&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;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="nx"&gt;displayError&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&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="p"&gt;});&lt;/span&gt;

  &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;payment-form&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="c1"&gt;// Get the data from the form&lt;/span&gt;
      &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;amount&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="c1"&gt;// Get the client secret&lt;/span&gt;
      &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/payments/payment_intents&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
              &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;X-CSRF-Token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;csrftoken&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&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="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;confirmPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;client_secret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="c1"&gt;// Confirm the payment&lt;/span&gt;
      &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;confirmPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;confirmCardPayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;clientSecret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="na"&gt;payment_method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="na"&gt;card&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;card&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="c1"&gt;// Show error to your customer (e.g., insufficient funds)&lt;/span&gt;
                  &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;message&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="c1"&gt;// The payment has been processed!&lt;/span&gt;
                  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;paymentIntent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;succeeded&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="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Succeeded!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                      &lt;span class="c1"&gt;// Show a success message to your customer&lt;/span&gt;
                      &lt;span class="c1"&gt;// There's a risk of the customer closing the window before callback&lt;/span&gt;
                      &lt;span class="c1"&gt;// execution. Set up a webhook or plugin to listen for the&lt;/span&gt;
                      &lt;span class="c1"&gt;// payment_intent.succeeded event that handles any business critical&lt;/span&gt;
                      &lt;span class="c1"&gt;// post-payment actions.&lt;/span&gt;
                  &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice when we set the &lt;code&gt;amount&lt;/code&gt;, we multiply it by 100:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;amount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;amount&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="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because Stripe handles amounts as integer values in cents. The input is formatted for dollars, so we multiply by 100 to get the correct amount of cents to pass to the &lt;code&gt;create&lt;/code&gt; method in &lt;code&gt;PaymentIntentsController&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out in a host application
&lt;/h2&gt;

&lt;p&gt;Make a new Rails application. In the console:&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;cd&lt;/span&gt; ..
rails new hostapp
&lt;span class="nb"&gt;cd &lt;/span&gt;hostapp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://guides.rubyonrails.org/engines.html#mounting-the-engine"&gt;Mount the engine&lt;/a&gt;. In &lt;code&gt;hostapp/Gemfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gem 'payments', path: 'full/path/to/payments'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;bundle&lt;/code&gt; in the command line to install everything. &lt;/p&gt;

&lt;h2&gt;
  
  
  Set up the engine routes
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;hostapp/config/routes.rb&lt;/code&gt;, add the routes:&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;# hostapp/config/routes.rb&lt;/span&gt;
&lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;draw&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="c1"&gt;# For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html&lt;/span&gt;
  &lt;span class="n"&gt;mount&lt;/span&gt; &lt;span class="no"&gt;Payments&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Engine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;at: &lt;/span&gt;&lt;span class="s2"&gt;"/payments"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Link the engine stylesheet
&lt;/h2&gt;

&lt;p&gt;The stylesheet from the engine needs to be linked to the hostapp for asset compilation. In &lt;code&gt;hostapp/app/assets/stylesheets/application.css&lt;/code&gt;, add &lt;code&gt;//= link payments/application.css&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The file should look like this entirely:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/*
 * This is a manifest file that'll be compiled into application.css, which will include all the files
 * listed below.
 *
 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
 * vendor/assets/stylesheets directory can be referenced here using a relative path.
 *
 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
 * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
 * files in this directory. Styles in this file should be added after the last require_* statement.
 * It is generally better to create a new file per style scope.
 *
 *= require_tree .
 *= require_self
 //= link payments/application.css
 */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Securely store your Stripe API keys
&lt;/h2&gt;

&lt;p&gt;Use &lt;a href="https://medium.com/cedarcode/rails-5-2-credentials-9b3324851336"&gt;Rails credentials&lt;/a&gt; to store your Stripe keys. For now, we can just the the test publishable key and the test secret key. &lt;/p&gt;

&lt;p&gt;In the command line:&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;EDITOR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"vim"&lt;/span&gt; rails credentials:edit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then edit the file to add the following YAML:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;stripe&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;test_publishable_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_key_here&lt;/span&gt;
    &lt;span class="na"&gt;test_secret_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;your_key_here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Add the test keys to the development environment
&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;hostapp/config/environments/development.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# `hostapp/config/environments/development.rb`&lt;/span&gt;
&lt;span class="c1"&gt;# . . . other configuration here&lt;/span&gt;
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;publishableKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:test_publishable_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
  &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;secret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Rails&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;application&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stripe&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:test_secret_key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Test it out
&lt;/h2&gt;

&lt;p&gt;From within the &lt;code&gt;hostapp&lt;/code&gt; directory: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Run &lt;code&gt;rails s&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Visit localhost:3000/payments/checkouts/new &lt;/li&gt;
&lt;li&gt;Input an amount, fill in a &lt;a href="https://stripe.com/docs/testing#cards"&gt;test card number&lt;/a&gt;, &lt;/li&gt;
&lt;li&gt;Submit the form and check your Stripe dashboard for the test charges.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Next steps
&lt;/h2&gt;

&lt;p&gt;This engine isn't quite ready for primetime. This is mostly a proof-of-concept that I plan to expand on for personal use. Here are some things I might do to make it a little more versatile: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create an installation rake task to handle the routing and asset linking with a command like &lt;code&gt;rails generate payments:install&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Create some generators to render the views and controllers for further configuration, like &lt;a href="https://github.com/heartcombo/devise#configuring-views"&gt;Devise does&lt;/a&gt;. &lt;/li&gt;
&lt;li&gt;Handle the client-side JavaScript more gracefully. I don't love writing it inline, but I had trouble including the JavaScript correctly through the generator. I need to learn how to do that, or consider packaging it up separately to drop in as a separate JS dependency. &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ruby</category>
      <category>rails</category>
      <category>stripe</category>
      <category>ecommerce</category>
    </item>
    <item>
      <title>A Use Case for CSS Parent Selectors</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Fri, 10 Apr 2020 15:58:42 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/a-use-case-for-css-parent-selectors-47p1</link>
      <guid>https://dev.to/ogdenstudios/a-use-case-for-css-parent-selectors-47p1</guid>
      <description>&lt;p&gt;At some point, Chris Coyier suggested people write blog posts presenting why they might need parent selectors. Here's mine.&lt;/p&gt;

&lt;p&gt;I've got some form that looks like this:&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;form&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"category_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Category 1&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"category_1"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"category_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"category_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Category 2&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"category_2"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"category_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"category_3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Category 3&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"category_3"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"category_3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Show results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It allows people to select some grouping of filters: category 1, category 2, and category 3. When they hit &lt;code&gt;Show results&lt;/code&gt;, they get some results back based on these filters. &lt;/p&gt;

&lt;p&gt;I want to give a visual cue for which filters they've used. Maybe something like a background color on each associated &lt;code&gt;fieldset&lt;/code&gt; that contains checked checkboxes. That feels somewhat straightforward. &lt;/p&gt;

&lt;p&gt;But right now if I want to style the &lt;code&gt;fieldset&lt;/code&gt; based on its child, I have to use JavaScript to maybe listen for a &lt;code&gt;change&lt;/code&gt; or &lt;code&gt;click&lt;/code&gt; event, find the correct &lt;code&gt;fieldset&lt;/code&gt;, and update its styles through JS. &lt;/p&gt;

&lt;p&gt;Alternatively, I could set up a pseudo-element to do the job. But wait! &lt;code&gt;input&lt;/code&gt; elements &lt;em&gt;can't have pseudo-elements&lt;/em&gt;. So now I have to add an empty &lt;code&gt;span&lt;/code&gt; as a sibling and style its pseudo-elements. The markup changes to this:&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;form&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"category_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Category 1&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"category_1"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"category_1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"category_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Category 2&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"category_2"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"category_2"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fieldset&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"category_3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Category 3&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"category_3"&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"category_3"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;br&amp;gt;&amp;lt;br&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fieldset&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt; &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;"Show results"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then I write these styles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;fieldset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nt"&gt;span&lt;/span&gt;&lt;span class="nd"&gt;:before&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;content&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="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;absolute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100%&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;z-index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;-1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's workable. It's only a little extra code. But it would be really slick if I could write some CSS that looked like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="nd"&gt;:checked&lt;/span&gt; &lt;span class="nt"&gt;PARENT_SELECTOR_SYMBOL_HERE&lt;/span&gt; &lt;span class="nt"&gt;fieldset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;green&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's a &lt;a href="https://codepen.io/ogdenstudios/pen/jObEqpZ"&gt;codepen&lt;/a&gt; with the sample code so you can play around with it and see what I mean&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
    </item>
    <item>
      <title>Wrapping nuxt-links to make your Vue.js components Nuxt.js agnostic.</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Mon, 23 Mar 2020 22:48:54 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/wrapping-nuxt-links-to-make-your-vue-js-components-nuxt-js-agnostic-3o7</link>
      <guid>https://dev.to/ogdenstudios/wrapping-nuxt-links-to-make-your-vue-js-components-nuxt-js-agnostic-3o7</guid>
      <description>&lt;p&gt;At work we've got a component library built in &lt;a href="https://vuejs.org/"&gt;Vue.js&lt;/a&gt;. It's great because we can take the components our designers create, build them once, and then ship them to any project.&lt;/p&gt;

&lt;p&gt;Most, but not all, of our projects use &lt;a href="https://nuxtjs.org/"&gt;Nuxt.js&lt;/a&gt;. We like it because it gives us the ability to build sites with server-side rendering, static site generation, or single-page applications as needed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the components for Nuxt
&lt;/h2&gt;

&lt;p&gt;We have navigational components in our library like a &lt;code&gt;Navbar&lt;/code&gt; component and a &lt;code&gt;Footer&lt;/code&gt; component. Since these components typically direct users around internal pages on our Nuxt projects, we want to use the &lt;code&gt;nuxt-link&lt;/code&gt; component to get the most out of the framework. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://nuxtjs.org/api/components-nuxt-link/"&gt;nuxt-link&lt;/a&gt; allows users to navigate the application like they might expect with a &lt;code&gt;router-link&lt;/code&gt;. It is itself an extension of &lt;a href="https://router.vuejs.org/api/#router-link"&gt;router-link&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;But to use &lt;code&gt;nuxt-link&lt;/code&gt;, the component needs to be used &lt;em&gt;inside a Nuxt project&lt;/em&gt;. In Nuxt projects that's fine, but what do we do when we aren't using Nuxt? In those cases, we may want to use a regular HTML &lt;code&gt;a&lt;/code&gt; tag. &lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping nuxt-link
&lt;/h2&gt;

&lt;p&gt;So we built a utility component to wrap our links. It's aptly named &lt;code&gt;AnchorLinkOrNuxtLink&lt;/code&gt;. Here's what that looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nuxt-link&lt;/span&gt; &lt;span class="na"&gt;v-if=&lt;/span&gt;&lt;span class="s"&gt;"nuxt"&lt;/span&gt; &lt;span class="na"&gt;:to=&lt;/span&gt;&lt;span class="s"&gt;"to"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nuxt-link&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;a&lt;/span&gt; &lt;span class="na"&gt;v-else&lt;/span&gt; &lt;span class="na"&gt;:href=&lt;/span&gt;&lt;span class="s"&gt;"to"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;slot&amp;gt;&amp;lt;/slot&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/a&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nuxt&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;to&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&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 pass two props to the &lt;code&gt;AnchorLinkOrNuxtLink&lt;/code&gt; component: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nuxt&lt;/code&gt;: a boolean value which makes the component act as a &lt;code&gt;nuxt-link&lt;/code&gt; or an &lt;code&gt;a&lt;/code&gt; tag. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;to&lt;/code&gt;: some string that acts as the &lt;code&gt;to&lt;/code&gt; prop on a &lt;code&gt;nuxt-link&lt;/code&gt;, or the &lt;code&gt;href&lt;/code&gt; attribute on an &lt;code&gt;a&lt;/code&gt; tag. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We use &lt;a href="https://vuejs.org/v2/guide/conditional.html"&gt;conditional rendering&lt;/a&gt; to check if &lt;code&gt;nuxt&lt;/code&gt; is &lt;code&gt;true&lt;/code&gt;. If so, we use &lt;code&gt;nuxt-link&lt;/code&gt;. Otherwise, the component renders as an &lt;code&gt;a&lt;/code&gt; tag. If the &lt;code&gt;nuxt&lt;/code&gt; prop isn't passed in, the expression will evaluate to &lt;code&gt;false&lt;/code&gt; and we default to the safe fallback of an &lt;code&gt;a&lt;/code&gt; tag, which will work in either a Nuxt project or something else. &lt;/p&gt;

&lt;p&gt;Finally, since both &lt;code&gt;nuxt-link&lt;/code&gt;s and &lt;code&gt;a&lt;/code&gt; tags are able to wrap things, we provide a &lt;a href="https://vuejs.org/v2/guide/components.html#Content-Distribution-with-Slots"&gt;slot component&lt;/a&gt; inside either to contain any wrapped content. &lt;/p&gt;

&lt;h2&gt;
  
  
  Putting it together
&lt;/h2&gt;

&lt;p&gt;We want to be able to create a flexible component that can take links and render out either &lt;code&gt;nuxt-link&lt;/code&gt;s or &lt;code&gt;a&lt;/code&gt; tags. Let's look at a quick example. Say we want a &lt;code&gt;Navbar&lt;/code&gt; component with three links: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The brand element that navigates to &lt;code&gt;/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A secondary &lt;code&gt;About&lt;/code&gt; page &lt;/li&gt;
&lt;li&gt;Some link to an external resource like &lt;code&gt;Partner site&lt;/code&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can build that like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;nav&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;    
                &lt;span class="nt"&gt;&amp;lt;AnchorLinkOrNuxtLink&lt;/span&gt; &lt;span class="na"&gt;to=&lt;/span&gt;&lt;span class="s"&gt;"/"&lt;/span&gt; &lt;span class="na"&gt;:nuxt=&lt;/span&gt;&lt;span class="s"&gt;"brandIsNuxtLink"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="nt"&gt;&amp;lt;img&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"some-logo.jpg"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/AnchorLinkOrNuxtLink&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;li&lt;/span&gt; &lt;span class="na"&gt;v-for=&lt;/span&gt;&lt;span class="s"&gt;"item in navbar.links"&lt;/span&gt; &lt;span class="na"&gt;:key=&lt;/span&gt;&lt;span class="s"&gt;"item.link"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;AnchorLinkOrNuxtLink&lt;/span&gt; &lt;span class="na"&gt;:to=&lt;/span&gt;&lt;span class="s"&gt;"item.link"&lt;/span&gt; &lt;span class="na"&gt;:nuxt=&lt;/span&gt;&lt;span class="s"&gt;"item.nuxt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="si"&gt;{{&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt; &lt;span class="si"&gt;}}&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;/AnchorLinkOrNuxtLink&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/nav&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;AnchorLinkOrNuxtLink&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./AnchorLinkOrNuxtLink.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;components&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;AnchorLinkOrNuxtLink&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;brandIsNuxtLink&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;navbar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&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;This component takes two props: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;brandIsNuxtLink&lt;/code&gt;: since the &lt;strong&gt;brand&lt;/strong&gt; element is a bit different than the rest of the links in the nav, we call this out separately. We can pass a boolean to determine &lt;code&gt;nuxt-link&lt;/code&gt; vs &lt;code&gt;a&lt;/code&gt; tag behavior. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;navbar&lt;/code&gt;: we can pass an object as this prop to set up the links. It might look something like this:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;navbar&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/about&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;nuxt&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="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;About&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;link&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://www.partner.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;nuxt&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="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Partner site&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;/about&lt;/code&gt; link will act as a Nuxt link, and the &lt;code&gt;https://www.partner.com&lt;/code&gt; link will act like a normal anchor link. &lt;/p&gt;

&lt;p&gt;Fun!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>vue</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Troubleshooting Devise Redirects with Multiple Models and Turbolinks</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Tue, 18 Feb 2020 20:27:00 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/troubleshooting-devise-redirects-with-multiple-models-and-turbolinks-2c6p</link>
      <guid>https://dev.to/ogdenstudios/troubleshooting-devise-redirects-with-multiple-models-and-turbolinks-2c6p</guid>
      <description>&lt;h2&gt;
  
  
  Using two Devise Models
&lt;/h2&gt;

&lt;p&gt;I pretty much always default to using &lt;a href="https://github.com/heartcombo/devise"&gt;Devise&lt;/a&gt; for my Ruby on Rails authentication.&lt;/p&gt;

&lt;p&gt;For my current side project built in Rails 6, I've got two authenticating models: &lt;code&gt;Author&lt;/code&gt; and &lt;code&gt;Reader&lt;/code&gt;. It makes sense for me to keep these two models entirely separate. It's made my life a lot easier, in general. Using multiple models is supported out of the box with Devise, &lt;a href="https://github.com/heartcombo/devise/wiki/How-to-Setup-Multiple-Devise-User-Models"&gt;with some custom configuration&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  Preventing Cross-model Visits with Devise
&lt;/h2&gt;

&lt;p&gt;Devise provides a &lt;a href="https://github.com/heartcombo/devise/wiki/How-to-Setup-Multiple-Devise-User-Models#6-fix-cross-model-visits-fancy-name-for-users-can-visit-admins-login-and-viceversa-and-mess-up-your-auth-tokens"&gt;sample solution&lt;/a&gt; to prevent a logged in &lt;code&gt;Author&lt;/code&gt; from &lt;em&gt;concurrently&lt;/em&gt; logging in as a &lt;code&gt;Reader&lt;/code&gt;, and vice-versa.&lt;/p&gt;

&lt;p&gt;I modified the sample code a little bit when I first implemented this. I didn't have anywhere to send them since I built it out early in the development process, so I had each model &lt;code&gt;redirect_to&lt;/code&gt; the &lt;code&gt;root_path&lt;/code&gt;. This laid the groundwork for two days of troubleshooting down the road. &lt;/p&gt;

&lt;p&gt;My custom &lt;code&gt;Accessible&lt;/code&gt; module was initially written 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;# ../controllers/concerns/accessible.rb
module Accessible
  extend ActiveSupport::Concern
  included do
    before_action :check_user
  end

  protected
  def check_user
    if current_admin
      flash.clear
      # if you have rails_admin. You can redirect anywhere really
      redirect_to(root_path) and return
    elsif current_user
      flash.clear
      # The authenticated root path can be defined in your routes.rb in: devise_scope :user do...
      redirect_to(root_path) and return
    end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Turbolinks Red Herring
&lt;/h2&gt;

&lt;p&gt;As time went on, I built out most of the functionality of the application. I got the MVP working, built out some seed data, and deployed to a staging environment. I did some manual testing and played around with everything, and noticed that whenever I logged in as a sample &lt;code&gt;Author&lt;/code&gt; or &lt;code&gt;Reader&lt;/code&gt;, I got redirected to the home page. I assumed I had misconfigured something, so I followed &lt;a href="https://github.com/heartcombo/devise/wiki/How-To:-Redirect-back-to-current-page-after-sign-in,-sign-out,-sign-up,-update"&gt;this wiki article&lt;/a&gt; to redirect users back to their last visited page. &lt;/p&gt;

&lt;p&gt;The wiki article provides two different implementations. I tried both and couldn't get it to work for the life of me. I dug in to the helper methods, hard coded returns, ran &lt;a href="https://github.com/deivid-rodriguez/byebug"&gt;byebug&lt;/a&gt; sessions, and couldn't quite figure out waht wasn't working. &lt;/p&gt;

&lt;p&gt;But I noticed that both of the methods provided by Devise checked if the request was an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest"&gt;XHR&lt;/a&gt;. I thought I had identified the bug: I was using &lt;a href="https://github.com/turbolinks/turbolinks"&gt;turbolinks&lt;/a&gt; out of the box with Rails 6. I don't know precisely what Turbolinks is doing under the hood, but my understanding is that it uses client-side requests to pre-render pages from the same origin, providing an SPA-like experience. &lt;/p&gt;

&lt;p&gt;I figured Turbolinks navigation was breaking the expected Devise behavior. I found &lt;a href="https://www.oarod.com/2017/01/29/turbolinks-with-devise/"&gt;semi-recent blog posts&lt;/a&gt; about this phenomenon. I saw a few issues across the Turbolinks and Devise repositiories. I figured I was on to something. &lt;/p&gt;

&lt;h2&gt;
  
  
  Building a Reduced Test Case
&lt;/h2&gt;

&lt;p&gt;So after I latched on to this idea, I decided I would write a blog post about it. To demonstrate the problem, I spun up a sample Rails app with Turbolinks and Devise. I duplicated my issue. As I went to turn off Turbolinks and demonstrate the root cause, I found this snippet in &lt;code&gt;config/initializers/devise.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ==&amp;gt; Turbolinks configuration&lt;/span&gt;
&lt;span class="c1"&gt;# If your app is using Turbolinks, Turbolinks::Controller needs to be included to make redirection work correctly:&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;#  ActiveSupport.on_load(:devise_failure_app) do&lt;/span&gt;
&lt;span class="c1"&gt;#    include Turbolinks::Controller&lt;/span&gt;
&lt;span class="c1"&gt;#  end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So I un-commented the piece of configuration, but no luck. There was still a problem. &lt;/p&gt;

&lt;h2&gt;
  
  
  Removing the &lt;code&gt;current_user&lt;/code&gt; Check
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://github.com/heartcombo/devise/wiki/How-To:-Redirect-back-to-current-page-after-sign-in,-sign-out,-sign-up,-update#storelocation-to-the-rescue"&gt;first StoreLocation example&lt;/a&gt;, I noticed that &lt;code&gt;store_location_for(:user, request.fullpath)&lt;/code&gt; was only being triggered if &lt;code&gt;current_user.present?&lt;/code&gt; returned true. &lt;/p&gt;

&lt;p&gt;But that doesn't track for me. I want to store the location for a &lt;code&gt;User&lt;/code&gt; (or &lt;code&gt;Author&lt;/code&gt;, or &lt;code&gt;Reader&lt;/code&gt;, or whomever) &lt;em&gt;before they log in&lt;/em&gt;. So I removed that check. In my sample app, with just one &lt;code&gt;User&lt;/code&gt; Devise model, and with &lt;code&gt;Turbolinks::Controller&lt;/code&gt; turned on, I implemented the following:&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;# This example assumes that you have setup devise to authenticate a class named User.&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicationController&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ActionController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="no"&gt;Base&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:store_user_location!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;if: :storable_location?&lt;/span&gt;
  &lt;span class="c1"&gt;# The callback which stores the current location must be added before you authenticate the user &lt;/span&gt;
  &lt;span class="c1"&gt;# as `authenticate_user!` (or whatever your resource is) will halt the filter chain and redirect &lt;/span&gt;
  &lt;span class="c1"&gt;# before the location can be stored.&lt;/span&gt;
  &lt;span class="n"&gt;before_action&lt;/span&gt; &lt;span class="ss"&gt;:authenticate_user!&lt;/span&gt;

  &lt;span class="kp"&gt;private&lt;/span&gt;
    &lt;span class="c1"&gt;# Its important that the location is NOT stored if:&lt;/span&gt;
    &lt;span class="c1"&gt;# - The request method is not GET (non idempotent)&lt;/span&gt;
    &lt;span class="c1"&gt;# - The request is handled by a Devise controller such as Devise::SessionsController as that could cause an &lt;/span&gt;
    &lt;span class="c1"&gt;#    infinite redirect loop.&lt;/span&gt;
    &lt;span class="c1"&gt;# - The request is an Ajax request as this can lead to very unexpected behaviour.&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;storable_location?&lt;/span&gt;
      &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;is_navigational_format?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;devise_controller?&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;xhr?&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;store_user_location!&lt;/span&gt;
      &lt;span class="c1"&gt;# :user is the scope we are authenticating&lt;/span&gt;
      &lt;span class="n"&gt;store_location_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fullpath&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;And it worked! I figured I had solved my problem. All I needed to do to make it work in my actual application was: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Turn on &lt;code&gt;Turbolinks::Controller&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Implement the first &lt;code&gt;store_user_location!&lt;/code&gt; method&lt;/li&gt;
&lt;li&gt;Remove checks for &lt;code&gt;current_author&lt;/code&gt; and &lt;code&gt;current_reader&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;??? &lt;/li&gt;
&lt;li&gt;Profit!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Hubris. Pure Hubris.
&lt;/h2&gt;

&lt;p&gt;I made those changes to my application. No luck. I tried the second implementation of &lt;code&gt;store_user_locaiton!&lt;/code&gt;... no luck. I turned Turbolinks on and off again. No luck. I yelled a little bit into a pillow. No luck, but it felt good. &lt;/p&gt;

&lt;p&gt;I started digging into the differences between the sample application and my real application. I figured the biggest difference was using one Devise model vs. using many. So I started looking at the generated controllers and views for my multiple Devise models. I wrote some experimental code, tried to override &lt;code&gt;after_sign_in_path_for&lt;/code&gt; from Devise, and still no luck. &lt;/p&gt;

&lt;p&gt;But, if you'll recall, I was preventing cross-model visits with my &lt;code&gt;Accessible&lt;/code&gt; module. For laughs, I turned off the module. Things started working. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Real Culprit: Hardcoded Redirects
&lt;/h2&gt;

&lt;p&gt;Remember how I told my &lt;code&gt;Accessible&lt;/code&gt; module to &lt;code&gt;redirect_to(root_path) and return&lt;/code&gt; in &lt;code&gt;check_user&lt;/code&gt;? Yeah - me neither. I forgot I had written that method long ago before the application had taken shape. Forgot that I was hardcoding a redirect to the root path. &lt;/p&gt;

&lt;p&gt;So I tapped into the &lt;code&gt;stored_location_for&lt;/code&gt; method from Devise. I rewrote the &lt;code&gt;Accessible&lt;/code&gt; module to look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;module&lt;/span&gt; &lt;span class="nn"&gt;Accessible&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_action&lt;/span&gt; &lt;span class="ss"&gt;:check_user&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

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

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;check_user&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;current_author&lt;/span&gt;
      &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;
      &lt;span class="n"&gt;redirect_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stored_location_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:author&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="k"&gt;elsif&lt;/span&gt; &lt;span class="n"&gt;current_reader&lt;/span&gt;
      &lt;span class="n"&gt;flash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;clear&lt;/span&gt;
      &lt;span class="n"&gt;redirect_to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stored_location_for&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:reader&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="k"&gt;return&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 everything started working. Now: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Authors&lt;/code&gt; can't log in as &lt;code&gt;Readers&lt;/code&gt; without signing out first&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Readers&lt;/code&gt; can't log in as &lt;code&gt;Authors&lt;/code&gt; without signing out first &lt;/li&gt;
&lt;li&gt;When a person signs in to either an &lt;code&gt;Author&lt;/code&gt; or a &lt;code&gt;Reader&lt;/code&gt; account, they will then be redirected to the last page they were viewing before signing in &lt;/li&gt;
&lt;li&gt;Turbolinks are still working.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>devise</category>
      <category>turbolinks</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Refactoring Personal Data out of a Devise Model</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Sun, 16 Feb 2020 23:00:18 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/refactoring-personal-data-out-of-a-devise-model-3jh9</link>
      <guid>https://dev.to/ogdenstudios/refactoring-personal-data-out-of-a-devise-model-3jh9</guid>
      <description>&lt;p&gt;I'm working on &lt;a href="https://rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt; application. It's an ecommerce platform for print creators. My minimum viable product is working, and it's time to roll up my sleeves and refactor the code to get it production-ready. &lt;/p&gt;

&lt;h2&gt;
  
  
  What needs to change about my Reader Model?
&lt;/h2&gt;

&lt;p&gt;The basic authentication model is the &lt;code&gt;Reader&lt;/code&gt;. It represents what you might consider to be a &lt;code&gt;User&lt;/code&gt; in other applications. &lt;/p&gt;

&lt;p&gt;This model is built with &lt;a href="https://github.com/heartcombo/devise"&gt;Devise&lt;/a&gt;. When I first wrote it, I also used it to store profile information for each reader. &lt;/p&gt;

&lt;p&gt;After some great conversations in the &lt;a href="https://www.rubyonrails.link/"&gt;Ruby on Rails Link Slack&lt;/a&gt;, I've come to understand that my authentication model shouldn't be responsible for managing user data. It sort of violates the &lt;a href="https://www.rubyonrails.link/"&gt;single responsibility principle&lt;/a&gt;. And practically speaking, every attribute follows the &lt;code&gt;current_reader&lt;/code&gt; object in controllers and views. So if I have a logged-in &lt;code&gt;Reader&lt;/code&gt; on the home page, the view knows all of its attributes. In my case, that only includes a &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt; column, but this approach can lead to problems down the road.&lt;/p&gt;

&lt;p&gt;If I continue to add reader data in the &lt;code&gt;Reader&lt;/code&gt; model, I will be loading a lot of unnecessary data in each request with the &lt;code&gt;current_reader&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;I want to contain these attributes in a new class called &lt;code&gt;ReaderProfile&lt;/code&gt;, of which each &lt;code&gt;Reader&lt;/code&gt; object will &lt;code&gt;have_one&lt;/code&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Current Reader Model
&lt;/h2&gt;

&lt;p&gt;This is my current &lt;code&gt;ApplicationRecord&lt;/code&gt; subclass:&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;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Reader&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="c1"&gt;# Include default devise modules. Others available are:&lt;/span&gt;
  &lt;span class="c1"&gt;# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable&lt;/span&gt;
  &lt;span class="n"&gt;devise&lt;/span&gt; &lt;span class="ss"&gt;:database_authenticatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:registerable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="ss"&gt;:recoverable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:rememberable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:validatable&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:works&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:through&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:purchases&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:followings&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:purchases&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:reading_list_items&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:works_to_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;through: :reading_list_items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;source: :work&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:reviews&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 the relevant schema from &lt;code&gt;db/schema.rb&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;create_table&lt;/span&gt; &lt;span class="s2"&gt;"readers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;force: :cascade&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;t&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default: &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"encrypted_password"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;default: &lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"reset_password_token"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="s2"&gt;"reset_password_sent_at"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="s2"&gt;"remember_created_at"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="s2"&gt;"created_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;precision: &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt; &lt;span class="s2"&gt;"updated_at"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;precision: &lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;null: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"first_name"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt; &lt;span class="s2"&gt;"last_name"&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"email"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"index_readers_on_email"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unique: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
    &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;index&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"reset_password_token"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="ss"&gt;name: &lt;/span&gt;&lt;span class="s2"&gt;"index_readers_on_reset_password_token"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;unique: &lt;/span&gt;&lt;span class="kp"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Current Reader Tests
&lt;/h2&gt;

&lt;p&gt;I'm using &lt;a href="https://github.com/rspec/rspec-rails"&gt;RSpec&lt;/a&gt; to test my Rails application, along with &lt;a href="https://github.com/thoughtbot/factory_bot_rails"&gt;FactoryBot&lt;/a&gt; for my factories.&lt;/p&gt;

&lt;p&gt;I have unit tests in &lt;code&gt;spec/models/reader_spec.rb&lt;/code&gt;. Here's what I test for:&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;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s1"&gt;'rails_helper'&lt;/span&gt;

&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :model&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'has a valid factory'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:reader&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_valid&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="n"&gt;describe&lt;/span&gt; &lt;span class="s1"&gt;'associations'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:followings&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:purchases&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:reading_list_items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:reviews&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_many&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:works&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The ReaderProfile Model
&lt;/h2&gt;

&lt;p&gt;I can create my new &lt;code&gt;ReaderProfile&lt;/code&gt; model with the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;rails g model ReaderProfile first_name:string last_name:string reader:references
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates the relevant ActiveRecord class, Rails migration, and tests for the class. &lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the ReaderProfile
&lt;/h2&gt;

&lt;p&gt;I'm going to make &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt; information optional for readers, so all I want to do is make sure I've got a test in &lt;code&gt;spec/models/reader_profile_spec.rb&lt;/code&gt; that checks for a valid factory and it belongs to a &lt;code&gt;Reader&lt;/code&gt; object. Here's what that unit test looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;RSpec&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt; &lt;span class="no"&gt;ReaderProfile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;type: :model&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="s1"&gt;'has a valid factory'&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:reader_profile&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt; &lt;span class="n"&gt;be_valid&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;My factory in &lt;code&gt;spec/factories/reader_profiles.rb&lt;/code&gt; looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="no"&gt;FactoryBot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;define&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;factory&lt;/span&gt; &lt;span class="ss"&gt;:reader_profile&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;first_name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"MyString"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;last_name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s2"&gt;"MyString"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:reader&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="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I add the &lt;code&gt;belongs_to&lt;/code&gt; code in my &lt;code&gt;ReaderProfile&lt;/code&gt; model like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# app/models/reader_profile.rb&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReaderProfile&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="no"&gt;ApplicationRecord&lt;/span&gt;
    &lt;span class="n"&gt;belongs_to&lt;/span&gt; &lt;span class="ss"&gt;:reader&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 when I run &lt;code&gt;rspec spec/models/reader_profile_spec.rb&lt;/code&gt;, my tests pass. &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding to the Reader Tests
&lt;/h2&gt;

&lt;p&gt;I want every &lt;code&gt;Reader&lt;/code&gt; object to have one &lt;code&gt;ReaderProfile&lt;/code&gt;. To test that, I add the following to &lt;code&gt;spec/models/reader_spec.rb&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="n"&gt;it&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;should&lt;/span&gt; &lt;span class="n"&gt;have_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:reader_profile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And I update the &lt;code&gt;Reader&lt;/code&gt; model to look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# frozen_string_literal: true&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Reader&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="c1"&gt;# Include default devise modules. Others available are:&lt;/span&gt;
  &lt;span class="c1"&gt;# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable&lt;/span&gt;
  &lt;span class="n"&gt;devise&lt;/span&gt; &lt;span class="ss"&gt;:database_authenticatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:registerable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="ss"&gt;:recoverable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:rememberable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:validatable&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:works&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;:through&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:purchases&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:followings&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:purchases&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:reading_list_items&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:works_to_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;through: :reading_list_items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;source: :work&lt;/span&gt;
  &lt;span class="n"&gt;has_many&lt;/span&gt; &lt;span class="ss"&gt;:reviews&lt;/span&gt;
  &lt;span class="n"&gt;has_one&lt;/span&gt; &lt;span class="ss"&gt;:reader_profile&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When I run &lt;code&gt;rspec spec/models/reader_spec&lt;/code&gt;, everything passes. &lt;/p&gt;

&lt;h2&gt;
  
  
  Updating the impacted Views and Controllers
&lt;/h2&gt;

&lt;p&gt;I've been focusing on the model layer of this refactoring. It's worth noting that I have &lt;code&gt;current_reader.first_name&lt;/code&gt; and &lt;code&gt;current_reader.last_name&lt;/code&gt; strewn through my application. I'll need to find-and-replace those instances to &lt;code&gt;current_reader.reader_profile.first_name&lt;/code&gt; and &lt;code&gt;current_reader.reader_profile.last_name&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I'll also need to drop the &lt;code&gt;first_name&lt;/code&gt; and &lt;code&gt;last_name&lt;/code&gt; parameters from the &lt;code&gt;ReadersController&lt;/code&gt;, and create endpoints for readers to create, update, and delete their profiles.&lt;/p&gt;

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

&lt;p&gt;Aside from my remaining TODOs, I've made good progress today. Now I have a &lt;code&gt;ReaderProfile&lt;/code&gt; model to encapsulate personal information associated with each &lt;code&gt;Reader&lt;/code&gt;. This makes it easier to add more pieces of &lt;code&gt;Reader&lt;/code&gt; data without bloating the authentication class. It also means I can extend my authentication class to include different types of profiles if I like. Here's what my refactoring is really saying: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Reader&lt;/code&gt; model handles authentication and authorization for readers. When a reader signs in, they can access their associated &lt;code&gt;ReaderProfile&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;The &lt;code&gt;ReaderProfile&lt;/code&gt; model stores personal information about the &lt;code&gt;Reader&lt;/code&gt; it belongs to. &lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>devise</category>
      <category>activerecord</category>
    </item>
    <item>
      <title>Sort Array by Parity</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Tue, 11 Feb 2020 16:35:29 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/sort-array-by-parity-1hbf</link>
      <guid>https://dev.to/ogdenstudios/sort-array-by-parity-1hbf</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is part of my "LeetCode for 1x Developers" series, in which I struggle through LeetCode problems. Sometimes I figure it out, other times I don't. Either way, I give each problem my best shot, and write up my thought process through the challenges&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Problem description
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/sort-array-by-parity-ii/"&gt;Problem on leetcode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Given an array &lt;code&gt;A&lt;/code&gt; of non-negative integers, half of the integers in &lt;code&gt;A&lt;/code&gt; ar odd, and half of the integers are even. &lt;/p&gt;

&lt;p&gt;Sort the array so that whenever &lt;code&gt;A[i]&lt;/code&gt; is odd, &lt;code&gt;i&lt;/code&gt; is odd. And when &lt;code&gt;A[i]&lt;/code&gt; is even, &lt;code&gt;i&lt;/code&gt; is even. &lt;/p&gt;

&lt;p&gt;You may return any answer array that satisfies this conditions. &lt;/p&gt;

&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; &lt;code&gt;[4,2,5,7]&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Output:&lt;/strong&gt; &lt;code&gt;[4,5,2,7]&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Explanation:&lt;/strong&gt; &lt;code&gt;[4,7,2,5]&lt;/code&gt;, &lt;code&gt;[2,5,4,6]&lt;/code&gt;, &lt;code&gt;[2,7,4,5]&lt;/code&gt; would also have been accepted.&lt;/p&gt;
&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Intuition
&lt;/h3&gt;

&lt;p&gt;OK, so it looks like we don't have to actually &lt;em&gt;sort&lt;/em&gt; the array in any meaningful way. We can probably do something with it in-place. We also know we'll always have enough numbers to fill the pattern, since half of the integers are odd and half are even. &lt;/p&gt;

&lt;p&gt;Can we do this in place? Let's look at the example: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;[4, 2, 5, 7]&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Check &lt;code&gt;A[0]&lt;/code&gt;. It's &lt;code&gt;4&lt;/code&gt;. OK, it's all good since &lt;code&gt;i&lt;/code&gt; and &lt;code&gt;A[i]&lt;/code&gt; are both even.&lt;/p&gt;

&lt;p&gt;Now check &lt;code&gt;A[2]&lt;/code&gt;, it's &lt;code&gt;2&lt;/code&gt;. &lt;code&gt;i&lt;/code&gt; is odd, but &lt;code&gt;A[i]&lt;/code&gt; is even. We need to move it. I almost want to just swap it with the next value, but I am pretty sure that won't work all the time so I'm going to leave it alone. &lt;/p&gt;

&lt;p&gt;What if we stored all of the even numbers in an array called &lt;code&gt;even&lt;/code&gt; and all the odd numbers in an array called &lt;code&gt;odd&lt;/code&gt;? We could then rebuild an array and pull a number from each depending on the parity of the number. &lt;/p&gt;

&lt;p&gt;I'm worried about basically running two loops and using three arrays. But I think it's still technically O(n), and the space constraints will only ever be 2n. Maybe that's reasonable. Let's find out. &lt;/p&gt;

&lt;p&gt;Here's my first pass at expressing this solution in JavaScript (ES6):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;sortArrayByParityII&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;odd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&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="nx"&gt;odd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;even&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pop&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="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;odd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;    
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It passed, faster than 51.97% of JS solutions, and with less than 27.27% of JS solutions. I wonder where I can optimize it. It feels like I &lt;em&gt;should&lt;/em&gt; be able to do something in one loop, but I can't really reckon with it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Answer
&lt;/h3&gt;

&lt;p&gt;After checking the discussion section, I found there &lt;em&gt;is&lt;/em&gt; a one-loop solution. It's not too far off from my first pass. &lt;/p&gt;

&lt;p&gt;First, you set up an empty array, which you'll use as the result. Call it &lt;code&gt;result&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then you set an &lt;code&gt;evenIndex&lt;/code&gt; to 0, and an &lt;code&gt;oddIndex&lt;/code&gt; to `. &lt;/p&gt;

&lt;p&gt;You loop through the input array &lt;code&gt;A&lt;/code&gt;. If &lt;code&gt;A[i]&lt;/code&gt; is even, you set &lt;code&gt;result[evenIndex]&lt;/code&gt; to the value and increment &lt;code&gt;evenIndex&lt;/code&gt; by two. If it's odd, you set &lt;code&gt;result[oddINdex]&lt;/code&gt; to the value and increment &lt;code&gt;oddIndex&lt;/code&gt; by two. &lt;/p&gt;

&lt;p&gt;You can express it like this: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
var sortArrayByParityII = function(A) {&lt;br&gt;
    let result = [];&lt;br&gt;
    let evenIndex = 0;&lt;br&gt;
    let oddIndex = 1;&lt;br&gt;
    for (let i=0; i&amp;lt;A.length; i++) {&lt;br&gt;
        if (A[i] % 2 === 0) {&lt;br&gt;
            result[evenIndex] = A[i];&lt;br&gt;
            evenIndex += 2;&lt;br&gt;
        } else {&lt;br&gt;
            result[oddIndex] = A[i];&lt;br&gt;
            oddIndex += 2;&lt;br&gt;
        }&lt;br&gt;
    }&lt;br&gt;
    return result;&lt;br&gt;
}&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And it runs faster than 86% of JS solutions with less memory than 36% of other solutions. Nice! &lt;/p&gt;

&lt;p&gt;After having done a dozen or so easy problems, I'm really starting to see most Leetcode easy problems as array mapping solutions. &lt;/p&gt;

</description>
      <category>computerscience</category>
      <category>javascript</category>
      <category>leetcode</category>
      <category>algorithms</category>
    </item>
    <item>
      <title>Find the K-th Symbol in Grammar</title>
      <dc:creator>Tyler Scott Williams</dc:creator>
      <pubDate>Mon, 10 Feb 2020 18:24:14 +0000</pubDate>
      <link>https://dev.to/ogdenstudios/find-the-k-th-symbol-in-grammar-3k4</link>
      <guid>https://dev.to/ogdenstudios/find-the-k-th-symbol-in-grammar-3k4</guid>
      <description>&lt;p&gt;&lt;em&gt;This post is part of my "LeetCode for 1x Developers" series, in which I struggle through LeetCode problems. Sometimes I figure it out, other times I don't. Either way, I give each problem my best shot, and write up my thought process through the challenges&lt;/em&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  Problem description
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/k-th-symbol-in-grammar/"&gt;Problem on leetcode&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the first row, we write a &lt;code&gt;0&lt;/code&gt;. Now in every subsequent row, we look at the previous row and replace each occurence of &lt;code&gt;0&lt;/code&gt; with &lt;code&gt;01&lt;/code&gt;, and each occurrence of &lt;code&gt;1&lt;/code&gt; with &lt;code&gt;10&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Given row &lt;code&gt;N&lt;/code&gt; and index &lt;code&gt;K&lt;/code&gt;, return the &lt;code&gt;K&lt;/code&gt;-th indexed symbol in row &lt;code&gt;N&lt;/code&gt;. The values of &lt;code&gt;K&lt;/code&gt; are `-indexed. &lt;/p&gt;

&lt;h3&gt;
  
  
  Examples
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; N = 1, K = 1&lt;br&gt;
&lt;strong&gt;Output:&lt;/strong&gt; 0&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; N = 2, K = 1&lt;br&gt;
&lt;strong&gt;Output:&lt;/strong&gt; 0&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; N = 2, K = 2&lt;br&gt;
&lt;strong&gt;Output:&lt;/strong&gt; 1&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Input:&lt;/strong&gt; N = 4, K = 5&lt;br&gt;
&lt;strong&gt;Output:&lt;/strong&gt; 1&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explanation:&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;row 1: 0&lt;br&gt;
row 2: 01 &lt;br&gt;
row 3: 0110&lt;br&gt;
row 4: 01101001&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Intuition
&lt;/h3&gt;

&lt;p&gt;Based on the generating of the rows, I have a feeling there's a mathematical solution to this that's faster than a data structure based algorithm. &lt;/p&gt;

&lt;p&gt;To get a feel for what's going on and how I might express it mathematically, I'm going to manually write out the pattern. &lt;/p&gt;

&lt;p&gt;Looking at four rows: &lt;/p&gt;

&lt;p&gt;0&lt;br&gt;
01&lt;br&gt;
0110&lt;br&gt;
01101001&lt;br&gt;
0110100110010110&lt;/p&gt;

&lt;p&gt;I notice that the number of items in each row is &lt;code&gt;2^N&lt;/code&gt;. Which suggests to me there might be some bitwise solution here, which also feels right considering all the &lt;code&gt;0&lt;/code&gt; and &lt;code&gt;1&lt;/code&gt; values. &lt;/p&gt;

&lt;p&gt;What's more, looking at the way that the pattern stacks (every row &lt;code&gt;N&lt;/code&gt; is the beginning of the next row &lt;code&gt;N+1&lt;/code&gt;), I don't think &lt;code&gt;N&lt;/code&gt; really matters. I think there's something I can do with &lt;code&gt;K&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;I'm feeling really good about there being an existing binary operation I can do, but I just can't quite find it or reason about it. I've mentioned this in other posts, but I'm definitely weak when it comes to binary operations and using them for problem solving. This probably comes from my day-to-day in web development, where I'm just not using that kind of problem-solving tool. &lt;/p&gt;

&lt;p&gt;So I looked up the discussion answer and I was absolutely on the right track. There is a single arithmetic I can do, in binary, and ignoring &lt;code&gt;N&lt;/code&gt; completely. &lt;/p&gt;

&lt;h3&gt;
  
  
  Answer
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://leetcode.com/problems/k-th-symbol-in-grammar/discuss/415514/Python-one-line-solution"&gt;Here's a Python one-liner&lt;/a&gt; which converts &lt;code&gt;K-1&lt;/code&gt; into its binary representation, counts how many times &lt;code&gt;1&lt;/code&gt; appears in that representation, and runs a bitwise AND operation on the result. &lt;/p&gt;

&lt;p&gt;I couldn't quite grok what was going on and why, but I found &lt;a href="https://leetcode.com/problems/k-th-symbol-in-grammar/discuss/113736/PythonJavaC%2B%2B-Easy-1-line-Solution-with-detailed-explanation"&gt;this explanation&lt;/a&gt; which helps more. &lt;/p&gt;

&lt;p&gt;Basically, since we know the prefix of every row &lt;code&gt;N&lt;/code&gt; is the same, we only care about how the new row &lt;code&gt;N+1&lt;/code&gt; is going to generate its new string up to &lt;code&gt;K&lt;/code&gt;, which will depend on the number &lt;code&gt;K-1&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;If we know what &lt;code&gt;K-1&lt;/code&gt; in binary is, we'll know how many times the &lt;code&gt;01&lt;/code&gt; and &lt;code&gt;10&lt;/code&gt; pattern toggles back and forth before the number we care about, &lt;code&gt;K&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;So we convert it over, count up the &lt;code&gt;1s&lt;/code&gt;, and convert that number into binary. We then run &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators"&gt;bitwise AND&lt;/a&gt; against it to determine the &lt;code&gt;K&lt;/code&gt;th value. &lt;/p&gt;

&lt;p&gt;We don't have all the syntactic sugar that comes along with Python, Java, and C++ for bitwise operations, so here's a way to represent it in JavaScript: &lt;/p&gt;

&lt;p&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;br&gt;
var kthGrammar = function(N, K) {&lt;br&gt;
    let binary = (K-1).toString(2);&lt;br&gt;
    let array = binary.split('');&lt;br&gt;
    let count = 0;&lt;br&gt;
    for (let i=0; i&amp;lt;array.length; i++) {&lt;br&gt;
        if (array[i] === '1') {&lt;br&gt;
            count++;&lt;br&gt;
        }&lt;br&gt;
    }&lt;br&gt;
    return count &amp;amp; 1;&lt;br&gt;
};&lt;br&gt;
&lt;/code&gt;&lt;code&gt;&lt;/code&gt;&lt;/p&gt;

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