<?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>Forem: milandhar</title>
    <description>The latest articles on Forem by milandhar (@milandhar).</description>
    <link>https://forem.com/milandhar</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%2F169468%2Fa3d5e537-2651-4806-979c-a6bc0c50a2a6.jpg</url>
      <title>Forem: milandhar</title>
      <link>https://forem.com/milandhar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/milandhar"/>
    <language>en</language>
    <item>
      <title>What are Heroku Dynos?</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Thu, 28 Nov 2019 00:08:43 +0000</pubDate>
      <link>https://forem.com/milandhar/what-are-heroku-dynos-3b1p</link>
      <guid>https://forem.com/milandhar/what-are-heroku-dynos-3b1p</guid>
      <description>&lt;p&gt;In recent weeks' posts, I have been making changes to my personal project &lt;a href="https://effectivedonate.herokuapp.com/" rel="noopener noreferrer"&gt;EffectiveDonate&lt;/a&gt;, including making my &lt;a href="https://dev.to/milandhar/responsive-react-components-w-semantic-ui-10cn"&gt;React components responsive&lt;/a&gt;, &lt;a href="https://dev.to/milandhar/using-css-media-queries-2hf3"&gt;optimizing the site for mobile&lt;/a&gt;, and &lt;a href="https://dev.to/milandhar/drag-and-drop-table-with-react-beautiful-dnd-54ad"&gt;improving the UX&lt;/a&gt;. All of these changes have been getting me closer to considering EffectiveDonate "production ready".&lt;/p&gt;

&lt;p&gt;However one barrier that has stood in the way of production had to do with my settings on &lt;a href="https://heroku.com/" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt;. Heroku is the cloud application platform that I have been using to deploy my web development projects, including EffectiveDonate. The particular problem that I faced had to do with a concept called "dynos" in Heroku, which are the building blocks powering any Heroku app. In this post, I will explain what dynos are, the problem that affected my website, and how I fixed it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heroku Dynos
&lt;/h2&gt;

&lt;p&gt;To understand dynos, we must first learn about the concept of containerization in app development. &lt;a href="https://www.heroku.com/dynos" rel="noopener noreferrer"&gt;Containerization&lt;/a&gt; is what abstracts away the need for app developers to manage hardware or virtual machines. Instead, we just deploy the app to a cloud platform like Heroku, which package the app into containers, which are environments that provide compute, memory, an OS, and a file system. &lt;/p&gt;

&lt;p&gt;Heroku uses the container model to handle its apps, and the containers are called "dynos". &lt;a href="https://www.heroku.com/dynos" rel="noopener noreferrer"&gt;Dynos&lt;/a&gt; are isolated Linux containers that are designed to execute code based on user commands. Heroku apps can dynamically scale to any number of dynos based on resource demands. &lt;/p&gt;

&lt;p&gt;Dynos allow app developers to focus on building new projects without needing to worry about managing infrastructure. Cool! &lt;/p&gt;

&lt;h3&gt;
  
  
  Dyno Types
&lt;/h3&gt;

&lt;p&gt;Heroku offers many &lt;a href="https://www.heroku.com/dynos/configure" rel="noopener noreferrer"&gt;different types of dynos&lt;/a&gt;, each with their own features, functionality and pricing: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free dynos: ideal for experimenting. These dynos sleep after 30 minutes of inactivity to preserve remaining free dyno hours. &lt;/li&gt;
&lt;li&gt;Hobby dynos: good for small scale personal projects. These dynos don't sleep.&lt;/li&gt;
&lt;li&gt;Standard dynos: provide enhanced visibility, performance and scalability for professional apps. &lt;/li&gt;
&lt;li&gt;Performance dynos: provide superior performance when it's most critical. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dynos in My Project
&lt;/h3&gt;

&lt;p&gt;When I deployed EffectiveDonate to Heroku, I didn't customize any of the performance settings, so it defaulted to using free dynos. I began to notice that whenever I accessed the site for the first time of the day, it would take a long time to load and then I'd get an error message like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F7L0E4PA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F7L0E4PA.png" alt="Application Error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But when I refreshed the page, the login screen would appear correctly. Although everything ran smoothly after I refreshed the page, having the user land on an error page was obviously not a good UX and gave a poor first impression of the site. &lt;/p&gt;

&lt;p&gt;After doing some digging, I learned that this was actually expected behavior when using free dynos, since they sleep after 30 minutes of inactivity. Now that EffectiveDonate was getting close to production status, I decided it was time to upgrade to hobby dynos. &lt;/p&gt;

&lt;p&gt;Luckily, hobby dynos cost only $7/month, and are prorated to the time that the dyno is actually in use. So running a dyno for 15/30 days of a month would cost only $3.50 for that month. &lt;/p&gt;

&lt;p&gt;In my Heroku Dashboard, I selected my project, navigated to the "Resources" section, and selected "Change Dyno Type". I selected "Hobby", and the change immediately reflected in my project's dashboard. &lt;/p&gt;

&lt;p&gt;Now anytime I enter the EffectiveDonate site, the hobby dynos are awake and I am correctly routed to the login page, without a delay or that nasty error page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FjGuFcJK.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FjGuFcJK.png" alt="Login Page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another cool bonus about upgrading to hobby dynos is that a "Metrics" section gets added to your app's dashboard, giving you stats on events, memory usage, response time, throughput, and dyno load.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FiQgMDLJ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FiQgMDLJ.png" alt="Metrics section"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Dynos had been a concept that kept popping up during my builds and app management, but I had never really dug into them. Researching them has been a good exercise in learning more about cloud concepts such as containerization. And now EffectiveDonate no longer has the poor UX of landing on an error message, so users now correctly reach the login page. &lt;/p&gt;

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

</description>
      <category>heroku</category>
      <category>webdev</category>
      <category>production</category>
      <category>linux</category>
    </item>
    <item>
      <title>Drag and Drop Tables - Rails Backend (Part II)</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Sat, 23 Nov 2019 01:16:00 +0000</pubDate>
      <link>https://forem.com/milandhar/drag-and-drop-tables-rails-backend-part-ii-b55</link>
      <guid>https://forem.com/milandhar/drag-and-drop-tables-rails-backend-part-ii-b55</guid>
      <description>&lt;p&gt;In my &lt;a href="https://dev.to/milandhar/drag-and-drop-table-with-react-beautiful-dnd-54ad"&gt;last post&lt;/a&gt; I described how I used the &lt;a href="https://github.com/atlassian/react-beautiful-dnd" rel="noopener noreferrer"&gt;react-beautiful-dnd&lt;/a&gt; package to make a drag-and-drop Semantic UI Table. By the end of the process, I was able to implement the DnD action to re-order my table's rows. The only problem was that the newly updated order didn't persist on the backend, so if the user refreshed the page, the new order would be lost. Not a good UX! &lt;/p&gt;

&lt;p&gt;So the challenge for this week was to find a way to maintain the new order on the backend so that every time the user refreshes the page, it looks exactly like they'd expect. &lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing the Problem
&lt;/h2&gt;

&lt;p&gt;I recommend looking over &lt;a href="https://dev.to/milandhar/drag-and-drop-table-with-react-beautiful-dnd-54ad"&gt;last week's post&lt;/a&gt; to understand the use case of the React DnD table in my website, &lt;a href="https://mighty-beach-46515.herokuapp.com/" rel="noopener noreferrer"&gt;EffectiveDonate&lt;/a&gt;. I created a button under the "Starred Projects" table to save the user's new order of starred projects once they are done dragging and dropping. Upon clicking this button, I had a skeleton method called &lt;code&gt;saveOrder()&lt;/code&gt; which would &lt;code&gt;POST&lt;/code&gt; the new order to my API endpoint. The task for this week was to actually implement that route on the backend and ensure that every time the "Starred Projects" table populates, it fills in with the correctly ordered projects. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKRyzd9f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FKRyzd9f.png" alt="Screenshot of table with "&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Table with the "Save New Order" button (to be implemented)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Database Changes
&lt;/h3&gt;

&lt;p&gt;Before I could begin implementing the new route on my Rails backend, I had to think about the changes I needed to make to my database's &lt;code&gt;user_starred_projects&lt;/code&gt; table. This table is a join table that only had two attributes: &lt;code&gt;user_id&lt;/code&gt; and &lt;code&gt;project_id&lt;/code&gt;. Previously when a user wanted to add a new project to their stars, it would be created with these two attributes and the next sequential &lt;code&gt;id&lt;/code&gt; primary key. When the user got to their profile page, their projects would be displayed in reverse-chronological order (ascending &lt;code&gt;id&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;In order to allow the starred projects table to be dynamically ordered, I needed to create a new integer attribute in the &lt;code&gt;user_starred_projects&lt;/code&gt; table I called &lt;code&gt;order_number&lt;/code&gt;. I created a migration: &lt;code&gt;rails generate migration add_order_number_to_user_starred_projects order_number:integer&lt;/code&gt; and then a &lt;code&gt;rails db:migrate&lt;/code&gt; to migrate the database to the new schema. &lt;/p&gt;
&lt;h3&gt;
  
  
  Controller Changes
&lt;/h3&gt;

&lt;p&gt;Now that the database was updated with the new &lt;code&gt;order_number&lt;/code&gt; column, it was time to build out this attribute in the &lt;code&gt;UserStarredProjects&lt;/code&gt; controller. I wanted to ensure that each new starred project was given the next sequential order number, so that the first star had an &lt;code&gt;order_number&lt;/code&gt; of 1, and each additional starred project would increment that number. In the &lt;code&gt;create&lt;/code&gt; controller action, I added the following code:&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;number_stars&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UserStarredProject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="vi"&gt;@userStar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;
&lt;span class="vi"&gt;@userStar&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;number_stars&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had an existing method in the &lt;code&gt;UserStarredProjects&lt;/code&gt; controller to remove projects from the user's starred list, but since I had a new &lt;code&gt;order_number&lt;/code&gt; attribute, I needed to consider the impact of removing a starred project on the rest of the list's orders. For example, if there were five projects in a user's starred list and the third one was removed, I would shift the following orders: (4 =&amp;gt; 3, and 5 =&amp;gt; 4). To scale this, I wrote the following code:&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;remove_project&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;project_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:project_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="vi"&gt;@user_project&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UserStarredProject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;project_id: 
    &lt;/span&gt;&lt;span class="n"&gt;project_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;higher_projects&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UserStarredProject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;where&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"order_number &amp;gt; ? AND user_id = 
    ?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="vi"&gt;@user_project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="vi"&gt;@user_project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete&lt;/span&gt;
      &lt;span class="c1"&gt;#Find all the projects with an order_number &amp;gt; @user_project.order_number &lt;/span&gt;
      &lt;span class="c1"&gt;#and decrement them&lt;/span&gt;
      &lt;span class="n"&gt;higher_projects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
        &lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order_number&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;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
      &lt;span class="k"&gt;end&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s1"&gt;'Removed Project'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :accepted&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
      &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;error: &lt;/span&gt;&lt;span class="s1"&gt;'Could Not Remove Project'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :not_acceptable&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 that the removal of a starred project has been handled, the final controller action to implement was the endpoint that is called when the user re-orders their project list and saves the new order on the frontend. In the next section I will go into detail about how I POSTed the order on the frontend, but the order parameter gets sent as an array of the new project IDs (ex: [475, 170, 87]). So in the &lt;code&gt;update_star_orders&lt;/code&gt; controller action, I iterate through this array, look up the &lt;code&gt;UserStarredProject&lt;/code&gt; object that corresponds to its &lt;code&gt;project_id&lt;/code&gt; and then assign it a new incrementing &lt;code&gt;order_number&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update_star_orders&lt;/span&gt;
    &lt;span class="n"&gt;user_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:user_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;order&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;project_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="ss"&gt;:project_array&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;project_array&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;id&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
      &lt;span class="n"&gt;user_star&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UserStarredProject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_by&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;user_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;project_id: &lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="n"&gt;user_star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;order_number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;order&lt;/span&gt;
      &lt;span class="n"&gt;order&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;user_star&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
    &lt;span class="k"&gt;end&lt;/span&gt;
    &lt;span class="n"&gt;render&lt;/span&gt; &lt;span class="ss"&gt;json: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;message: &lt;/span&gt;&lt;span class="s1"&gt;'Updated Order'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="ss"&gt;status: :accepted&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 the database will reflect the correct &lt;code&gt;order_number&lt;/code&gt; for each starred project after the user rearranges their list! &lt;/p&gt;

&lt;h3&gt;
  
  
  Frontend Changes
&lt;/h3&gt;

&lt;p&gt;Now that I had the &lt;code&gt;update_star_orders&lt;/code&gt; endpoint implemented, it was time to write out the &lt;code&gt;fetch&lt;/code&gt; action for the user to persist their new order. I first extract the &lt;code&gt;project.id&lt;/code&gt;s from each &lt;code&gt;project&lt;/code&gt; as an array, and send that array as a parameter to the &lt;code&gt;update_star_orders&lt;/code&gt; endpoint I described in the previous section. Here's how I did it:&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;saveOrder&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="n"&gt;let&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;starredProjects&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;state&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;let&lt;/span&gt; &lt;span class="n"&gt;projectIds&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="sr"&gt;//&lt;/span&gt;&lt;span class="n"&gt;go&lt;/span&gt; &lt;span class="n"&gt;thru&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="n"&gt;objects&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;unshift&lt;/span&gt; &lt;span class="n"&gt;their&lt;/span&gt; &lt;span class="n"&gt;ids&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;the&lt;/span&gt; &lt;span class="n"&gt;empty&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt; 

    &lt;span class="n"&gt;starredProjects&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;projectIds&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unshift&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="sr"&gt;//&lt;/span&gt; &lt;span class="no"&gt;Take&lt;/span&gt; &lt;span class="n"&gt;new&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;starred&lt;/span&gt; &lt;span class="n"&gt;project&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="no"&gt;POST&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;endpoint&lt;/span&gt;

    &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;userid&lt;/span&gt;
    &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`${config.get('API_URL')}/api/v1/update_star_orders`&lt;/span&gt;
    &lt;span class="n"&gt;const&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="ss"&gt;method: &lt;/span&gt;&lt;span class="s1"&gt;'POST'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="ss"&gt;headers: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s1"&gt;'Content-Type'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="ss"&gt;body: &lt;/span&gt;&lt;span class="no"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;project_array: &lt;/span&gt;&lt;span class="n"&gt;projectIds&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&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="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
          &lt;span class="n"&gt;alert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"New order saved!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://i.giphy.com/media/USy5ybVP3WlzYpt13F/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/USy5ybVP3WlzYpt13F/giphy.gif" alt="GIF of persistent DnD table"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The drag-and-drop reorder posted to backend&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Overall, this exercise was a good way to get creative while thinking of a way to persist the list's order on the backend. This process reminded me of solving an algorithm, since there were limitless ways of tackling this problem and many different use cases that it had to meet. It would be an interesting exercise to see what other data structures I could use to optimize time/space efficiency here, and I'd love to explore refactoring this in different ways in the future. But for now, this solution worked and neatly maintains the order of each starred project in the database. &lt;/p&gt;

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

</description>
      <category>rails</category>
      <category>ux</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Drag and Drop Tables with React-Beautiful-DND (Part I)</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Sat, 16 Nov 2019 02:40:51 +0000</pubDate>
      <link>https://forem.com/milandhar/drag-and-drop-table-with-react-beautiful-dnd-54ad</link>
      <guid>https://forem.com/milandhar/drag-and-drop-table-with-react-beautiful-dnd-54ad</guid>
      <description>&lt;p&gt;This week, I wanted to experiment learning a new React component and implementing it into my &lt;a href="http://effectivedonate.herokuapp.com" rel="noopener noreferrer"&gt;EffectiveDonate&lt;/a&gt; website. I began to think of what aspects of the site could use a cool new feature to improve its UX, and focused in on the Profile page. Previously, the Profile page allowed users to update their default themes (Health, Education, etc), and also to view the nonprofit projects that they had starred. The list of projects was organized in a &lt;a href="https://react.semantic-ui.com/collections/table/" rel="noopener noreferrer"&gt;Semantic UI Table&lt;/a&gt;, and enabled users to view key information about the projects, donate to the project, or delete the project from their stars. However, the table was sorted in chronological order, so that the user's most recent starred projects were all the way at the bottom of the table - not the best UX! &lt;/p&gt;

&lt;p&gt;While I could have easily just sorted the table in reverse chronological order as a quick fix, I wanted to give the user some more control. So I started to brainstorm some solutions in React to make the table more dynamic. I found this &lt;a href="https://github.com/brillout/awesome-react-components" rel="noopener noreferrer"&gt;List of Awesome React Components&lt;/a&gt;, and read through a list of several drag and drop components. Drag and drop would be a nice, clean way to let the user customize their starred projects! I eventually chose &lt;a href="https://github.com/atlassian/react-beautiful-dnd" rel="noopener noreferrer"&gt;React Beautiful DnD&lt;/a&gt; - it had over 17k stars on GitHub, a nice instruction video and many examples.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FFlmF3l5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FFlmF3l5.png" alt="Original Profile Page"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The original profile page, with starred projects table in chronological order&lt;/em&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What is React-Beautiful-DnD?
&lt;/h2&gt;

&lt;p&gt;React-Beautiful-DnD is a React package with a goal of creating drag and drop functionality for lists that anyone can use, even people who can't see. The main &lt;a href="https://medium.com/@alexandereardon/rethinking-drag-and-drop-d9f5770b4e6b" rel="noopener noreferrer"&gt;design goal&lt;/a&gt; is physicality - they want users to feel like they are moving objects around by hand. It also has accessibility features, including drag and drop using just the keyboard. &lt;/p&gt;

&lt;p&gt;It also plays nicely with tables, specifically the Semantic UI React Table component, which sealed the deal for me to use it. &lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing React-Beautiful-DnD on my Website
&lt;/h2&gt;

&lt;p&gt;In order to make my &lt;code&gt;StarredProjectsList&lt;/code&gt; component DnD-able, I followed a &lt;a href="https://egghead.io/courses/beautiful-and-accessible-drag-and-drop-with-react-beautiful-dnd" rel="noopener noreferrer"&gt;video course&lt;/a&gt; on react-beautiful-dnd, and referenced this &lt;a href="https://github.com/Frankcarvajal/rbdnd-suir-table/blob/master/src/components/SemanticUIDnDTable.js" rel="noopener noreferrer"&gt;example&lt;/a&gt; of a Semantic UI table component. Also I made sure to install the package with: &lt;code&gt;npm install react-beautiful-dnd --save&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;While I recommend going through the two resources I listed above to thoroughly understand the process for implementing the component in your project, I'll give a few highlights of key components in the API here: &lt;/p&gt;

&lt;h3&gt;
  
  
  DragDropContext
&lt;/h3&gt;

&lt;p&gt;This &lt;a href="https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/drag-drop-context.md" rel="noopener noreferrer"&gt;component&lt;/a&gt; is required to specify which part of your React tree you want to be able to use drag and drop. For me, I wrapped my entire Semantic UI &lt;code&gt;Table&lt;/code&gt; component with &lt;code&gt;&amp;lt;DragDropContext /&amp;gt;&lt;/code&gt;. A required prop for this component is &lt;code&gt;onDragEnd&lt;/code&gt;, a function that dictates how the list or table's state should change once the drag operation is complete. The opening tag for my &lt;code&gt;DragDropContext&lt;/code&gt; is the following: &lt;code&gt;&amp;lt;DragDropContext onDragEnd={this.onDragEnd}&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;The &lt;code&gt;onDragEnd&lt;/code&gt; method finds the index of the starred project I dragged, and splices it into the array of my &lt;code&gt;starredProjects&lt;/code&gt; state. Below is my implementation of the method: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 javascript
  onDragEnd = result =&amp;gt; {
    const { destination, source, reason } = result;

    // Not a thing to do...
    if (!destination || reason === 'CANCEL') {
      this.setState({
        draggingRowId: null,
      });
      return;
    }

    if (
      destination.droppableId === source.droppableId &amp;amp;&amp;amp;
      destination.index === source.index
    ) {
      return;
    }

    const starredProjects = Object.assign([], this.state.starredProjects);
    const project = this.state.starredProjects[source.index];
    starredProjects.splice(source.index, 1);
    starredProjects.splice(destination.index, 0, project);
    this.setState({
      starredProjects
    });
  }


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Droppable
&lt;/h3&gt;

&lt;p&gt;A &lt;a href="https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/droppable.md" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Droppable/&amp;gt;&lt;/code&gt;&lt;/a&gt; is a container for &lt;code&gt;&amp;lt;/Draggable/&amp;gt;&lt;/code&gt; items. It can be dropped on by &lt;code&gt;&amp;lt;/Draggable /&amp;gt;&lt;/code&gt;s. &lt;/p&gt;

&lt;p&gt;The only required prop for &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt;s is a string, &lt;code&gt;droppableId&lt;/code&gt;. I wrapped my &lt;code&gt;&amp;lt;Table.Body/&amp;gt;&lt;/code&gt; in the &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt; component, since that is the container of data on which I will be dragging rows. &lt;/p&gt;
&lt;h3&gt;
  
  
  Draggable
&lt;/h3&gt;

&lt;p&gt;A &lt;a href="https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/draggable.md" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Draggable /&amp;gt;&lt;/code&gt;&lt;/a&gt; is the React component that will actually be dragged around onto &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt;s. It must always be contained by a &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt;, but it can also be moved onto other &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt;s. &lt;/p&gt;

&lt;p&gt;The required props for &lt;code&gt;&amp;lt;Draggable /&amp;gt;&lt;/code&gt;s are: &lt;code&gt;draggableId&lt;/code&gt; and &lt;code&gt;index&lt;/code&gt;. Some important notes on these props: &lt;/p&gt;

&lt;p&gt;1) the &lt;code&gt;draggableId&lt;/code&gt; &lt;em&gt;must&lt;/em&gt; be a string. I initially made mine an integer and was stumped when my table rows couldn't be dragged. But once I added the &lt;code&gt;.toString()&lt;/code&gt; function to the prop, it was all good. &lt;br&gt;
2) the &lt;code&gt;index&lt;/code&gt; prop must be a consecutive integer &lt;code&gt;[1,2,3,etc]&lt;/code&gt;. It also must be unique in each &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Below is a snippet of my code where I wrap each &lt;code&gt;&amp;lt;Table.Row&amp;gt;&lt;/code&gt; in a &lt;code&gt;&amp;lt;Droppable/&amp;gt;&lt;/code&gt; after &lt;code&gt;map&lt;/code&gt;ing each of the starred projects in state:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 javascript
{this.state.starredProjects.map((project, idx) =&amp;gt; {
 return (
     &amp;lt;Draggable
        draggableId={project.id.toString()}
        index={idx}
        key={project.id}
     &amp;gt;
       {(provided, snapshot) =&amp;gt; (
       &amp;lt;Ref innerRef={provided.innerRef}&amp;gt;
         &amp;lt;Table.Row
     ...


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

&lt;/div&gt;
&lt;h2&gt;
  
  
  Children Function
&lt;/h2&gt;

&lt;p&gt;Another quirk about the &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Draggable /&amp;gt;&lt;/code&gt; components is that  their &lt;code&gt;React&lt;/code&gt; child must be a function that requires a &lt;code&gt;ReactNode&lt;/code&gt;. If this child function is not created, the component will error out.  The function contains two arguments: &lt;code&gt;provided&lt;/code&gt; and &lt;code&gt;snapshot&lt;/code&gt;. I recommend reading the documentation for both &lt;a href="https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/draggable.md" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Draggable /&amp;gt;&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/api/droppable.md" rel="noopener noreferrer"&gt;&lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt;&lt;/a&gt; to fully understand what these two arguments do and what props they take.&lt;/p&gt;

&lt;p&gt;Also, the &lt;code&gt;&amp;lt;Draggable /&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt; components require an &lt;code&gt;HTMLElement&lt;/code&gt; to be provided to them. This element can be created using the &lt;code&gt;ref&lt;/code&gt; callback in React or the &lt;a href="https://bit.dev/semantic-org/semantic-ui-react/ref" rel="noopener noreferrer"&gt;'Ref'&lt;/a&gt; Semantic UI Component. This &lt;a href="https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/guides/using-inner-ref.md" rel="noopener noreferrer"&gt;react-beautiful-dnd guide&lt;/a&gt; does a good job of explaining the purpose of the &lt;code&gt;ref&lt;/code&gt; callback and how to avoid any errors. &lt;/p&gt;

&lt;p&gt;For an example of how I used the &lt;code&gt;provided&lt;/code&gt; and &lt;code&gt;snapshot&lt;/code&gt; arguments of the child function, as well as the &lt;code&gt;Ref&lt;/code&gt; Semantic UI Component in my table, here is a snippet of the &lt;code&gt;&amp;lt;Droppable /&amp;gt;&lt;/code&gt; tag: &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 javascript
&amp;lt;Droppable droppableId="table"&amp;gt;
    {(provided, snapshot) =&amp;gt; (
       &amp;lt;Ref innerRef={provided.innerRef}&amp;gt;
          &amp;lt;Table.Body {...provided.droppableProps}&amp;gt;
          ...


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

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/H1vU3P0uSo4isgRKtb/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/H1vU3P0uSo4isgRKtb/giphy.gif" alt="GIF of the working DnD Table"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The working DnD table&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Overall, it was a fun and informative process to implement my Semantic UI Table with react-beautiful-dnd. I enjoyed learning the component's API and it was interesting to work with concepts that were new to me, like the children functions and &lt;code&gt;ref&lt;/code&gt; callbacks. &lt;/p&gt;

&lt;p&gt;I definitely recommend viewing the &lt;a href="https://egghead.io/courses/beautiful-and-accessible-drag-and-drop-with-react-beautiful-dnd" rel="noopener noreferrer"&gt;video course&lt;/a&gt; on react-beautiful-dnd, and also checking out the example code online. You can also reference my &lt;a href="https://github.com/milandhar/mod5-project-frontend/blob/master/src/components/StarredProjectsList.js" rel="noopener noreferrer"&gt;table component file&lt;/a&gt; on GitHub to fully see how I implemented the DnD components. &lt;/p&gt;

&lt;p&gt;While I am satisfied with the UX that is available on the table component now, the next step is to make it persist on the backend so that when the user refreshes the page, the table re-renders in the new order. This should require a bit of creative manipulation on the backend, which I am excited to tackle next week :) &lt;/p&gt;

&lt;p&gt;Thank you for reading and let me know if you have any questions or comments! &lt;/p&gt;

</description>
      <category>react</category>
      <category>npm</category>
      <category>ux</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Using CSS Media Queries</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Thu, 07 Nov 2019 20:39:48 +0000</pubDate>
      <link>https://forem.com/milandhar/using-css-media-queries-2hf3</link>
      <guid>https://forem.com/milandhar/using-css-media-queries-2hf3</guid>
      <description>&lt;p&gt;In this post I will be diving into the important topic of Media Queries in CSS, providing examples of  elements from my own project that needed mobile optimization and how I approached them. In my &lt;a href="https://dev.to/milandhar/responsive-react-components-w-semantic-ui-10cn"&gt;previous post&lt;/a&gt; I covered how to make React components responsive, which allowed me to create a unique user experience for mobile devices. This week's post zooms in to the individual HTML elements within each component that need mobile optimization. I view this process as analogous to responsiveness in React, except it is more manual whereas Semantic UI React has &lt;a href="https://react.semantic-ui.com/addons/responsive/" rel="noopener noreferrer"&gt;special props and components&lt;/a&gt; that do much of the work for us.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.w3schools.com%2Fcss%2Fmqcap.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.w3schools.com%2Fcss%2Fmqcap.JPG" alt="Media Query Image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Media Query?
&lt;/h2&gt;

&lt;p&gt;In CSS, a &lt;a href="https://www.w3schools.com/css/css_rwd_mediaqueries.asp" rel="noopener noreferrer"&gt;media query&lt;/a&gt; uses the &lt;code&gt;@media&lt;/code&gt; rule to include certain CSS properties only if a condition is true. Media queries can check several things, like the width or height of a device, the screen's orientation (landscape or portrait), the screen's resolution, and more. &lt;/p&gt;

&lt;p&gt;The syntax for a media query is the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;mediatype&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediafeature&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="n"&gt;or&lt;/span&gt;&lt;span class="err"&gt;|&lt;/span&gt;&lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;mediafeature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;CSS-Code&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can find all of the different media types and media features at this &lt;a href="https://www.w3schools.com/cssref/css3_pr_mediaquery.asp" rel="noopener noreferrer"&gt;W3Schools page&lt;/a&gt;. I most frequently use the "screen" media type and "max-width" media feature for my responsive web development media queries. &lt;/p&gt;

&lt;p&gt;An example of a type of media query I often use is below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;500px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would change the &lt;code&gt;display&lt;/code&gt; property to &lt;code&gt;block&lt;/code&gt; of the element with class of "container" for screen sizes less than or equal to 500px. &lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Media Queries to My Project
&lt;/h2&gt;

&lt;p&gt;A note on the media feature I used - for most of the media queries, I used a &lt;code&gt;max-width: 767px&lt;/code&gt; feature. I found that setting the breakpoint at 767px max-width allowed me to capture most mobile device sizes (portrait and landscape) for which I needed to adjust CSS properties. I used Chrome DevTools to &lt;a href="https://developers.google.com/web/tools/chrome-devtools/device-mode" rel="noopener noreferrer"&gt;simulate different mobile devices&lt;/a&gt; on my website. I highly recommend using the device mode with DevTools for mobile responsiveness media queries.  &lt;/p&gt;

&lt;p&gt;In my css file, I grouped most of the media queries I wrote for mobile responsiveness in the following block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;767px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in the examples below I have repeated the query each time for clarity. &lt;/p&gt;

&lt;p&gt;Now let's dive into some real examples of how I used media queries to make elements in &lt;a href="https://mighty-beach-46515.herokuapp.com/" rel="noopener noreferrer"&gt;EffectiveDonate&lt;/a&gt; responsive. &lt;/p&gt;

&lt;h3&gt;
  
  
  Stacking Elements Using Flexbox Layout
&lt;/h3&gt;

&lt;p&gt;In the "Projects" page of EffectiveDonate, there are dropdowns for countries and themes, allowing the user to filter the types of projects they want to learn about. On desktop screens, it works to have these dropdowns positioned next to each other. However, once the width of the screen shrinks to mobile sizes, the dropdowns become too small to contain all of the content, and they look awkward: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F0nqgwVn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F0nqgwVn.png" alt="Project Dropdowns"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To solve this on mobile, I wrote a media query that changes the &lt;code&gt;display&lt;/code&gt; to "flex" and also associated properties &lt;code&gt;justify-content&lt;/code&gt; and &lt;code&gt;align-items&lt;/code&gt; to "center". This style of container is called the "Flexbox Layout". You can learn all about Flexbox in this excellent &lt;a href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/" rel="noopener noreferrer"&gt;CSS-Tricks Guide&lt;/a&gt;, which walks you through all of the awesomeness of Flexbox. I enjoy using Flexbox when I can, since it is inherently more responsive than other layouts, and just feels more spatially intuitive to me. &lt;/p&gt;

&lt;p&gt;I also increased the width of both of the dropdowns so that the longer countries and themes could be easily readable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;415px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nc"&gt;.ui.grid&lt;/span&gt; &lt;span class="nc"&gt;.project-dropdown-row&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;flex-direction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.project-dropdown-row&lt;/span&gt; &lt;span class="nc"&gt;.country-drop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;70%&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.project-dropdown-row&lt;/span&gt; &lt;span class="nc"&gt;.themes-drop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;min-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;70%&lt;/span&gt; &lt;span class="cp"&gt;!important&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;Now the dropdowns are cleanly stacked and easy to read! &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FXp4gzMY.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FXp4gzMY.png" alt="Project Dropdowns Fixed"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Make Table Text Wrap
&lt;/h3&gt;

&lt;p&gt;Another component that needed some responsive media queries was my &lt;code&gt;Profile&lt;/code&gt; section. I have a responsive &lt;a href="https://react.semantic-ui.com/collections/table/" rel="noopener noreferrer"&gt;Semantic UI Table&lt;/a&gt; for the user's starred projects that collapses on smaller screens. However, the table's text data would not wrap to the next line, so it cut off key project data on mobile: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F2RVFCJ6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F2RVFCJ6.png" alt="No-wrap table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To fix this, I changed the &lt;code&gt;white-space&lt;/code&gt; and &lt;code&gt;word-wrap&lt;/code&gt; properties in my media query. &lt;code&gt;white-space&lt;/code&gt; was previously set to "nowrap", which forced all text in the table to render on one line. &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/white-space" rel="noopener noreferrer"&gt;Setting it&lt;/a&gt; to "normal" allows text to be broken into multiple lines. Setting &lt;code&gt;word-wrap: break-word&lt;/code&gt; is self explanatory: it &lt;a href="https://www.w3schools.com/cssref/css3_pr_word-wrap.asp" rel="noopener noreferrer"&gt;allows words to be broken up&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I also wanted the red "X" and green "$" buttons to be easier to click on mobile, so I flipped their &lt;code&gt;display&lt;/code&gt; to flex and used &lt;code&gt;justify-content: space-evenly&lt;/code&gt; to spread the buttons out along the container. &lt;/p&gt;

&lt;p&gt;Here are both of the blocks I wrote to solve these issues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;415px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nc"&gt;.ui.table&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;class&lt;/span&gt;&lt;span class="o"&gt;*=&lt;/span&gt;&lt;span class="s1"&gt;"single line"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;white-space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;normal&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;word-wrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;break-word&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;#remove-donate-div&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt; &lt;span class="cp"&gt;!important&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;justify-content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;space-evenly&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;Now the entire table content can actually be viewed and the buttons are spread out enough to be clickable on mobile! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F8n1z8UN.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F8n1z8UN.png" alt="Wrapped table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Centering Content
&lt;/h3&gt;

&lt;p&gt;The final example of media queries I will discuss here is a common one that is frustrating if you don't know a quick trick. The way to center text within a container is fairly straightforward (&lt;code&gt;text-align:center&lt;/code&gt;). But actually horizontally centering an entire container of content is less intuitive. The best way I've learned is to make the &lt;code&gt;margin-left&lt;/code&gt; and &lt;code&gt;margin-right&lt;/code&gt; equal to "auto". This effectively equalizes the space to the left and right of the container, ensuring that it is always centered. This is also very responsive design friendly, since the content will be centered as the viewport shrinks.&lt;/p&gt;

&lt;p&gt;In my Create User Form, I have a checklist of themes the user can choose as their top three favorites. However, each list item was awkwardly positioned left of center: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FMM84eGM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FMM84eGM.png" alt="Uncentered Content"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To horizontally center each theme &lt;code&gt;div&lt;/code&gt;, I used the margin trick:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="n"&gt;and&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;415px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;#fields-div&lt;/span&gt; &lt;span class="nc"&gt;.field&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin-left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;margin-right&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;auto&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="cp"&gt;!important&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;I also set the &lt;code&gt;width&lt;/code&gt; to 100% to ensure the theme text would not wrap. Now the theme checklist is centered and good to go! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FWhSFHuU.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FWhSFHuU.png" alt="Centered Content"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;While the examples I included in this post represent many common use cases for media queries, there are limitless possibilities. I recommend skimming the list of &lt;a href="https://www.w3schools.com/cssref/css3_pr_mediaquery.asp" rel="noopener noreferrer"&gt;Media Features&lt;/a&gt; available just to see the different ways media queries can be used. &lt;/p&gt;

&lt;p&gt;However, now that I've implemented these responsive queries, I feel ready to share &lt;a href="https://mighty-beach-46515.herokuapp.com/" rel="noopener noreferrer"&gt;EffectiveDonate&lt;/a&gt;. Feel free to check it out and let me know if you have any feedback or see any bugs. Thanks for reading! &lt;/p&gt;

</description>
      <category>css</category>
      <category>webdev</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Responsive React Components (w/ Semantic UI)</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Fri, 01 Nov 2019 18:15:19 +0000</pubDate>
      <link>https://forem.com/milandhar/responsive-react-components-w-semantic-ui-10cn</link>
      <guid>https://forem.com/milandhar/responsive-react-components-w-semantic-ui-10cn</guid>
      <description>&lt;p&gt;In this post I'll cover some strategies to make your React application more responsive. I had a specific component in one of my projects that needed to be bypassed in order for my website to be optimal on mobile, and I will go through the steps I took to tackle that issue. Also, my Navbar component (referred to as "Menu" in Semantic UI) needed some work to look good on mobile, so I'll cover the changes I made to that component as well! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jCAhPRAZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/3800/1%2AL8OQ0W5hnsYpGhhABLnkzg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jCAhPRAZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/max/3800/1%2AL8OQ0W5hnsYpGhhABLnkzg.jpeg" alt="Responsive devices" width="880" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Making My Website Responsive
&lt;/h2&gt;

&lt;p&gt;The main page of my nonprofit donation website, EffectiveDonate, is a world map that uses data visualization with the &lt;a href="https://react-d3-library.github.io/"&gt;React D3 Library&lt;/a&gt;. While I was able to make the world map responsive on larger screen sizes using some D3 methods and an event listener for window resize, the map just would not look good on mobile screens. It would either be so zoomed in that the user could only see a few countries at a time, or way too zoomed out and small to click on a particular country. &lt;/p&gt;

&lt;p&gt;Although I liked visually presenting project data through the world map component, I realized that I needed to explore new options to make my website user friendly on mobile. So I decided I would create a new simple landing page for mobile that would replace the map, which would just appear on desktop and tablet screens. The question then was - how do I do that?? &lt;/p&gt;

&lt;h3&gt;
  
  
  Dynamic and Responsive Routing
&lt;/h3&gt;

&lt;p&gt;I initially came across a feature in React called &lt;a href="https://reacttraining.com/react-router/core/guides/philosophy"&gt;Dynamic Routing&lt;/a&gt;. The philosophy is that frameworks like Rails use static routing, where routes are declared before any rendering takes place. React wanted to change this style, so since v4 routing takes place dynamically as the app is rendering. &lt;/p&gt;

&lt;p&gt;React also has a way to make routes responsive to different screen sizes. Similar to CSS media queries, React has a &lt;a href="https://github.com/ReactTraining/react-media"&gt;Media Component&lt;/a&gt; that listens for CSS media query responses and renders components if the query matches. This &lt;a href="https://reacttraining.com/react-router/core/guides/philosophy"&gt;React Training&lt;/a&gt; gives an excellent example of how to dynamically redirect a user to a different component based on a responsive media query. &lt;/p&gt;

&lt;h3&gt;
  
  
  My Approach
&lt;/h3&gt;

&lt;p&gt;Although the Responsive Routing I described above is a clean way to compose routes given different screen sizes, I realized the problem I needed to solve was a bit simpler. The training gave some sound advice: "Think about how to solve the problem with React’s declarative composability because nearly every 'React Router question' is probably a 'React question'". This made me think deeply about which React component I really needed to change to have my desired result on mobile. &lt;/p&gt;

&lt;p&gt;It turns out that my &lt;code&gt;LoginForm&lt;/code&gt; component is where the user gets redirected to the &lt;code&gt;MapBrowser&lt;/code&gt; landing page, so that's where I zoomed in and made some changes. Previously, the user would be redirected to the &lt;code&gt;MapBrowser&lt;/code&gt; page if they were successfully granted a &lt;a href="https://jwt.io/"&gt;jwt token&lt;/a&gt; upon login: &lt;code&gt;this.props.history.push("/map")&lt;/code&gt; This is where I needed to build in some logic to redirect to the mobile landing page on small screens.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wApQg5yt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/nbohMaC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wApQg5yt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/nbohMaC.png" alt="World Map Component" width="880" height="489"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The existing map landing page&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I found a helpful &lt;a href="https://stackoverflow.com/questions/44480053/how-to-detect-if-screen-size-has-changed-to-mobile-in-react"&gt;stackoverflow post&lt;/a&gt; that explained how to detect if the screen has changed to mobile in React. I created a new state in my &lt;code&gt;LoginForm&lt;/code&gt; component called "mobile", and wrote a function that would set the state to true if the screen width is less than 760px:&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;resize&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;currentMobile&lt;/span&gt; &lt;span class="o"&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;innerWidth&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;760&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;currentMobile&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;currentMobile&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;Then, in the &lt;code&gt;componentDidMount()&lt;/code&gt; function, I added an event listener for a window resize and then called &lt;code&gt;resize()&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&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="s2"&gt;resize&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will ensure that whenever the component renders, the screen size will be accurately saved in state. &lt;/p&gt;

&lt;p&gt;Next, in my &lt;code&gt;login()&lt;/code&gt; function's &lt;code&gt;fetch&lt;/code&gt; method, I added the following conditional logic:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mobile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/mobile_landing&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/map&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the user will be redirected to the new &lt;code&gt;mobile_landing&lt;/code&gt; route if they are on a mobile screen at login. Great! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m-KnYzoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/iLZmbUo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m-KnYzoj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/iLZmbUo.png" alt="Mobile Landing Page" width="252" height="486"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;The new mobile landing page&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Updating My Navbar Component
&lt;/h3&gt;

&lt;p&gt;Now that the redirect from login was directed to the correct route on mobile, I had to make some changes to my &lt;code&gt;Navbar&lt;/code&gt; component. I had attempted to use the &lt;a href="https://react.semantic-ui.com/collections/menu/"&gt;Collapsable Menu&lt;/a&gt; React component with Semantic UI, since it is supposed to dynamically collapse on mobile screens, but I wasn't able to get it to look exactly like I wanted it to. Plus, my &lt;code&gt;Navbar&lt;/code&gt; included a "Map" item, which I needed to change to "Select" on mobile, so I knew I had to find a way to customize the component &lt;em&gt;and&lt;/em&gt; make it responsive. &lt;/p&gt;

&lt;p&gt;I found out that the &lt;a href="https://react.semantic-ui.com/collections/grid/#responsive-variations-only"&gt;Grid&lt;/a&gt; Component includes an &lt;code&gt;only&lt;/code&gt; prop that makes a Grid Row visible by adding breakpoints for certain screen sizes. I also wanted to make my mobile Navbar vertical. Semantic UI makes this super easy by just passing a &lt;code&gt;vertical&lt;/code&gt; prop to the &lt;code&gt;Menu&lt;/code&gt; component. &lt;/p&gt;

&lt;p&gt;So now I could write a separate Grid Row that would only be visible for mobile screens, and would redirect to the new mobile landing page instead of the map. Here's a preview of what this separate row looks 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="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Row&lt;/span&gt; &lt;span class="nx"&gt;columns&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mobile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
       &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Grid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Column&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Menu&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;massive&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="nx"&gt;vertical&lt;/span&gt; &lt;span class="nx"&gt;inverted&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt; &lt;span class="nx"&gt;header&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;EffectiveDonate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Menu.Item&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;             &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Menu&lt;/span&gt; &lt;span class="nx"&gt;position&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;right&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
               &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Item&lt;/span&gt;
                 &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;select&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
                 &lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;activeItem&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mobileLanding&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
                 &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                 &lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So now the Navbar is responsive with the items that correspond to the correct routes for mobile / desktop! You can check out the two screenshots of the website above to see the different Navbars that render on different screen sizes. &lt;/p&gt;

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

&lt;p&gt;It took some digging to find the best solutions to make my application responsive, but the approaches I took ended up being much more straightforward than expected. Both React and Semantic UI luckily make responsive design relatively easy with built-in components. &lt;/p&gt;

&lt;p&gt;Although it would have been nice to have a visual map available on mobile as well, I've learned that the simplest solution from a UI perspective is often the best. It would get really messy to try to zoom/scroll in the map without clicking on a country. &lt;/p&gt;

&lt;p&gt;This step felt like a big hurdle to cross in order to make EffectiveDonate fully responsive and ready to distribute more broadly. I still have lots of work to do to make each component mobile friendly, but the trickiest part is now over.&lt;/p&gt;

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

</description>
      <category>react</category>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Functional Testing in Rails</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Thu, 24 Oct 2019 03:41:18 +0000</pubDate>
      <link>https://forem.com/milandhar/functional-testing-in-rails-50kh</link>
      <guid>https://forem.com/milandhar/functional-testing-in-rails-50kh</guid>
      <description>&lt;p&gt;In &lt;a href="https://dev.to/milandhar/unit-testing-in-rails-4oke"&gt;last week's post&lt;/a&gt;, I described how I learned the basics of unit testing and then wrote unit tests for my EffectiveDonate project. As I mentioned in that post, unit tests in Rails deal with testing a model's validations and methods. This week, I will be diving into the concept of functional testing, which in Rails means testing controllers! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbalance3hplus.com%2Fwp-content%2Fuploads%2F2018%2F07%2Ftest-tubes-155769_1280-1024x854.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fbalance3hplus.com%2Fwp-content%2Fuploads%2F2018%2F07%2Ftest-tubes-155769_1280-1024x854.png" alt="Test tubes cartoon"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Functional Testing
&lt;/h2&gt;

&lt;p&gt;In general, &lt;a href="http://softwaretestingfundamentals.com/functional-testing/#targetText=FUNCTIONAL%20TESTING%20is%20a%20type,properly%20satisfied%20by%20the%20application." rel="noopener noreferrer"&gt;functional testing&lt;/a&gt; is a "type of software testing whereby the system is tested against the functional requirements/specifications." These requirements are tested by feeding them sample input based on the function's specifications, determining the output based on the behavior of the program, and then comparing the actual and expected results. This is a chance for developers to ensure that real-world user stories are fulfilled to satisfy the requirements of the application. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://guides.rubyonrails.org/testing.html#functional-tests-for-your-controllers" rel="noopener noreferrer"&gt;Rails' documentation&lt;/a&gt; recommends writing functional tests for the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;was the web request successful?&lt;/li&gt;
&lt;li&gt;was the user redirected to the right page?&lt;/li&gt;
&lt;li&gt;was the user successfully authenticated?&lt;/li&gt;
&lt;li&gt;was the appropriate message displayed to the user in the view?&lt;/li&gt;
&lt;li&gt;was the correct information displayed in the response?&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Functional Testing in Rails
&lt;/h2&gt;

&lt;p&gt;To get started learning about the &lt;code&gt;test&lt;/code&gt; directory that is built-in to Rails applications, refer to the "Test Directory" section in my &lt;a href="https://dev.to/milandhar/unit-testing-in-rails-4oke"&gt;previous blog &lt;/a&gt;. Similar to creation of unit tests for models, running a command like &lt;code&gt;rails generate controller project&lt;/code&gt; will create a file called &lt;code&gt;projects_controller_test.rb&lt;/code&gt; in the &lt;code&gt;test/controllers/&lt;/code&gt; directory. &lt;/p&gt;

&lt;p&gt;In this newly created file, you will see a class declaration like &lt;code&gt;class ProjectsControllerTest &amp;lt; ActionDispatch::IntegrationTest&lt;/code&gt;. Rails has &lt;a href="https://api.rubyonrails.org/classes/ActionController/TestCase.html" rel="noopener noreferrer"&gt;encouraged&lt;/a&gt; the use of its "integration-style" controller tests because they perform actual requests, while the "functional-style" tests in Rails just simulate a request. But for the purposes of this post, I still refer to the tests I wrote as "Functional", following the Rails testing naming convention (although some of them do involve multiple components). &lt;/p&gt;

&lt;h2&gt;
  
  
  Functional Testing My Project
&lt;/h2&gt;

&lt;p&gt;Now that my models for EffectiveDonate have been unit tested, it was time to functionally test my controllers! I used &lt;a href="https://guides.rubyonrails.org/testing.html#functional-tests-for-your-controllers" rel="noopener noreferrer"&gt;Rails' documentation&lt;/a&gt; to learn the syntax for functional testing in the Minitest suite, and would highly recommend reading it to anyone interested. While the assertions for functional testing are similar to those used in unit testing, there are several additional features of functional testing, such as request types (like get, post, put, etc), available instance variables (@controller, @request, @response), and three Hash objects (flash, cookies, and session). &lt;/p&gt;

&lt;p&gt;While I wrote functional tests for more controllers than I've included in this post, some tend to follow the same patterns, and I tried to discuss the ones that were most distinct here. Let's dive into the controllers I tested: &lt;/p&gt;

&lt;h2&gt;
  
  
  Countries Controller
&lt;/h2&gt;

&lt;p&gt;For my first functional test, I wanted to start with a simple request to the index endpoint of the &lt;code&gt;Countries&lt;/code&gt; controller. In the &lt;code&gt;conuntries_controller_test.rb&lt;/code&gt; file, I wrote the following: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
    test "should get index" do
      get "/api/v1/countries"
      assert_response :success
    end


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

&lt;/div&gt;

&lt;p&gt;This test sends a &lt;code&gt;get&lt;/code&gt; request to the "/api/v1/countries" route. The &lt;code&gt;:success&lt;/code&gt; parameter of &lt;code&gt;assert_response&lt;/code&gt; specifies that the test will pass if the response comes back with a status code between 200-299. You can also specify &lt;code&gt;:redirect&lt;/code&gt; (status code between 300-399), &lt;code&gt;:missing&lt;/code&gt; (status code of 404), or &lt;code&gt;:error&lt;/code&gt; (500-599). &lt;/p&gt;

&lt;p&gt;A key function of the &lt;code&gt;Countries&lt;/code&gt; controller is its ability to return the correct number of active projects in each country. Below is the test I wrote for this: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
  test "should get project count" do
      Country.delete_all
      Country.create(name: "Mexico", iso3166CountryCode: "MEX")
      project = Project.new
      project.image_url = "https://files.globalgiving.org/pfil/34796/pict_large.jpg?m=1534281939000"
      project.theme_str_id = "env"
      project.project_link = "https://www.globalgiving.org/projects/nourish-a-young-brain-protect-one-ancient-culture/"
      project.title = "Nourish a Young Brain Protect One Ancient Culture"
      project.save
      mexico = Country.find_by(iso3166CountryCode: "MEX")
      mexico.projects &amp;lt;&amp;lt; project
      get "/api/v1/get_project_count"
      res = JSON.parse(@response.body)
      assert_equal 1, res[0][1]
    end


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

&lt;/div&gt;

&lt;p&gt;This test creates a single &lt;code&gt;Country&lt;/code&gt; object and assigns it a new &lt;code&gt;Project&lt;/code&gt;. Then it sends a request to the "get_project_count" endpoint. The assertion I wrote tests whether the JSON response includes the single project that belongs to Mexico. &lt;/p&gt;

&lt;h2&gt;
  
  
  Users Controller
&lt;/h2&gt;

&lt;p&gt;I next wanted to test my endpoints in the &lt;code&gt;Users&lt;/code&gt; controller, another vital set of functions in EffectiveDonate. The &lt;code&gt;User&lt;/code&gt; actions I will be testing involve things like creating a new user, returning all of a user's saved projects, verifying whether a project has been starred by a user, and updating a user's information. &lt;/p&gt;

&lt;p&gt;Many of the tests in this file will use the following data:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
  user_params = { user:{
    username: "milan123",
    password: "abc123",
    first_name: "Milan",
    last_name: "Dhar",
    default_country: "USA",
    theme1: 14,
    theme2: 15,
    theme3: 16
    }
  }

  project = Project.new
  project.image_url = "https://files.globalgiving.org/pfil/34796/pict_large.jpg?m=1534281939000"
  project.theme_str_id = "env"
  project.project_link = "https://www.globalgiving.org/projects/nourish-a-young-brain-protect-one-ancient-culture/"
  project.title = "Nourish a Young Brain Protect One Ancient Culture"
  project.save


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Creating a New User
&lt;/h3&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
  test "should create new user" do
      post "/api/v1/users", params: user_params.to_json, headers: { "Content-Type": "application/json" }
      assert_response(:success, message = "failed to create user")
    end


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

&lt;/div&gt;

&lt;p&gt;This test will attempt to create a new &lt;code&gt;User&lt;/code&gt; object using the &lt;code&gt;user_params&lt;/code&gt; listed above. If the response is not "success", this test will fail with a message of "failed to create user".&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating a User
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
test "should update user" do
      user = User.create(user_params[:user])
      put "/api/v1/users/#{user.id}", params: {id: user.id, first_name: "Dylan"}.to_json, headers: { "Content-Type": "application/json" }
      res = JSON.parse(@response.body)
      assert_equal 'Dylan', res["first_name"]
   end


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

&lt;/div&gt;

&lt;p&gt;This test sends a new first name as a parameter to the "/users/:user_id" endpoint. It then checks to make sure the &lt;code&gt;first_name&lt;/code&gt; in the response JSON is equal to "Dylan", the new first name. &lt;/p&gt;

&lt;h3&gt;
  
  
  Return All a User's Saved Projects
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
test "should get all user's saved projects" do
      user = User.create(user_params[:user])
      user.projects &amp;lt;&amp;lt; project
      starred_project_params = {user_id: user.id, project_id: project.id}
      post "/api/v1/get_user_projects", params: starred_project_params.to_json, headers: { "Content-Type": "application/json" }
      assert_response(:success, message = "failed to get all projects")
    end


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

&lt;/div&gt;

&lt;p&gt;This test assigns the existing project as a favorite of a new user. It then sends a post request to the "get_user_projects" endpoint, sending the &lt;code&gt;user_id&lt;/code&gt; and &lt;code&gt;project_id&lt;/code&gt; as params. If the response is returned successfully, the test will pass. &lt;/p&gt;

&lt;h3&gt;
  
  
  Verify a Project is Starred
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
test "should verify that a project is starred" do
       User.delete_all
       user = User.new(user_params[:user])
       user.projects &amp;lt;&amp;lt; project
       user.save
       post "/api/v1/check_star", params: {user_id: user.id, project_id: project.id}.to_json, headers: { "Content-Type": "application/json" }
       status_hash = JSON.parse(@response.body)
       assert_equal 'Project is starred.', status_hash["status"]
     end


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

&lt;/div&gt;

&lt;p&gt;This test is similar to the previous one, but it pings the "check_star" endpoint and checks the "status" of the response to ensure that the project has been correctly recognized as "starred". The &lt;code&gt;check_star&lt;/code&gt; method in the &lt;code&gt;Users&lt;/code&gt; Controller includes the following render statement if the project is starred by the user: &lt;code&gt;render json: {status: 'Project is starred.'}&lt;/code&gt;, so the test's response is able to parse out the correct status. &lt;/p&gt;

&lt;h2&gt;
  
  
  Auth Controller
&lt;/h2&gt;

&lt;p&gt;The final controller in EffectiveDonate that I will discuss for testing purposes here is the &lt;code&gt;Auth&lt;/code&gt; controller. This controller's only function is to authorize a user has signed in with the correct credentials, and if so, grant them a &lt;a href="https://jwt.io/" rel="noopener noreferrer"&gt;JWT&lt;/a&gt; so they can proceed to the website. Here is the test I wrote (using the same &lt;code&gt;user_params&lt;/code&gt; as previous tests):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
test "should authorize user on login" do
    user = User.create(user_params[:user])
    post "/api/v1/login", params: user_params.to_json, headers: { "Content-Type": "application/json" }
    assert_response :success, "Incorrectly denied user access"
  end


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

&lt;/div&gt;

&lt;p&gt;This test sends the &lt;code&gt;user_params&lt;/code&gt; to the "/login" endpoint, although it will just check for the username and password of the &lt;code&gt;user&lt;/code&gt;. If the controller function works correctly, it will authorize the user with a jwt token and a successful status code, thus passing the test. &lt;/p&gt;

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

&lt;p&gt;Overall, I found functional tests to be a natural next step from writing unit tests, as they were much more involved and as such, more likely to encounter errors. I made some silly mistakes, like forgetting my route paths started with "/api/v1/", and not converting my parameters to json, but these were good learning experiences. Also, writing these functional tests helped me to understand more deeply how my controllers worked, and to feel more confident that the user experience will be as intended. Thanks for reading! &lt;/p&gt;

</description>
      <category>rails</category>
      <category>ruby</category>
      <category>testing</category>
    </item>
    <item>
      <title>Unit Testing in Rails</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Thu, 17 Oct 2019 19:37:33 +0000</pubDate>
      <link>https://forem.com/milandhar/unit-testing-in-rails-4oke</link>
      <guid>https://forem.com/milandhar/unit-testing-in-rails-4oke</guid>
      <description>&lt;p&gt;For my blog this week, I decided to explore the topic of unit testing in Rails. Throughout my time at the Flatiron School, I completed labs that included &lt;a href="https://en.wikipedia.org/wiki/RSpec" rel="noopener noreferrer"&gt;RSpec&lt;/a&gt; tests to determine if the code was correct. Although I indirectly used hundreds of these RSpec tests, I never quite dove into the topic of writing tests myself. I was always curious how to write my own tests and knew it is an extremely skill to learn for Test-Driven Development (TDD), so I decided I needed to teach myself how to write them! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.typemock.com%2Fwp-content%2Fuploads%2F2018%2F08%2FThe-Business-Case-for-Unit-Testing-part2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.typemock.com%2Fwp-content%2Fuploads%2F2018%2F08%2FThe-Business-Case-for-Unit-Testing-part2.png" alt="Eat, Sleep, Code, Unit Test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit Testing
&lt;/h2&gt;

&lt;p&gt;I wanted to begin my testing journey with the concept of &lt;a href="https://en.wikipedia.org/wiki/Unit_testing" rel="noopener noreferrer"&gt;unit testing&lt;/a&gt;. Broadly speaking, unit testing is a testing method where individual units of source code, program modules, usage procedures, and operating procedures are tested to determine if they are fit for use. They make sure that a section of an application, or a “unit”, is behaving as intended. In a &lt;a href="https://guides.rubyonrails.org/v3.2/testing.html#unit-testing-your-models" rel="noopener noreferrer"&gt;Rails context&lt;/a&gt;, unit tests are what you use to test your models. Although it is possible in Rails to run all tests simultaneously, each unit test case should be tested independently to isolate issues that may arise. The goal of unit testing is to isolate each part of the program and show that the individual parts are correct.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages of Unit Testing
&lt;/h3&gt;

&lt;p&gt;Unit testing has become a standard in many development methods because it encourages well-structured code and good development practices. &lt;a href="https://en.wikipedia.org/wiki/Unit_testing#Advantages" rel="noopener noreferrer"&gt;One advantage&lt;/a&gt; of unit testing is that it finds problems early in the development cycle rather than later. It’s always better to find bugs earlier so that features that are added on later in the cycle are using the correct component parts. Additionally, unit testing forces developers to structure functions and objects in better ways, since poorly written code can be impossible to test. Finally, unit testing provides a living documentation of the system as it is developed. The description of the tests can give an outsider a basic understanding of the unit’s API and its features. &lt;/p&gt;

&lt;h2&gt;
  
  
  The Test Directory
&lt;/h2&gt;

&lt;p&gt;In a normal situation, when creating a new Rails app, you would run the &lt;code&gt;rails new application_name&lt;/code&gt; command after installing Rails. Once the skeleton of the new Rails application has been built, you will see a folder called &lt;code&gt;test&lt;/code&gt; in the root of the new application, and many subfolders and files within the &lt;code&gt;test&lt;/code&gt; directory. For the purposes of this post, I will be focusing on adding tests to the &lt;code&gt;models&lt;/code&gt; directory, since unit testing in Rails primarily involves testing models. However, if you are interested in learning about the other directories within the "test" folder (such as &lt;code&gt;helpers&lt;/code&gt;, &lt;code&gt;channels&lt;/code&gt;, &lt;code&gt;controllers&lt;/code&gt;, etc), you can do so &lt;a href="https://guides.rubyonrails.org/testing.html#rails-sets-up-for-testing-from-the-word-go" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Rails automatically adds new test files to the &lt;code&gt;models&lt;/code&gt; directory when new models are generated. So if you were to run a &lt;code&gt;rails generate model User&lt;/code&gt;, Rails would add a &lt;code&gt;user_test.rb&lt;/code&gt; file in the &lt;code&gt;test/models&lt;/code&gt; directory. The unit tests will be written in these files for each model. &lt;/p&gt;

&lt;h2&gt;
  
  
  Unit Testing My Project
&lt;/h2&gt;

&lt;p&gt;I decided a good place to start practicing unit testing would be my project called EffectiveDonate, a nonprofit donation website. I originally developed this project without any tests, and it has a fairly complicated Rails backend with many models, so there was a plethora of features I could test. &lt;/p&gt;

&lt;p&gt;It was slightly more work to add in the tests at this point, since I initially ran the &lt;code&gt;rails new&lt;/code&gt; command without adding tests. I ended up just creating a new blank project with the test directory, and then dragging it into the root of my EffectiveDonate backend. Then I added files for the models that I wanted to test into the &lt;code&gt;models&lt;/code&gt; directory, such as &lt;code&gt;project_test.rb&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To learn how to unit test my models, I followed the &lt;strong&gt;&lt;a href="https://guides.rubyonrails.org/v3.2/testing.html#unit-testing-your-models" rel="noopener noreferrer"&gt;Rails Guides for Unit Testing Models&lt;/a&gt;&lt;/strong&gt;. I won't repeat all the information I read there, but I would highly recommend reading it since it is an excellent resource for how to write Rails testing code, testing terminology, how to prepare your app for testing, running tests, and test assertions. An important piece of advice in the documentation is to include a test for everything which could possibly break. And that it is a best practice to have at least one test for each of your validations and at least one test for every method in your model. So with that framework, I began writing tests!&lt;/p&gt;

&lt;h3&gt;
  
  
  Project Model
&lt;/h3&gt;

&lt;p&gt;The most complex model in my backend for EffectiveDonate is the &lt;code&gt;Project&lt;/code&gt; model. This model has several has_many / belongs_to associations with other models, and the primary call to the external API (GlobalGiving) that feeds all the data in my project happens in this model. &lt;/p&gt;

&lt;p&gt;But as I began writing tests for the &lt;code&gt;Project&lt;/code&gt; model, I realized I didn't have any validations! So theoretically it would be possible for a &lt;code&gt;Project&lt;/code&gt; instance to be created without having key attributes like a title or images. While GlobalGiving's API generally has very clean data, I want to make sure all the &lt;code&gt;Project&lt;/code&gt; data in my app has the attributes I need. So I went ahead and wrote the following validations:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
  validates :title, presence: true
  validates :image_url, presence: true
  validates :project_link, presence: true
  validates :theme_str_id, presence: true


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

&lt;/div&gt;

&lt;p&gt;These will ensure that &lt;code&gt;Project&lt;/code&gt;s without these attributes will not be saved. &lt;/p&gt;

&lt;p&gt;Now it was time to test these validations. In my &lt;code&gt;test/models/project_test.rb&lt;/code&gt; file, I had the following class set up:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
require 'test_helper'

class ProjectTest &amp;lt; ActiveSupport::TestCase
  test "the truth" do
    assert true
  end
end 


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

&lt;/div&gt;

&lt;p&gt;This is the skeleton that Rails adds for each model that is generated. The "the truth" test is an example test that will always pass and allows you to verify that your Test class is up and running. In Rails testing, assertions are the most important part of the test. They actually perform the checks to make sure things are going as planned. The example test above will pass because it just ensures that the argument in the assertion (&lt;code&gt;true&lt;/code&gt;) is true. There are &lt;a href="https://guides.rubyonrails.org/v3.2/testing.html#assertions-available" rel="noopener noreferrer"&gt;many other types of assertions&lt;/a&gt; that you get for free with Rails unit tests, each with their own purpose. &lt;/p&gt;

&lt;p&gt;In order to test my new &lt;code&gt;Project&lt;/code&gt; validations, I wrote similar tests for each validation. Each test created a new &lt;code&gt;Project&lt;/code&gt;, then assigned the projects all of the other required attributes, except for the one that I am testing for. Then I wrote an &lt;code&gt;assert_not&lt;/code&gt; to ensure that the &lt;code&gt;Project&lt;/code&gt; would not save without the missing attribute. &lt;/p&gt;

&lt;p&gt;For example, here is my validation for my test to ensure a &lt;code&gt;Project&lt;/code&gt; will not save without a title: &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
test "should not save a project without a title" do
    project = Project.new
    project.image_url = "https://files.globalgiving.org/pfil/34796/pict_large.jpg?m=1534281939000"
    project.theme_str_id = "env"
    project.project_link = "https://www.globalgiving.org/projects/nourish-a-young-brain-protect-one-ancient-culture/"
    assert_not project.save, "Saved the project without a title"
  end


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

&lt;/div&gt;

&lt;p&gt;If I ran the test and the new &lt;code&gt;project&lt;/code&gt; instance did get saved, I would know there was a problem with my validation, and would receive the message in the argument of the assertion: "Saved the project without a title". &lt;/p&gt;

&lt;p&gt;To test the other methods in my &lt;code&gt;Project&lt;/code&gt; model, I wrote different tests. These methods perform the fetches from the GlobalGiving API, and return JSONs with the project data. I used the &lt;code&gt;assert_nothing_raised&lt;/code&gt; assertion to ensure my &lt;code&gt;queryActiveProjects&lt;/code&gt; method runs without raising an error (this will ensure the API endpoint and my credentials are correct):&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
  test "should query the active projects API endpoint without error" do
    assert_nothing_raised do
      Project.queryActiveProjects(nextProject:nil)
    end
  end


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

&lt;/div&gt;

&lt;p&gt;I also wanted to ensure that the JSON returned by this method has attributes that the application needs, such as &lt;code&gt;nextProjectId&lt;/code&gt;, and that the JSON includes a &lt;code&gt;project&lt;/code&gt; object with a valid &lt;code&gt;id&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
    test "should return a json of projects that has a next project ID" do
      assert Project.queryActiveProjects(nextProject:nil)["projects"]["nextProjectId"]
    end

    test "should return a json of projects whose first project has an ID" do
      assert Project.queryActiveProjects(nextProject:nil)["projects"]["project"].first["id"]
    end


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

&lt;/div&gt;

&lt;p&gt;These tests use &lt;code&gt;assert&lt;/code&gt; to validate that both of these attributes exist.&lt;/p&gt;

&lt;h3&gt;
  
  
  Country Model
&lt;/h3&gt;

&lt;p&gt;My &lt;code&gt;Country&lt;/code&gt; model includes similar API fetch methods to &lt;code&gt;Project&lt;/code&gt; above, so I wrote a similar unit test using &lt;code&gt;assert_nothing_raised&lt;/code&gt;. I also wrote a test to ensure that my &lt;code&gt;create_all&lt;/code&gt; method actually creates &lt;code&gt;Country&lt;/code&gt; instances:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
 ruby
test "should create countries" do
    Country.delete_all
    Country.create_all
    assert_not_equal Country.all.count, 0, "Didn't create any countries"
  end


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

&lt;/div&gt;

&lt;p&gt;Here I used &lt;code&gt;assert_not_equal&lt;/code&gt; to ensure that the number of &lt;code&gt;Country&lt;/code&gt;s created was greater than 0. &lt;/p&gt;

&lt;h3&gt;
  
  
  User Model
&lt;/h3&gt;

&lt;p&gt;My &lt;code&gt;User&lt;/code&gt; model already included a validation to ensure that a &lt;code&gt;User&lt;/code&gt; cannot create a profile with the same &lt;code&gt;username&lt;/code&gt; as someone else: &lt;code&gt;validates :username, uniqueness: { case_sensitive: false }&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To test this, I created one &lt;code&gt;User&lt;/code&gt; and then used an &lt;code&gt;assert_not&lt;/code&gt; to ensure that a second &lt;code&gt;User&lt;/code&gt; with the same username could not be saved:&lt;/p&gt;

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

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"should not allow duplicate user names"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;user1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&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;username: &lt;/span&gt;&lt;span class="s2"&gt;"barryobama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s2"&gt;"bo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;username: &lt;/span&gt;&lt;span class="s2"&gt;"barryobama"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s2"&gt;"michelle"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
    &lt;span class="n"&gt;assert_not&lt;/span&gt; &lt;span class="n"&gt;user2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"Saved a duplicate user name"&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 &lt;code&gt;user2&lt;/code&gt; was able to be saved, the test would fail and I would see the message "Saved a duplicate user name". &lt;/p&gt;

&lt;h3&gt;
  
  
  User Starred Project Model
&lt;/h3&gt;

&lt;p&gt;The final model in EffectiveDonate that I needed to test was &lt;code&gt;User_Starred_Project&lt;/code&gt;. A user should not be able to star the same project multiple times, so I had already added the following validation to the model: &lt;code&gt;validates :user_id, uniqueness: {scope: :project_id}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In order to test this validation, I created a new &lt;code&gt;User&lt;/code&gt; and a valid &lt;code&gt;Project&lt;/code&gt; with all the required attributes. I then successfully created one instance of &lt;code&gt;UserStarredProject&lt;/code&gt; using the &lt;code&gt;id&lt;/code&gt; of both the &lt;code&gt;User&lt;/code&gt; and &lt;code&gt;Project&lt;/code&gt; that I created. I then attempted to save a duplicate &lt;code&gt;UserStarredProject&lt;/code&gt;, using &lt;code&gt;assert_not&lt;/code&gt; to ensure that it would not save: &lt;/p&gt;

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

  &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="s2"&gt;"should prevent a user from starring multiple projects"&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
    &lt;span class="n"&gt;user1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;User&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;username: &lt;/span&gt;&lt;span class="s2"&gt;"barryobama10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;password: &lt;/span&gt;&lt;span class="s2"&gt;"bo"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;project1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
    &lt;span class="n"&gt;project1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;title&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Nourish a young brain, protect one ancient culture"&lt;/span&gt;
    &lt;span class="n"&gt;project1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;theme_str_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"env"&lt;/span&gt;
    &lt;span class="n"&gt;project1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;image_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"www.google.com/img"&lt;/span&gt;
    &lt;span class="n"&gt;project1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;project_link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"https://www.globalgiving.org/projects/nourish-a-young-brain-protect-one-ancient-culture/"&lt;/span&gt;
    &lt;span class="n"&gt;project1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;
    &lt;span class="n"&gt;user_star_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UserStarredProject&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;project_id: &lt;/span&gt;&lt;span class="n"&gt;project1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;user1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;user_star_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UserStarredProject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;project_id: &lt;/span&gt;&lt;span class="n"&gt;project1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ss"&gt;user_id: &lt;/span&gt;&lt;span class="n"&gt;user1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;assert_not&lt;/span&gt; &lt;span class="n"&gt;user_star_2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"User starred a duplicate project"&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 there was a problem in my validation, I would see the message "User starred a duplicate project", and the test would fail. &lt;/p&gt;

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

&lt;p&gt;Ultimately, this process of learning about unit testing and testing my own project's models was very helpful. For some reason, testing seemed like an intimidating skill to learn, but I realized it is actually not too difficult once you get started. I also am starting to understand its importance to maintaining well-organized and clean code. I probably wouldn't have added all of those validations to my &lt;code&gt;Project&lt;/code&gt; model unless I started to test it, so my app is already more resilient to bad data than it was before. Also, the tests I wrote to check the API calls will be really helpful to ensure that my API credentials are still valid and that the endpoints I am reaching are correct.&lt;/p&gt;

&lt;p&gt;I am looking forward to exploring more facets of testing in the near future, so stay tuned for more testing-related posts. Until next time! &lt;/p&gt;

</description>
      <category>rails</category>
      <category>testing</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Using Heroku Scheduler</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Mon, 07 Oct 2019 21:34:35 +0000</pubDate>
      <link>https://forem.com/milandhar/using-heroku-scheduler-1ei9</link>
      <guid>https://forem.com/milandhar/using-heroku-scheduler-1ei9</guid>
      <description>&lt;p&gt;It's been a few months since my last post, and am excited to begin posting again!&lt;/p&gt;

&lt;p&gt;Following my completion of EffectiveDonate, a nonprofit discovery website I developed for my capstone project, it was time to publicly deploy it. I've had experience deploying other projects I built at the Flatiron School to Heroku (a cloud platform service), so I decided to go with Heroku again for EffectiveDonate. However there were a few additional features of Heroku I needed to use for the first time since I was working with API data that I needed to refresh regularly, requiring me to schedule a job to run daily. Let me tell you how I did it! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sgvjmUWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.pexels.com/photos/359989/pexels-photo-359989.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26dpr%3D2%26h%3D650%26w%3D940" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sgvjmUWA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://images.pexels.com/photos/359989/pexels-photo-359989.jpeg%3Fauto%3Dcompress%26cs%3Dtinysrgb%26dpr%3D2%26h%3D650%26w%3D940" alt="Clock" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are Heroku Add-ons?
&lt;/h2&gt;

&lt;p&gt;According to &lt;a href="https://devcenter.heroku.com/articles/add-ons"&gt;Heroku&lt;/a&gt;, add-ons are components that support your application, such as data storage, monitoring, analytics, data processing, and more. Add-ons are managed either by third-parties or by Heroku itself. The purpose of add-ons is to allow developers to focus on the maintenance of their own code and to outsource the services supporting production to the add-ons. &lt;/p&gt;

&lt;p&gt;You can install add-ons either through the CLI or the Heroku Dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Heroku Scheduler
&lt;/h2&gt;

&lt;p&gt;My EffectiveDonate site uses project data from the GlobalGiving API, and I have a method on my Rails backend to fetch new projects. However, these projects are dynamic - they are active only until their funding goal hasn't been reached, and then they stop taking donations. New projects are also started daily. Additionally, project funding amounts are constantly changing. As a result, I need to fetch project data daily regularly from the API to prevent stale data from reaching my application. &lt;/p&gt;

&lt;p&gt;I researched several ways of automating query jobs, both with &lt;code&gt;npm&lt;/code&gt; packages and Ruby &lt;code&gt;gems&lt;/code&gt;, but I finally came across Heroku Scheduler, which turned out to be much more straightforward than those other methods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devcenter.heroku.com/articles/scheduler"&gt;Heroku Scheduler&lt;/a&gt; is a free add-on that allows you to automatically run jobs at scheduled intervals (daily, hourly, etc). &lt;/p&gt;

&lt;p&gt;To install Heroku Scheduler, simply run &lt;code&gt;heroku addons:create scheduler:standard&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a scheduled task
&lt;/h3&gt;

&lt;p&gt;In Rails, the convention is to create a &lt;code&gt;rake&lt;/code&gt; task file in the &lt;code&gt;lib/tasks/&lt;/code&gt; directory. &lt;br&gt;
Below are the tasks that I have written in my &lt;code&gt;scheduler.rake&lt;/code&gt; file:&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;desc&lt;/span&gt; &lt;span class="s2"&gt;"This task is called by the Heroku scheduler add-on"&lt;/span&gt;
&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:fetch_projects&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Deleting Tables..."&lt;/span&gt;
  &lt;span class="no"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_all&lt;/span&gt;
  &lt;span class="no"&gt;UserStarredProject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_all&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"done."&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Fetching Projects..."&lt;/span&gt;
  &lt;span class="no"&gt;Project&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;nextProject: &lt;/span&gt;&lt;span class="kp"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"done."&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;task&lt;/span&gt; &lt;span class="ss"&gt;:fetch_countries&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="ss"&gt;:environment&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Deleting Countries..."&lt;/span&gt;
  &lt;span class="no"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;delete_all&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"Fetching Countries... "&lt;/span&gt;
  &lt;span class="no"&gt;Country&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_all&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"done."&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, the &lt;code&gt;fetch_projects&lt;/code&gt; task is the one that I will be adding to Heroku Scheduler to run regularly. It completes the actions of deleting the existing &lt;code&gt;Project&lt;/code&gt;s and fetches new &lt;code&gt;Project&lt;/code&gt;s from the GlobalGiving API. &lt;/p&gt;

&lt;p&gt;After making sure the task is working locally and pushing it to Heroku, I can test that it is also functioning correctly on Heroku by running &lt;code&gt;heroku run rake fetch_projects&lt;/code&gt;. If it's working right then it will work on Heroku Scheduler!&lt;/p&gt;

&lt;h3&gt;
  
  
  Scheduling Jobs
&lt;/h3&gt;

&lt;p&gt;To get your rake task up on Heroku Scheduler, either open Scheduler in your &lt;a href="https://dashboard.heroku.com/apps"&gt;app dashboard&lt;/a&gt; or the following command: &lt;code&gt;heroku addons:open scheduler&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;On the Scheduler dashboard, you can add and edit jobs. Jobs can be scheduled to run daily, hourly, or every 10 minutes. Next, you enter the task that the scheduler should run. In my case it was &lt;code&gt;rake fetch_projects&lt;/code&gt;. Then just hit "Save Job", and it will start running when the next scheduled time is reached! &lt;/p&gt;

&lt;p&gt;Below is what my scheduled job looks like:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KNgWFFbO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/uM8gso4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KNgWFFbO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/uM8gso4.png" alt="Scheduler add jobs" width="394" height="670"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Too much data!!
&lt;/h3&gt;

&lt;p&gt;After I scheduled my &lt;code&gt;fetch_projects&lt;/code&gt; job, everything seemed to be going fine and the databases began to populate. However, I checked my email, and saw a message with the shocking subject: "[warning] Database disruption imminent, row limit exceeded for hobby-dev database on Heroku app". That didn't sound good! I did some digging, and sure enough, I had over 45,000 rows in my app's Postgres database, while the limit for Heroku's Hobby-dev plan is 10,000 rows. I could either 1) upgrade to a &lt;a href="https://devcenter.heroku.com/articles/upgrading-heroku-postgres-databases?c=&amp;amp;utm_campaign=postgreslimits&amp;amp;utm_medium=telex&amp;amp;utm_source=nurture&amp;amp;utm_content=devcenter&amp;amp;utm_term=upgrade-c#upgrading-with-pg-copy"&gt;higher database plan&lt;/a&gt; or 2) reduce the number of rows in my database. &lt;/p&gt;

&lt;p&gt;Since I still need to build some more features in EffectiveDonate before I can start sharing it broadly, I decided to go with option 2 for now, and eventually I can always upgrade my database plan. This required a slight refactor in my database structure to avoid a join table that was adding multiple rows for each of the thousands of &lt;code&gt;Project&lt;/code&gt; objects that I was creating. &lt;/p&gt;

&lt;p&gt;Another useful tip I learned to prevent a scheduled job from continuing to run was a special CLI command. You can view all processes that are currently running on your Heroku app with &lt;code&gt;heroku ps&lt;/code&gt;. If your scheduled task is running, you will be able to see its associated process id. Then you can stop it using &lt;code&gt;heroku ps:stop &amp;lt;process id from heroku ps&amp;gt;&lt;/code&gt;, for example &lt;code&gt;heroku ps:stop run.8359&lt;br&gt;
&lt;/code&gt;. This is an invaluable tool to use if you see that your database is fast approaching the 10,000 row limit, then you can stop the rake task's runaway train! &lt;/p&gt;

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

&lt;p&gt;As you can see, the Heroku Scheduler add-on is an extremely powerful tool that can automate API fetches, or any other task that needs to be run regularly in your app. I love the Scheduler's easy-to-use interface and how nicely it plays with Rails' rake tasks. Now that I have my row count consistently under 10,000, my scheduled job has been running smoothly and there haven't been any more alarming emails reaching my inbox :) &lt;/p&gt;

&lt;h4&gt;
  
  
  Additional resources used in this blog:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/7743039/killing-abandoned-process-on-heroku"&gt;https://stackoverflow.com/questions/7743039/killing-abandoned-process-on-heroku&lt;/a&gt;&lt;/p&gt;

</description>
      <category>heroku</category>
      <category>deployment</category>
      <category>cloud</category>
    </item>
    <item>
      <title>China's Social Credit System</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Wed, 03 Jul 2019 22:42:46 +0000</pubDate>
      <link>https://forem.com/milandhar/china-s-social-credit-system-22b0</link>
      <guid>https://forem.com/milandhar/china-s-social-credit-system-22b0</guid>
      <description>&lt;p&gt;Now that we are approaching the end of our time at the Flatiron School, we have started to focus more on writing algorithms to practice for technical interviews.  I've found that practicing algorithms has been a good challenge - I enjoy the puzzle-solving aspect to them and it works a more mathematical part of the mind than Web Development areas. It can definitely be frustrating at times, especially when I don't even know how to get started, but solving a tough algorithm has been one of the more rewarding aspects of my software development journey thus far. &lt;/p&gt;

&lt;p&gt;For this post, I wanted to broach a more controversial subject that involves a government implementing an algorithm at massive scale. I've been both fascinated and concerned by the intersection of technology and society over the past few years, so this topic caught my attention immediately. The issue at hand is China's development of its &lt;strong&gt;Social Credit System&lt;/strong&gt; (社会信用体系). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0vu8oviwgy2da3wb29c.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe0vu8oviwgy2da3wb29c.gif" alt="Face Recognition GIF" width="168" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What is the Social Credit System?
&lt;/h2&gt;

&lt;p&gt;The system is intended to standardize the socioeconomic reputation of both businesses and individuals, or &lt;a href="https://en.wikipedia.org/wiki/Social_Credit_System" rel="noopener noreferrer"&gt;"Social Credit"&lt;/a&gt;. By 2020, all social credit scores for China's 1.4 billion people will be publically available. Since China's economy and living standards have skyrocketed in the past decades, it hasn't been able to develop the type of credit scores we are used to in the West. This allowed for people to default on loans or businesses to use shady practices without much backlash. The social credit system is an attempt to answer the question of who to trust. The &lt;a href="https://time.com/collection/davos-2019/5502592/china-social-credit-score/" rel="noopener noreferrer"&gt;guidance for the system&lt;/a&gt; called for a nationwide system that would allow the trustworthy to roam everywhere under heaven, while making it hard for the discredited to take a single step.”&lt;/p&gt;

&lt;p&gt;While the system is planned to launch in 2020, several Chinese companies have been licensed to start trials of social credit systems and develop the software and algorithms to calculate credit. The most prominent of these include Sesame Credit (owned by Alibaba) and Didi Chuxing (China's largest ride-sharing service). Sesame's pilot system determines a social credit rating from &lt;a href="https://time.com/collection/davos-2019/5502592/china-social-credit-score/" rel="noopener noreferrer"&gt;350 - 950 &lt;/a&gt; based on "a thousand variables across five data sets". &lt;/p&gt;

&lt;h2&gt;
  
  
  What are the Scoring Factors?
&lt;/h2&gt;

&lt;p&gt;Similar to credit scores, one's social credit rating can slide up and down based on their personal behavior. However, that is where the similarities end. &lt;/p&gt;

&lt;p&gt;China's government agencies and companies are &lt;a href="https://www.forbes.com/sites/bernardmarr/2019/01/21/chinese-social-credit-score-utopian-big-data-bliss-or-black-mirror-on-steroids/#72f5616e48b8" rel="noopener noreferrer"&gt;collecting massive amounts of data &lt;/a&gt; on its citizens, like social media activity, health records, and online purchases. Combined with its 200 million hidden cameras and facial recognition software, China's social tracking infrastructure makes it an unsettlingly perfect place for a social credit system. &lt;/p&gt;

&lt;p&gt;The precise factors that the algorithm will use are secret, but some &lt;a href="https://www.businessinsider.com/china-social-credit-system-punishments-and-rewards-explained-2018-4" rel="noopener noreferrer"&gt;examples of infractions&lt;/a&gt; are bad driving, smoking in non-smoking zones, playing too many video games, and posting fake news. Examples of &lt;a href="https://www.youtube.com/watch?v=Dkw15LkZ_Kw" rel="noopener noreferrer"&gt;actions that would boost your score&lt;/a&gt; include purchasing diapers for a child, donating to charity, turning in a lost wallet, or picking up garbage. &lt;/p&gt;

&lt;h2&gt;
  
  
  How will a Social Credit Score be Used?
&lt;/h2&gt;

&lt;p&gt;At this point, you may be wondering how the social credit system will end up affecting Chinese citizens' daily lives. How could playing too much PS4 impact their rights? The answer is: significantly.&lt;/p&gt;

&lt;p&gt;If individuals have &lt;a href="https://www.forbes.com/sites/bernardmarr/2019/01/21/chinese-social-credit-score-utopian-big-data-bliss-or-black-mirror-on-steroids/#72f5616e48b8" rel="noopener noreferrer"&gt;higher social credit scores&lt;/a&gt;, they enjoy lower energy bills, improved visibility on dating websites, and may rent things without a deposit. Chinese hospitals are also experimenting with social credit scores - enabling people with higher scores to skip a line and receive treatment immediately. &lt;/p&gt;

&lt;p&gt;If someone has a low score, they may find it harder to purchase luxury goods, rent/buy a house, find a job, or purchase a train/plane ticket. Others may find it difficult to enroll their children in their desired school, may be publicly shamed at movie theaters, could have their internet speeds throttled, or have their &lt;a href="https://www.businessinsider.com/china-social-credit-system-punishments-and-rewards-explained-2018-4#1-banning-you-from-flying-or-getting-the-train-1" rel="noopener noreferrer"&gt;dog taken away&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Reflections
&lt;/h2&gt;

&lt;p&gt;If all this sounds exactly like an episode of Black Mirror to you, that's because it is! The series 3 episode "Nosedive" explored this precise scenario. In this world, people rate each other from 1-5 stars for every interaction they have. One's current score can be seen by the public, causing an intense obsession by the episode's protagonist regarding her own score. I found this episode poignantly captures the phenomenon of social media obsession while also painting a haunting picture of future autocratic regimes' uses of big data.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xvsgzen8m31tkbf7c6l.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xvsgzen8m31tkbf7c6l.gif" alt="Black Mirror Gif" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I remember this episode was especially ominous to me, even though it wasn't as terrifying as many of the show's other episodes. It really brought out the worst of social media and how it plays into the human mind's intense desire for status and acceptance. It also seemed so plausible in real life given how ubiquitous social media and data tracking have gotten. When I heard that China was developing a similar system, it was clear to me that the future is now. I think that democratic governments like the US must get ahead of this and enact legislation both to restrict itself and private corporations from immorally collecting data on its citizens. Otherwise the dystopia presented by Black Mirror and the reality of China's social credit system could reach without us knowing it.&lt;/p&gt;

&lt;p&gt;Another aspect of China's system that shocked me was how supportive people are of it - &lt;a href="https://www.merics.org/en/blog/chinas-social-credit-systems-are-highly-popular-now" rel="noopener noreferrer"&gt;a survey shows that 80% of respondents either somewhat or strongly approve&lt;/a&gt; of social credit systems. This statistic made me realize that coming from a Western context, the idea of a social credit system seems Orwellian and completely backwards. However, Chinese citizens are closely aware that the government has been tracking them for years, and in a way this system merely digitizes the practice. Also the system will likely promote good behavior and dissuade people and businesses from stealing and committing fraud, so it is understandable that people could support it. &lt;/p&gt;

&lt;p&gt;Finally, researching China's developing system further reinforced to me how powerful big data and algorithms can be. To think that a country of 1.4 billion people could have their rights controlled by an algorithm is mind blowing to me. It really makes the importance of ethical technologists and policy leaders even more pressing in the years and decades to come. &lt;/p&gt;

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

</description>
      <category>algorithms</category>
      <category>bigdata</category>
      <category>china</category>
      <category>social</category>
    </item>
    <item>
      <title>Chrome Local Storage in Extensions</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Mon, 24 Jun 2019 22:20:21 +0000</pubDate>
      <link>https://forem.com/milandhar/chrome-local-storage-in-extensions-4k9m</link>
      <guid>https://forem.com/milandhar/chrome-local-storage-in-extensions-4k9m</guid>
      <description>&lt;p&gt;For my Javascript project at Flatiron School's Web Development course, my partner and I decided to build a Chrome extension. When we got the project requirement, we wanted to create something that we would actually use, and also learn about a new area that we hadn't yet explored. Since we often find ourselves needing to remind ourselves to take a break, we decided to make a break timer extension!&lt;/p&gt;

&lt;p&gt;While we knew creating an extension would be a different challenge than other Javascript projects we'd worked on, we underestimated how difficult it would be to make the app's data persist for a sufficient amount of time. The beauty of Chrome extensions is that they allow users to access a minimal app on their toolbar, opening and closing it whenever they want. However even a straightforward challenge like a break timer was tough, since clicking away from the extension effectively kills the Javascript session, wiping away all regular variable data. &lt;/p&gt;

&lt;p&gt;Luckily, Chrome provides its own chrome.storage API that helps solve this problem, making developing extensions feasible.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Local Storage?
&lt;/h2&gt;

&lt;p&gt;So far at the Flatiron School, we've been exposed to some browser-storage methods such as cookies and sessions in a Rails context. The &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API"&gt;Web Storage API&lt;/a&gt; contains two mechanisms: localStorage and sessionStorage. LocalStorage is &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage"&gt;similar to sessionStorage&lt;/a&gt; in that they are both read-only, but data stored in localStorage has no expiration time, while sessionStorage gets cleared every time the page session ends (the tab is closed). &lt;/p&gt;

&lt;p&gt;Since localStorage is persistent among multiple page sessions, it is the ideal option for saving Chrome extension data, allowing users to click off and on the extension to their heart's content. &lt;/p&gt;

&lt;h2&gt;
  
  
  Using Chrome's Local Storage in Your Extension
&lt;/h2&gt;

&lt;p&gt;Google has developed its own &lt;a href="https://developer.chrome.com/extensions/storage"&gt;chrome.storage API&lt;/a&gt; that provides the same storage capacity as the Web Storage API. One thing to keep in mind when using chrome.storage is that the storage space is not encrypted, so confidential customer data should not be stored. &lt;/p&gt;

&lt;p&gt;There are a few steps you must take and things to keep in mind when implementing Chrome's storage in your extension: &lt;/p&gt;

&lt;h3&gt;
  
  
  Manifest
&lt;/h3&gt;

&lt;p&gt;Every Chrome extension has a &lt;a href="https://developer.chrome.com/extensions/manifest"&gt;manifest file&lt;/a&gt; called &lt;code&gt;manifest.json&lt;/code&gt; which describes the app and provides important metadata such as its name, scripts, permissions and version. If you want to use chrome storage, you must declare the "storage" permission to your &lt;code&gt;manifest.json&lt;/code&gt; file. Here is a snippet from our extension:&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="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&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;break alarm&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;version&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;1.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;description&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;Be more productive.&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;permissions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;alarms&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;declarativeContent&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;storage&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;&amp;lt;all_urls&amp;gt;&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;background&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;scripts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;helpers.js&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;background.js&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;persistent&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Storage.sync
&lt;/h3&gt;

&lt;p&gt;One key difference between Chrome's storage API and the Web Storage API is that Chrome offers a &lt;code&gt;storage.sync&lt;/code&gt; mechanism that allows user data to be automatically synced with Chrome sync. This would allow a user to access their data on a different device, assuming they have Chrome Sync enabled on their account. &lt;br&gt;
So when developing your extension, you will need to decide whether you want to use &lt;code&gt;storage.local&lt;/code&gt; or &lt;code&gt;storage.sync&lt;/code&gt;. We decided to use &lt;code&gt;storage.local&lt;/code&gt; for our break timer extension. The main difference between the two is the storage limit: &lt;code&gt;storage.local&lt;/code&gt; offers about 5.2MB of data while &lt;code&gt;storage.sync&lt;/code&gt;'s limit is about 102KB, with maximum number of items stored of 512. A nice feature of &lt;code&gt;storage.sync&lt;/code&gt; is that even if the user has disabled Chrome Sync, it will still work and just behave like &lt;code&gt;storage.local&lt;/code&gt;. &lt;/p&gt;
&lt;h3&gt;
  
  
  Asynchronous Calling
&lt;/h3&gt;

&lt;p&gt;Another cool feature of chrome.storage is that all of its calls are asynchronous, while the localStorage in the Web Storage API is called synchronously. While in our project I found the process of getting every locally stored variable asynchronously to be annoying at times, this mechanism allows extensions to run much faster. &lt;/p&gt;

&lt;p&gt;Setting a new object in chrome.storage is relatively straightforward. In our break timer extension, when the user clicked the "resume" button, we would set the following in local storage:&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;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;isPaused&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="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_name&lt;/span&gt;&lt;span class="dl"&gt;'&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;user_name&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;phone_number&lt;/span&gt;&lt;span class="dl"&gt;'&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;phone_number&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redirect_url&lt;/span&gt;&lt;span class="dl"&gt;'&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;default_url&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;break_time&lt;/span&gt;&lt;span class="dl"&gt;'&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;default_break_time&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When calling saved objects from chrome.storage, we can use a bulk async &lt;code&gt;get&lt;/code&gt; function that will access multiple objects at once. Here's an example from our break timer extension:&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;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_name&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;phone_number&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;redirect_url&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;break_time&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;isPaused&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;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;h1&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;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user_name&lt;/span&gt;
    &lt;span class="nx"&gt;timerInput&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;break_time&lt;/span&gt;
    &lt;span class="nx"&gt;urlInput&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect_url&lt;/span&gt;
    &lt;span class="nx"&gt;phoneInput&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="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phone_number&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isPaused&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;updateCountdown&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nx"&gt;countdownInterval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updateCountdown&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;isNotPausedDisplay&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;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pausedCount&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;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;counterElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;secToMin&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;pausedCount&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="nx"&gt;isPausedDisplay&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;h3&gt;
  
  
  Removing Items from Chrome Storage
&lt;/h3&gt;

&lt;p&gt;In order to make full use of chrome.storage, it is important to understand how and when to remove stored data. In our timer extension, we had user data stored such as their preferred break time, their preferred "work" url, and their phone number for timer alerts. We wanted to persist the user's data while they were logged in so that they could set several timers and didn't have to re-enter all their settings if they returned to the extension. However when they log out, we want to remove the user's stored data from chrome.storage so that another user could log in on the same machine. &lt;/p&gt;

&lt;p&gt;Luckily, chrome.storage makes it easy to do this! Chrome offers both a &lt;code&gt;chrome.storage.local.remove&lt;/code&gt; function that lets you specify which key(s) you would like to remove, and a &lt;code&gt;chrome.storage.local.clear&lt;/code&gt; function that will clear all data stored in the extension's local storage. Both functions have optional callback function parameters that will return on success or failure (and then runtime.lastError will be set). &lt;/p&gt;

&lt;p&gt;Since in our extension, we wanted to remove all the user's data once they logged out of the app, we wrote a method that used the clear function with an error-catching callback:&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;function&lt;/span&gt; &lt;span class="nx"&gt;clearLocalStorage&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;storage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;local&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clear&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;chrome&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastError&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;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;console&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;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;})&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;p&gt;Overall, chrome.storage was an indispensable tool to ensure that our extension ran correctly and persisted the user data that we wanted. While building an extension seemed daunting at first, with so many new files and specifications, learning how to use chrome.storage made things so much easier. I would highly recommend heading over to &lt;a href="https://developer.chrome.com/extensions"&gt;Chrome's extensions documentation&lt;/a&gt; when developing your first extension, it is very helpful and concise. &lt;/p&gt;

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

</description>
      <category>javascript</category>
      <category>chrome</category>
      <category>extensions</category>
      <category>api</category>
    </item>
    <item>
      <title>The Benefits of Pair Programming</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Wed, 12 Jun 2019 21:40:11 +0000</pubDate>
      <link>https://forem.com/milandhar/the-benefits-of-pair-programming-470h</link>
      <guid>https://forem.com/milandhar/the-benefits-of-pair-programming-470h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;"It is the long history of humankind (and animal kind, too) that those who learned to collaborate and improvise most effectively have prevailed." – Charles Darwin &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One aspect of my time at the Flatiron School that I have greatly enjoyed has been getting to program with other members of my cohort. The curriculum includes both smaller "pairing labs" that last a few hours and larger pair projects that span four to five days. Both styles have given me a taste of what it will be like to work in a team development environment, and also have been immensely beneficial to my learning and fluency with many concepts. It has been interesting to work with people of different personality types and technical strengths. Pair programming also has challenged the stereotypical image I used to have of engineers locking themselves in a dark room alone with a can of Mountain Dew at 2am. &lt;/p&gt;

&lt;p&gt;While these pairing labs and projects have been great so far, I've found myself interested in how to optimize my own efficiency and performance when working in pairs. I have also wondered whether pair programming has been proven to be more effective than individual work. These questions have led me to conduct additional research on the topic of pair programming, which resulted in this blog! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3hWAtgMt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thumbs.gfycat.com/EntireDistantFlyingfish-size_restricted.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3hWAtgMt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://thumbs.gfycat.com/EntireDistantFlyingfish-size_restricted.gif" alt="Office Space Gif" width="500" height="335"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What is Pair Programming?
&lt;/h1&gt;

&lt;p&gt;At a basic level, pair programming is the agile technique of two people sitting side by side while developing software on one computer. In most pair programming scenarios, one programmer (the driver) writes code while the other (the navigator) reviews each line as it's typed. While at face value it seems that this practice is a waste of resources since it is requiring two people to complete a task that one &lt;em&gt;could&lt;/em&gt; do, studies have shown that pair programming has a significant impact on engineering and organizational effectiveness.  &lt;/p&gt;

&lt;h2&gt;
  
  
  Economics of Pair Programming
&lt;/h2&gt;

&lt;p&gt;In a &lt;a href="https://collaboration.csc.ncsu.edu/laurie/Papers/XPSardinia.PDF"&gt;study at the University of Utah&lt;/a&gt;, students with no exposure to pair programming were assigned three tasks to complete in pairs, with 1/3 of students working on their own as a control group. As you can see from the graph below, after the adjustment period shown in first program, the paired students only spent about 15% more time than the individual students.  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AoCtQN3f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2ADUS6MPMwq_7cS8PMUQF35Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AoCtQN3f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1200/1%2ADUS6MPMwq_7cS8PMUQF35Q.png" alt="time comparison graph" width="644" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Offsetting the increased man-hours spent on pair programming, the code produced by the pairs had about 15% fewer defects than the individually developed code (see graph below). Since the average bug takes between four and 16 hours to resolve, the benefit of pair programming to reduced bugs would outweigh the cost of additional man-hours in most projects. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0HzTI15g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://ai2-s2-public.s3.amazonaws.com/figures/2017-08-08/731a6c7310be8ed0f8f281850b0b8322014a643a/2-Figure2-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0HzTI15g--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://ai2-s2-public.s3.amazonaws.com/figures/2017-08-08/731a6c7310be8ed0f8f281850b0b8322014a643a/2-Figure2-1.png" alt="defects comparison graph" width="648" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Satisfaction
&lt;/h2&gt;

&lt;p&gt;Having never heard of pair programming before starting at Flatiron, I was initially skeptical when I discovered we would be doing so much of our work in pairs. I thought it would hinder my learning to watch someone else do the work 50% of the time, and was worried that communication would be difficult. However, this uncertainty has gradually faded as we have progressed through the curriculum and gotten more practice working in pairs. &lt;/p&gt;

&lt;p&gt;The study at University of Utah reflected a similar sentiment among new pair programmers. The graph below shows the results of surveys of both the student pair programmers and professional pair programmers. It is clear that most of the programmers preferred to work collaboratively. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h__kHbLd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.researchgate.net/profile/Alistair_Cockburn/publication/2333697/figure/fig1/AS:334438278942720%401456747707636/Pair-Enjoyment-A-programmer-comments-It-is-psychologically-soothing-to-be-sure-that.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h__kHbLd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://www.researchgate.net/profile/Alistair_Cockburn/publication/2333697/figure/fig1/AS:334438278942720%401456747707636/Pair-Enjoyment-A-programmer-comments-It-is-psychologically-soothing-to-be-sure-that.png" alt="satisfaction comparison graph" width="465" height="287"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Design Quality
&lt;/h2&gt;

&lt;p&gt;Another effect of pair programming is an improved design quality of the resulting program. In the University of Utah study, the paired programmers finished their projects with a higher quality than the individuals and also implemented the same functionality as the individuals with fewer lines of code.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aGpoCNwe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AOmZRbGuLp0DOYwIpcggI2Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aGpoCNwe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/800/1%2AOmZRbGuLp0DOYwIpcggI2Q.png" alt="design comparison graph" width="662" height="406"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Styles of Pair Programming
&lt;/h1&gt;

&lt;p&gt;There are several styles of pair programming that fit different scenarios and levels of experience between the teammates. &lt;/p&gt;

&lt;h2&gt;
  
  
  Driver-Navigator
&lt;/h2&gt;

&lt;p&gt;Driver-navigator is likely the most widely-used style of pair programming. The analogy is relatively clear: one member of the pair acts as the "driver", doing the typing, ensuring the mechanics of the code are in place and any obstacles are avoided; the other member plays the part of the "navigator", checking for mistakes, and thinking big picture about what goals must be accomplished and the overall architecture of the project. &lt;/p&gt;

&lt;p&gt;The driver-navigator style works well with either two experts or an expert-novice pair. In this situation it is best for the expert to be the navigator and the novice to be the driver, to prevent the novice from merely observing while the expert assumes both roles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backseat Navigator
&lt;/h2&gt;

&lt;p&gt;This style is similar to driver-navigator, but the navigator takes over more of the tactical roles from the driver. In backseat navigation, the driver still handles the keyboard and typing, but the navigator dictates syntactical instructions, such as what name to call a variable or what specific method to call.&lt;/p&gt;

&lt;p&gt;The backseat navigator style works best with a novice as the driver and expert as the navigator, allowing the novice to learn by doing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ping Pong Pairing
&lt;/h2&gt;

&lt;p&gt;Another style of pair programming that is often use in development is ping pong pairing. In this pattern, the first person writes a test that is currently failing, and the second person gets the test to pass. Then the second person writes a failing test and the first person gets it to pass. &lt;/p&gt;

&lt;p&gt;The benefits of ping pong pairing are that it enables roles to switch frequently and forces engineers to pay attention to both the coding and testing aspects of development, gaining familiarity with TDD in the process.  This style of pairing works best with two experts, especially if they are also experts in TDD. But it can also work well with novice-expert pairing, and novice-novice pairing, to give beginners practice with writing tests. &lt;/p&gt;

&lt;h2&gt;
  
  
  Distributed Pairing
&lt;/h2&gt;

&lt;p&gt;This is still more of an unofficial style of pairing, but it is likely the future of pair programming. As more development workspaces shift towards remote and global environments, and screen sharing technology becomes ubiquitous, distributed pairing continues to grow in prevalence. &lt;/p&gt;

&lt;p&gt;Distributed pair programming involves both individuals working via a real-time collaborative editor, shared desktop, or remote IDE plugin. Distributed pair programming benefits from the flexibility of being in separate locations, but introduces new difficulties that come with the loss of in-person communication. This can make remembering which programmer has the role of driver ambiguous at times. &lt;/p&gt;

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

&lt;p&gt;Ultimately, it has been inspiring to learn and experience how much pair programming has been emphasized both at Flatiron and the larger developer community. I look forward to continuing to refine my pair programming skills and learn from my colleagues!&lt;/p&gt;

&lt;h4&gt;
  
  
  Sources I referenced in this post:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Pair_programming"&gt;https://en.wikipedia.org/wiki/Pair_programming&lt;/a&gt;&lt;br&gt;
&lt;a href="https://collaboration.csc.ncsu.edu/laurie/Papers/XPSardinia.PDF"&gt;https://collaboration.csc.ncsu.edu/laurie/Papers/XPSardinia.PDF&lt;/a&gt;&lt;br&gt;
&lt;a href="https://stackify.com/pair-programming-styles/"&gt;https://stackify.com/pair-programming-styles/&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/@weblab_tech/pair-programming-guide-a76ca43ff389"&gt;https://medium.com/@weblab_tech/pair-programming-guide-a76ca43ff389&lt;/a&gt;&lt;/p&gt;

</description>
      <category>pairprogramming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How To Select a Relational Database Management System</title>
      <dc:creator>milandhar</dc:creator>
      <pubDate>Mon, 03 Jun 2019 20:15:17 +0000</pubDate>
      <link>https://forem.com/milandhar/how-to-select-a-database-management-system-5006</link>
      <guid>https://forem.com/milandhar/how-to-select-a-database-management-system-5006</guid>
      <description>&lt;p&gt;At end of my 6th week at Flatiron School's Web Development course, my partner and I had &lt;em&gt;finally&lt;/em&gt; completed our &lt;a href="https://damp-garden-35705.herokuapp.com/login" rel="noopener noreferrer"&gt;Caribbean Stud Poker Rails Project&lt;/a&gt; and were ready to deploy it to Heroku. However, we had started our project using a SQLite database instead of using PostgreSQL, which ended up causing a frustrating (but not insurmountable) problem. Heroku, it turns out, is not compatible with SQLite. While we were eventually able to migrate our sqlite3 database over to postgres and deploy to Heroku, it was not immediately clear to me why the database migration was necessary, or even what the differences were between the two Database Management Systems (DBMs)'s. I think this topic will prove even more relevant as we continue developing more complex websites, which is why I wanted to learn more about it! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/aQCCNezRpb9Hq/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/aQCCNezRpb9Hq/giphy.gif" alt="Database Gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Database Terminology
&lt;/h1&gt;

&lt;p&gt;While this seems like a basic topic - I've noticed the terms "database" and "database management system" used interchangeably, and it's important to get these right. &lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;database&lt;/strong&gt; is an organized collection of data, generally stored and accessed electronically from a computer system. For example, the file 'development.sqlite3' in the above image is a database that stores valuable information for our poker app in tables like Users, Cards, Hands, etc. &lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;database management system&lt;/strong&gt; (DBMS) is the software that interacts with end users, applications, and the database itself to capture and analyze the data (run queries). In our poker example, we initially used the SQLite DBMS and then migrated to PostgreSQL. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SQL&lt;/strong&gt; is a domain-specific language designed for managing data held in a relational database management system. This is the language that we use to actually create our tables and store, manipulate and read our poker game data. &lt;/p&gt;

&lt;h1&gt;
  
  
  Types of DBMS's
&lt;/h1&gt;

&lt;p&gt;Another topic that initially confused me was why there was a need for multiple DBMS's. Wouldn't it be better if there just be one that worked for every use case? Maybe, but it turns out that different types of projects are best suited to different DBMS's based on their storage, speed, and functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  SQLite
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftableplus.io%2Fassets%2Fimages%2Fsqlite-vs-postgresql%2Fsqlite-works.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftableplus.io%2Fassets%2Fimages%2Fsqlite-vs-postgresql%2Fsqlite-works.jpg" alt="Embedded Database"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Embedded Database&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;According to its website, SQLite is described as &lt;a href="https://www.sqlite.org/serverless.html" rel="noopener noreferrer"&gt;"serverless"&lt;/a&gt;, which is different from most DMBS's. Usually, a program that wants to access a database can communicate with the server to send requests and receive data back. SQLite skips the intermediate server process and requires programs to read and write directly from the saved database file.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Advantages of SQLite
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;A serverless DBMS avoids the administrative need to install, setup, configure, initialize, manage, and troubleshoot a server process. This makes it easier to integrate with an application. &lt;/li&gt;
&lt;li&gt;SQLite allows multiple applications to access the same database simultaneously (rare for serverless DBMS's).&lt;/li&gt;
&lt;li&gt;Unsurprisingly, SQLite's library is very lightweight. And the entire database is stored in one file, making it extremely portable. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Disadvantages of SQLite
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Being serverless makes it harder to provide protection from bugs and corrupted memory in the client application. &lt;/li&gt;
&lt;li&gt;Even though it can host multiple applications at the same time, only one process can make changes to a SQLite database at one time. &lt;/li&gt;
&lt;li&gt;SQLite does not have a user management system that give users defined access privileges to the database. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  When to use SQLite
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Embedded applications like mobile applications, game consoles, televisions, airplanes, drones, watches, and robots (the internet of things).&lt;/li&gt;
&lt;li&gt;Testing. Includes an in-memory mode that can run tests without the overhead of actual database operations. &lt;/li&gt;
&lt;li&gt;Working with small amounts of data. The SQLite &lt;a href="https://www.sqlite.org/whentouse.html" rel="noopener noreferrer"&gt;website&lt;/a&gt; recommends that any database approaching 1TB be housed on a centralized client-server database.&lt;/li&gt;
&lt;li&gt;Only require 1 writer at a time.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  PostgreSQL
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftableplus.io%2Fassets%2Fimages%2Fsqlite-vs-postgresql%2Fpostgresql-works.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ftableplus.io%2Fassets%2Fimages%2Fsqlite-vs-postgresql%2Fpostgresql-works.jpg" alt="Client-Server Model"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Client-Server Model&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;PostgreSQL labels itself as "The World's Most Advanced Open Source Relational Database", and uses a client-server model requiring a DB server to set up and run over the network, as opposed to SQLite's serverless model. In the client-server &lt;a href="https://www.postgresql.org/docs/9.0/tutorial-arch.html" rel="noopener noreferrer"&gt;architecture&lt;/a&gt;, each sessions consists of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A server process, which manages the database files, accepts connections to the database from client applications, and performs database actions for the client. The database server is called &lt;code&gt;postgres&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;The user' clients application that performs database operations. These client applications could be anything from a web server to a graphical application to a special database maintenance tool.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Postgres server can handle multiple simultaneous connections from different clients, which is a huge strength. For each new connection, the server "forks" a new server process, and then the client and new server process can communicate without intervention by the original &lt;code&gt;postgres&lt;/code&gt; process.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Advantages of PostgreSQL
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Postgres is very compliant to SQL standards.&lt;/li&gt;
&lt;li&gt;It is an open source project and community driven.
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Disadvantages of PostgreSQL
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Since it forks a new process for every new client connection, it has poor memory performance (each new process is allotted about 10MB of memory).&lt;/li&gt;
&lt;li&gt;It is less popular than other client-server DBMS's like MySQL, meaning there aren't as many third-party tools to help manager a Postgres DB. &lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  When to use PostgreSQL
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Need to integrate the DB with other tools. Postgres is compatible with numerous other programming languages and platforms. So if you ever need to migrate your database to fit with a different tool, Postgres is a great option. &lt;/li&gt;
&lt;li&gt;Using complex operations such as data warehousing and online transaction processing. &lt;/li&gt;
&lt;li&gt;Your project doesn't require the fastest read speed. &lt;/li&gt;
&lt;li&gt;You are interested in optimizing data integrity. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fmo7vuqY.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fmo7vuqY.png" alt="Imgur"&gt;&lt;/a&gt; &lt;br&gt;
&lt;em&gt;Our un-deployable sqlite3 file&lt;/em&gt;&lt;/p&gt;
&lt;h1&gt;
  
  
  Migrating from SQLite to Postgres
&lt;/h1&gt;

&lt;p&gt;Based on the factors detailed in the section above, it is understandable that a cloud-based platform like Heroku would require a client-server DBMS like Postgres  to maintain data consistency and not the disk-backed storage provided by SQLite. &lt;/p&gt;

&lt;p&gt;Since Rails has SQLite installed by default and we used an sqlite3 database for our Poker project, we had to migrate our DB to Postgres in order to deploy to Heroku. Here is what we did:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Remove the following line in the &lt;code&gt;Gemfile&lt;/code&gt;:&lt;br&gt;
&lt;code&gt;gem 'sqlite3'&lt;/code&gt;&lt;br&gt;
and replace it with &lt;br&gt;
&lt;code&gt;gem 'pg'&lt;/code&gt;.  Then run &lt;code&gt;bundle install&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next, convert the &lt;code&gt;config/database.yml&lt;/code&gt; file. Replace the adaptor lines that read &lt;code&gt;adapter: sqlite3&lt;/code&gt; to &lt;code&gt;adapter: postgresql&lt;/code&gt;. Also, change the &lt;code&gt;database:&lt;/code&gt; to a custom line.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;After changing the &lt;code&gt;Gemfile&lt;/code&gt; and the &lt;code&gt;config/database.yml&lt;/code&gt;, you will have to create and migrate your new Postgres database:&lt;br&gt;
&lt;/p&gt;

&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ rake db:create
$ rake db:migrate
&lt;/code&gt;&lt;/pre&gt;




&lt;/li&gt;

&lt;li&gt;&lt;p&gt;Finally, just run a &lt;code&gt;git add .&lt;/code&gt; and &lt;code&gt;git commit -m "postgres"&lt;/code&gt;, and you will all set up with your Postgres DB. At this point you can &lt;a href="https://devcenter.heroku.com/articles/git" rel="noopener noreferrer"&gt;deploy your project to Heroku with git&lt;/a&gt;, if that is your end goal.&lt;/p&gt;&lt;/li&gt;

&lt;/ol&gt;

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

&lt;p&gt;Hopefully this post was able to detail some of the main differences between two widely-used DBMS's (PostgreSQL and SQLite), and will help you select an optimal DBMS for your next project. Feel free to add any questions or comments below! &lt;/p&gt;

&lt;h5&gt;
  
  
  Apart from the inline links, I used the following references in this post:
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Database" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Database&lt;/a&gt;&lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/SQL" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/SQL&lt;/a&gt;&lt;br&gt;
&lt;a href="https://www.digitalocean.com/community/tutorials/sqlite-vs-mysql-vs-postgresql-a-comparison-of-relational-database-management-systems" rel="noopener noreferrer"&gt;https://www.digitalocean.com/community/tutorials/sqlite-vs-mysql-vs-postgresql-a-comparison-of-relational-database-management-systems&lt;/a&gt;&lt;br&gt;
&lt;a href="https://devcenter.heroku.com/articles/sqlite3" rel="noopener noreferrer"&gt;https://devcenter.heroku.com/articles/sqlite3&lt;/a&gt;&lt;/p&gt;

</description>
      <category>sql</category>
      <category>sqlite</category>
      <category>postgres</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
