<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>CoderJourney</title>
    <link>https://coderjourney.com/</link>
    <description>Recent content on CoderJourney</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>keith@coderjourney.com (Keith Thompson)</managingEditor>
    <webMaster>keith@coderjourney.com (Keith Thompson)</webMaster>
    <lastBuildDate>Sun, 25 Feb 2018 00:00:00 -0500</lastBuildDate>
    
        <atom:link href="https://coderjourney.com/index.xml" rel="self" type="application/rss+xml" />
    
    
    <item>
      <title>Kubernetes Frontend Service with Nginx</title>
      <link>https://coderjourney.com/kubernetes-frontend-service-with-nginx/</link>
      <pubDate>Wed, 12 Apr 2017 02:30:15 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/kubernetes-frontend-service-with-nginx/</guid>
      <description>

&lt;p&gt;With both Rails and Postgres running smoothly in your Kubernetes cluster it&amp;rsquo;s time for you to create a frontend service to handle the web requests. In this tutorial, we&amp;rsquo;ll walk through what it looks like for us to set up Nginx as the frontend service for our Rails application.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/MyStCEmAYsg&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goals&#34;&gt;Goals:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create Nginx Deployment/Service&lt;/strong&gt; in front of Rails&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understand why a separate frontend vs backend&lt;/strong&gt; is good.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you went through the Ruby on Rails series then you&amp;rsquo;ve already worked a little with having Nginx in front of your Rails application, but today we&amp;rsquo;re going to translate that over to working with Kubernetes.&lt;/p&gt;

&lt;p&gt;Before we get started, if you&amp;rsquo;ve stoped and restarted minikube and you attempt to connect to the &lt;code&gt;mealplan&lt;/code&gt; service in your browser you&amp;rsquo;ll be met with this error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;An unhandled low-level error occurred. The application logs may have details.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Not the way we wanted to start this tutorial.&lt;/p&gt;

&lt;h2 id=&#34;fixing-the-postgres-persistence-layer-for-minikube&#34;&gt;Fixing the Postgres Persistence Layer for Minikube&lt;/h2&gt;

&lt;p&gt;This is caused by an oversite when we created the PersistentVolumeClaim in the previous tutorial. Our database was removed sadly. The reason that we lost our database after spinning down the minikube was because we mapped our PersistentVolumeClaim to the wrong directory in our &lt;code&gt;postgres&lt;/code&gt; container. We pointed to &lt;code&gt;/var/lib/postgresql/db-data&lt;/code&gt;, but the &lt;code&gt;PGDATA&lt;/code&gt; directory is actually at &lt;code&gt;/var/lib/postgresql/data&lt;/code&gt;. Let&amp;rsquo;s delete what currently exists so that we can patch it up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl delete -f deployments/postgres.yml
service &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; deleted
deployment &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; deleted
persistentvolumeclaim &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres-pv-claim&amp;#34;&lt;/span&gt; deleted&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We removed them entirely since we working locally, obviously, if we made this sort of mistake in a non-development set up we would probably do something more graceful. In addition to mapping our directory incorrectly there is also an issue with where we&amp;rsquo;re storing the data on the minikube VM. By default, new PersistentVolumes with minikube store their data in &lt;code&gt;/tmp/hostpath-provider&lt;/code&gt; and &lt;a href=&#34;https://github.com/kubernetes/minikube#persistent-volumes&#34;&gt;it isn&amp;rsquo;t supposed to be removed&lt;/a&gt;, but at the time of writing this it was being removed when we run &lt;code&gt;minikube stop&lt;/code&gt;. Because of this issue we&amp;rsquo;re going to manually create a PersistentVolume that stores the data under &lt;code&gt;/data/&lt;/code&gt; which does indeed persist between minikube starts.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;deployments/postgres.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Skipping the Service portion of the file&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;extensions/v1beta1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Deployment&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;template&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;labels&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;containers&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres:9.6.2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;env&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_USER&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_user&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_PASSWORD&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_password&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;containerPort&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;5432&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;volumeMounts&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-storage&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;mountPath&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/var/lib/postgresql/data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-storage&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;persistentVolumeClaim&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;claimName&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-pv-claim&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;---&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;v1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;PersistentVolumeClaim&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-pv-claim&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;accessModes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ReadWriteOnce&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;resources&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;requests&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;storage&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;5Gi&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;volumeName&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-pv&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;---&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;v1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;PersistentVolume&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-pv&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;accessModes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ReadWriteOnce&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;capacity&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;storage&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;5Gi&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;hostPath&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;path&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/data/mealplan-postgres&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can bring up all of these objects and recreate our database (your pod ID will be different):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl create -f deployments/postgres.yml
service &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; created
deployment &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; created
persistentvolumeclaim &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres-pv-claim&amp;#34;&lt;/span&gt; created
persistentvolume &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres-pv&amp;#34;&lt;/span&gt; created
$ kubectl &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; mealplan-4029866644-1srx8 --stdin --tty -- bundle &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; rake db:setup db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the database is back and we don&amp;rsquo;t have to worry about it getting deleted again.&lt;/p&gt;

&lt;h2 id=&#34;building-the-nginx-image&#34;&gt;Building the Nginx Image&lt;/h2&gt;

&lt;p&gt;If we think about the services that we have already, Rails &amp;amp; Postgres, they are both what we would call &amp;ldquo;backend&amp;rdquo; services. They aren&amp;rsquo;t really meant to be directly exposed to the web because that&amp;rsquo;s not where they shine. The Rails application&amp;rsquo;s main purpose is to handle the creation of recipes and meal plans, not serving static assets (stylesheets, javascript, etc.). For this reason, we want to put a more specialized tool in front, our &amp;ldquo;frontend&amp;rdquo; server, which in this case is going to be Nginx.&lt;/p&gt;

&lt;p&gt;Thankfully, &lt;a href=&#34;https://github.com/coderjourney/meal_plan/tree/postgres-in-kubernetes&#34;&gt;our project&lt;/a&gt; already has a Nginx configuration in the form of the &lt;code&gt;site.conf&lt;/code&gt; file. Let&amp;rsquo;s take a look at that and see what we will need to change to make it work with Kubernetes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;site.conf&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;kn&#34;&gt;listen&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Properly server assets
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;~&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;^/(assets)/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/usr/share/nginx/html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;gzip_static&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;expires&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Cache-Control&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;ETag&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Proxy request to rails app
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Host&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;X-Forwarded-For&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_pass_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Set-Cookie&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_pass&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;http://prod_app:3000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This looks pretty good, though we&amp;rsquo;re going to need to make will be changing &lt;code&gt;prod_app&lt;/code&gt; to be the name of the service for our Rails application. We&amp;rsquo;ll also add an &lt;code&gt;upstream&lt;/code&gt; block that we can use later. Here&amp;rsquo;s the modified file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;k&#34;&gt;upstream&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;mealplan&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;kn&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;mealplan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;kn&#34;&gt;listen&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Properly server assets
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;~&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;^/(assets)/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/usr/share/nginx/html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;gzip_static&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;expires&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Cache-Control&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;ETag&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Proxy request to rails app
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Host&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;X-Forwarded-For&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_pass_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Set-Cookie&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_pass&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;http://mealplan:3000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Unlike how you may have deployed this if you followed along in the Ruby on Rails series, we&amp;rsquo;ll need to build the image before we can deploy it. If you&amp;rsquo;re following allowing using minikube then make sure you are connected to the minikube host as your Docker host (&lt;code&gt;eval $(minikube docker-env)&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mkdir nginx
$ mv site.conf nginx/
$ touch nginx/Dockerfile&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s open up the &lt;code&gt;nginx/Dockerfile&lt;/code&gt; and set it up.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;nginx/Dockerfile&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; nginx:1.11.13-alpine&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;COPY site.conf /etc/nginx/conf.d/default.conf&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With the Dockerfile in place, we&amp;rsquo;re able to create the image we need before we&amp;rsquo;ll be able to create our Kubernetes Deployment &amp;amp; Service.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker build -t coderjourney/mealplan-frontend:1.0.0 nginx/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;creating-the-front-end-deployment-service&#34;&gt;Creating the Front-end Deployment &amp;amp; Service&lt;/h2&gt;

&lt;p&gt;Now that we have an image in place we need to specify what Kubernetes needs to run and maintain through a Deployment and Service. Similar to the &lt;a href=&#34;https://coderjourney.com/using-kubernetes-persistent-volumes/&#34;&gt;postgres tutorial&lt;/a&gt; we&amp;rsquo;ll define our Service and Deployment in the same file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;deployments/frontend.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;v1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Service&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;frontend&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;protocol&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;TCP&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;port&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;targetPort&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;selector&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;tier&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;frontend&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;type&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;LoadBalancer&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;---&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;extensions/v1beta1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Deployment&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;frontend&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;template&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;labels&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;tier&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;frontend&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;containers&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;coderjourney/mealplan-frontend:1.0.0&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;nginx&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;lifecycle&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;preStop&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;exec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;command&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/usr/sbin/nginx&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;-s&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;quit&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;ve seen most everything in this file except the extra &lt;code&gt;lifecycle&lt;/code&gt; bit in the container declaration. We&amp;rsquo;re specifying what command should be running before the container is stopped so that we don&amp;rsquo;t drop connections when stopping this particular container. With our Service and Deployment defined it&amp;rsquo;s time to create them.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl create -f deployments/frontend.yml
service &lt;span class=&#34;s2&#34;&gt;&amp;#34;frontend&amp;#34;&lt;/span&gt; created
deployment &lt;span class=&#34;s2&#34;&gt;&amp;#34;frontend&amp;#34;&lt;/span&gt; created&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With our service up and running we should be able to connect to our Nginx service through the web browser after we get the URL for it from minikube:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ minikube service frontend --url
http://192.168.99.100:31844&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Visiting that URL you should now show our rails application through the eyes of Nginx.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;In this tutorial, we continue to familiarize ourselves with Kubernetes by creating another service that will act as the frontend for our Rails backend service. We also fixed an issue that we created when originally setting up the persistent storage for our PostgreSQL database. There are still a few more things to tackle before we&amp;rsquo;ll have a production grade deployment setup for our Rails application, but we&amp;rsquo;re getting close.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Using Kubernetes Persistent Volumes</title>
      <link>https://coderjourney.com/using-kubernetes-persistent-volumes/</link>
      <pubDate>Tue, 04 Apr 2017 02:00:00 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/using-kubernetes-persistent-volumes/</guid>
      <description>

&lt;p&gt;In the &lt;a href=&#34;https://coderjourney.com/define-kubernetes-objects-using-yaml/&#34;&gt;previous tutorial&lt;/a&gt; we looked at running a Rails application utilizing a Kubernetes Deployment, Service, and ConfigMap. This week, we&amp;rsquo;ll take a look at running a stateful database in Kubernetes.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/E8uGIeiaaUQ&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goals&#34;&gt;Goals:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a service for our Postgres database.&lt;/li&gt;
&lt;li&gt;Connect our &lt;code&gt;mealplan&lt;/code&gt; service to our database.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;stateful-vs-stateless&#34;&gt;Stateful vs Stateless&lt;/h2&gt;

&lt;p&gt;Our &lt;a href=&#34;https://github.com/coderjourney/meal_plan/tree/adding-kubernetes&#34;&gt;Rails application&lt;/a&gt; is an example of a &amp;ldquo;stateless&amp;rdquo; application because there is no state maintained between requests. It might seem like there is, but all of the actual state is managed in the database. It&amp;rsquo;s very easy to tear down and spin up stateless applications because you just need to make sure that you&amp;rsquo;re not terminating a request while it&amp;rsquo;s being processed. Stateful applications aren&amp;rsquo;t quite so easy to work with in this way because the data could/would be lost.&lt;/p&gt;

&lt;p&gt;For us to run our Postgres database in Kubernetes we&amp;rsquo;re going to need to use the following Kubernetes object types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Service&lt;/li&gt;
&lt;li&gt;Deployment&lt;/li&gt;
&lt;li&gt;ConfigMap&lt;/li&gt;
&lt;li&gt;PersistentVolumeClaim&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We&amp;rsquo;ve seen &lt;code&gt;Service&lt;/code&gt;, &lt;code&gt;Deployment&lt;/code&gt;, and &lt;code&gt;ConfigMap&lt;/code&gt;, but &lt;code&gt;PersistentVolumeClaim&lt;/code&gt; is new. A &lt;code&gt;PersistentVolumeClaim&lt;/code&gt; object indicates that we need access to some storage that isn&amp;rsquo;t going to go away. It&amp;rsquo;s not quite like a Docker volume because we will need to specify more information like how much storage and how many containers can access it.&lt;/p&gt;

&lt;h2 id=&#34;creating-a-database-deployment&#34;&gt;Creating a Database Deployment&lt;/h2&gt;

&lt;p&gt;For this tutorial, we&amp;rsquo;re going to group all of the definitions necessary to run our database in Kubernetes into the same YAML file. Before we get too far let&amp;rsquo;s create the &lt;code&gt;Service&lt;/code&gt; and &lt;code&gt;Deployment&lt;/code&gt; that we need without any persistence (running it this way would cause data loss when the container stopped):&lt;/p&gt;

&lt;p&gt;&lt;em&gt;deployments/postgres.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;v1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Service&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;port&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;5432&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;selector&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;---&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;extensions/v1beta1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Deployment&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;template&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;labels&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;containers&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres:9.6.2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;env&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_USER&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_user&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_PASSWORD&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_password&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;containerPort&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;5432&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This isn&amp;rsquo;t super far off of how we defined our &lt;code&gt;mealplan&lt;/code&gt; &lt;code&gt;Deployment&lt;/code&gt; or &lt;code&gt;Service&lt;/code&gt;. We&amp;rsquo;re reusing the &lt;code&gt;configMapKeyRef&lt;/code&gt; lines from earlier since we want to use the same user and password. The biggest differences are that we&amp;rsquo;re defining both objects in the same file and we&amp;rsquo;re separating them with three dashes &lt;code&gt;---&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If we run this YAML file using the &lt;code&gt;kubectl create -f&lt;/code&gt; command we should see the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl create -f deployments/postgres.yml
service &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; created
deployment &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; created&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;adding-data-persistence&#34;&gt;Adding Data Persistence&lt;/h2&gt;

&lt;p&gt;Now that we have our &lt;code&gt;Service&lt;/code&gt; and &lt;code&gt;Deployment&lt;/code&gt; created successfully we&amp;rsquo;re going to set up our &lt;code&gt;PersistentVolumeClaim&lt;/code&gt; so that we can persist the data. The &lt;code&gt;postgres&lt;/code&gt; image that we&amp;rsquo;re using sets up the username/password combination when the container is first created with no database, because of this we&amp;rsquo;re going to remove our deployment and service for the time being:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl delete -f deployments/postgres.yml
service &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; deleted
deployment &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; deleted&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we will define the &lt;code&gt;PersistentVolumeClaim&lt;/code&gt; and also mount the volume into our deployment&amp;rsquo;s containers. The &lt;code&gt;Service&lt;/code&gt; portion of the file will be unchanged so we&amp;rsquo;ll leave that out.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Servie declaration left out for brevity&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;---&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;extensions/v1beta1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Deployment&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;template&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;labels&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;containers&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres:9.6.2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;env&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_USER&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_user&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_PASSWORD&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_password&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;containerPort&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;5432&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;volumeMounts&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-storage&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;mountPath&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/var/lib/postgresql/db-data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-storage&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;persistentVolumeClaim&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;claimName&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-pv-claim&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;---&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;v1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;PersistentVolumeClaim&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres-pv-claim&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;accessModes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ReadWriteOnce&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;resources&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;requests&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;storage&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;5Gi&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We needed to add a &lt;code&gt;volumeMounts&lt;/code&gt; section to our container in the &lt;code&gt;Deployment&lt;/code&gt; and then also tell the deployment what &lt;code&gt;volumes&lt;/code&gt; it has access to. Lastly, we created a &lt;code&gt;PersistenVolumeClaim&lt;/code&gt;. The claim itself exists to say that whatever is using this claim is allowed to access the &lt;code&gt;PersistentVolume&lt;/code&gt; behind it. Let&amp;rsquo;s create the resources and do some poking around.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl create -f deployments/postgres.yml
service &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; created
deployment &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres&amp;#34;&lt;/span&gt; created
persistentvolumeclaim &lt;span class=&#34;s2&#34;&gt;&amp;#34;postgres-pv-claim&amp;#34;&lt;/span&gt; created&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First taking a look at our &lt;code&gt;PersistentVolumeClaim&lt;/code&gt; using the &lt;code&gt;describe&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl describe pvc postgres-pv-claim
Name:           postgres-pv-claim
Namespace:      default
StorageClass:   standard
Status:         Bound
Volume:         pvc-9af882c8-1348-11e7-9408-080027b11ce5
Labels:         &amp;lt;none&amp;gt;
Capacity:       5Gi
Access Modes:   RWO
No events.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can see from the &lt;code&gt;describe&lt;/code&gt; output that a &lt;code&gt;PersistentVolume&lt;/code&gt; was created for our claim. Getting the description of that volume should give us even more insight how this is set up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl describe pv pvc-9af882c8-1348-11e7-9408-080027b11ce5
Name:           pvc-9af882c8-1348-11e7-9408-080027b11ce5
Labels:         &amp;lt;none&amp;gt;
StorageClass:   standard
Status:         Bound
Claim:          default/postgres-pv-claim
Reclaim Policy: Delete
Access Modes:   RWO
Capacity:       5Gi
Message:
Source:
    Type:       HostPath &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;bare host directory volume&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;
    Path:       /tmp/hostpath-provisioner/pvc-9af882c8-1348-11e7-9408-080027b11ce5
No events.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From the looks of it, the volume was created as a directory that we have read/write access to. That works perfectly fine for our needs.&lt;/p&gt;

&lt;h2 id=&#34;connecting-rails-to-our-database&#34;&gt;Connecting Rails to our Database&lt;/h2&gt;

&lt;p&gt;Now that we have a volume and Postgres running we need to reconfigure our Rails application to connect to it. To complete our set up we need to do a few more things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Change our ConfigMap&amp;rsquo;s &lt;code&gt;POSTGRES_HOST&lt;/code&gt; value so Rails knows what to talk to.&lt;/li&gt;
&lt;li&gt;Deploy the ConfigMap changes.&lt;/li&gt;
&lt;li&gt;Set up our new database (we&amp;rsquo;re not going to migrate any of the data).&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;updating-the-mealplan-config-configmap&#34;&gt;Updating the mealplan-config ConfigMap&lt;/h3&gt;

&lt;p&gt;Thankfully, Kubernetes makes it easy for us to edit the data in a config map using the &lt;code&gt;kubectl edit&lt;/code&gt; command. Let&amp;rsquo;s change the &lt;code&gt;POSTGRES_HOST&lt;/code&gt; value now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl edit configmap mealplan-config&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will open up your &lt;code&gt;$EDITOR&lt;/code&gt; (in my case that&amp;rsquo;s Vim) and you should edit the &lt;code&gt;POSTGRES_HOST&lt;/code&gt; from being an IP address to having the value of &lt;code&gt;postgres&lt;/code&gt;. It should look like this when we&amp;rsquo;re done:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Please edit the object below. Lines beginning with a &amp;#39;#&amp;#39; will be ignored,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# and an empty file will abort the edit. If an error occurs while saving this file will be&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# reopened with the relevant failures.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;#&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;v1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;postgres_host&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;postgres_password&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;dF1nu8xT6jBz01iXAfYDCmGdQO1IOc4EOgqVB703&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;postgres_user&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;meal_planner&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;rails_env&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;production&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;rails_log_to_stdout&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;secret_key_base&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;7a475ef05d7f1100ae91c5e7ad6ab4706ce5d303e6bbb8da153d2accb7cb53fa5faeff3161b29232b3c08d6417bd05686094d04e22950a4767bc9236991570ad&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ConfigMap&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;creationTimestamp&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;ld&#34;&gt;2017-03-21T22:46:45Z&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;namespace&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;default&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;resourceVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;82058&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;selfLink&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;/api/v1/namespaces/default/configmaps/mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;uid&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;427c493c-&lt;span class=&#34;m&#34;&gt;0e88&lt;/span&gt;-&lt;span class=&#34;m&#34;&gt;11e7&lt;/span&gt;-99a4-080027b11ce5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you save in your editor it will update the ConfigMap object that Kubernetes maintains.&lt;/p&gt;

&lt;h3 id=&#34;deploying-configmap-changes&#34;&gt;Deploying ConfigMap Changes&lt;/h3&gt;

&lt;p&gt;Unfortunately, it was very easy to update the ConfigMap, but slightly less easy or understandable to get those changes reflected in our deployment. Similar to the way that environment variable changes are deployed to Docker containers using &lt;code&gt;docker-compose&lt;/code&gt;, we need to stop our container and deploy a new one for the value to be updated. Since this is done on a deployment level we will be using the &lt;code&gt;kubectl scale&lt;/code&gt; command to stop our container(s) and spin some new ones back up:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl scale deployment/mealplan --replicas&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; kubectl scale deployment/mealplan --replicas&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
deployment &lt;span class=&#34;s2&#34;&gt;&amp;#34;mealplan&amp;#34;&lt;/span&gt; scaled
deployment &lt;span class=&#34;s2&#34;&gt;&amp;#34;mealplan&amp;#34;&lt;/span&gt; scaled&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now our new container will be connected to the Kubernetes maintained &lt;code&gt;postgres&lt;/code&gt; service.&lt;/p&gt;

&lt;h3 id=&#34;setting-up-the-database-in-kubernetes&#34;&gt;Setting up the Database in Kubernetes&lt;/h3&gt;

&lt;p&gt;Now that our rails application is connected to the &lt;code&gt;postgres&lt;/code&gt; service we need to do the work to set up the database initially. Since this is something that we&amp;rsquo;ll only be doing once we will run this manually by using the &lt;code&gt;kubectl exec&lt;/code&gt; command. First, we need to find the container that we&amp;rsquo;ll use to exec:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl get pods
NAME                        READY     STATUS    RESTARTS   AGE
mealplan-4029866644-mhhtf   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;/1       Running   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;          5m
postgres-4220950182-qphj2   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;/1       Running   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;          15m&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The container name that I&amp;rsquo;ll be using will be &lt;code&gt;mealplan-4029866644-mhhtf&lt;/code&gt; but yours will be different. Now let&amp;rsquo;s use the &lt;code&gt;kubectl exec&lt;/code&gt; command to make sure we&amp;rsquo;re talking to the proper host and get up our database:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; mealplan-4029866644-mhhtf -it -- env &lt;span class=&#34;p&#34;&gt;|&lt;/span&gt; grep POSTGRES_HOST
&lt;span class=&#34;nv&#34;&gt;POSTGRES_HOST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;postgres
$ kubectl &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; mealplan-4029866644-mhhtf -it -- rake db:setup&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;tearing-down-the-old-postgres-container&#34;&gt;Tearing Down the Old Postgres Container&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s make sure that we don&amp;rsquo;t leave the old Postgres container running outside of Kubernetes. Set the &lt;code&gt;minikube&lt;/code&gt; host as your &lt;code&gt;DOCKER_HOST&lt;/code&gt; if it&amp;rsquo;s not already set:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;minikube docker-env&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can stop &amp;amp; remove the database container that we were using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker stop mealplan_prod_db_1
mealplan_prod_db_1
$ docker rm mealplan_prod_db_1
mealplan_prod_db_1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;In this tutorial, you went through and learned how to set up a Kubernetes PersistentVolume and run a stateful application within Kubernetes. You also learned how to edit a ConfigMap and deploy the changes to an existing deployment. We had some unfortunate downtime that we had to deal with, but in later tutorials, we will address how to overcome that hurdle.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Define Kubernetes Objects using Yaml</title>
      <link>https://coderjourney.com/define-kubernetes-objects-using-yaml/</link>
      <pubDate>Tue, 21 Mar 2017 01:00:00 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/define-kubernetes-objects-using-yaml/</guid>
      <description>

&lt;p&gt;You&amp;rsquo;ve taken Kubernetes for a spin using the command line utility, but
eventually you&amp;rsquo;re going to need set up more customized pods &amp;amp; deployments.
In this tutorial, you&amp;rsquo;ll learn how to set up YAML files to create
custom Kubernetes objects.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/6XN6LEzsQTQ&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goals&#34;&gt;Goals:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a deployable image for a Rails application&lt;/li&gt;
&lt;li&gt;Generate a ConfigMap to define environment variables in our pods&lt;/li&gt;
&lt;li&gt;Configure deployment for our Rails application&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our goal for today is to get a Rails application running with Kubernetes. To get the application up and running we need to figure out how to use environment variables with Kubernetes, how to package the application to run with Kubernetes, and lastly how to define our configuration.&lt;/p&gt;

&lt;h2 id=&#34;using-the-minikube-docker-server&#34;&gt;Using the Minikube Docker Server&lt;/h2&gt;

&lt;p&gt;While we&amp;rsquo;re working locally using minikube we&amp;rsquo;re going to need to be building our applications into images that we can run in pods. We&amp;rsquo;ll do this using the &lt;code&gt;docker build&lt;/code&gt; command, but by default, our docker client won&amp;rsquo;t be talking to the minikube Docker.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll get around this by using a line similar to how we set which docker-machine to use:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;minikube docker-env&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will set our Docker client to use the proper server.&lt;/p&gt;

&lt;h2 id=&#34;building-our-rails-image&#34;&gt;Building our Rails Image&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ll be using the meal planning application that can be found &lt;a href=&#34;https://github.com/coderjourney/meal_plan&#34;&gt;here&lt;/a&gt;. Download this application to follow along.&lt;/p&gt;

&lt;p&gt;From within the application&amp;rsquo;s directory, let&amp;rsquo;s build the image and give it a meaningful name:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker build -t meal_plan:1 .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re giving this a version number of &lt;code&gt;1&lt;/code&gt; since it&amp;rsquo;s our first time packaging it up. Having a version number like this allows us to ensure that we&amp;rsquo;re deploying the proper version.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Remember:&lt;/em&gt; &lt;code&gt;latest&lt;/code&gt; is not a version number.&lt;/p&gt;

&lt;h2 id=&#34;starting-the-database-on-a-separate-docker-host&#34;&gt;Starting the Database on a Separate Docker Host&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;re not going to be running the database within Kubernetes just yet, but we still need one to be running so our application can connect to it. We&amp;rsquo;re going to run the database from the VM that Kubernetes is running in so we can easily connect our application to it. You would never actually do this, but we don&amp;rsquo;t have time in this tutorial to coverage running Postgres in Kubernetes.&lt;/p&gt;

&lt;p&gt;Before we start it, we&amp;rsquo;ll need to expose the database port to the Docker host so that our Kubernetes cluster can access it:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;docker-compose.prod.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Only showing the `prod_db` portion of the file&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;prod_db&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;5432:5432&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/var/lib/postgresql/db-data&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now with that changed we can start the database using:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ script/prod up -d prod_db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To make it easier on ourselves we should also make sure that the
database exists before continuing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ script/prod run --rm prod_app rake db:create db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;creating-a-rails-deployment&#34;&gt;Creating a Rails Deployment&lt;/h2&gt;

&lt;p&gt;Now that we have an image we could create a deployment using the &lt;code&gt;kubectl run&lt;/code&gt; command, but that can&amp;rsquo;t be peer reviewed and might be hard to replicate so we&amp;rsquo;re going to create this deployment as a YAML file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;deployments/mealplan.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;extensions/v1beta1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Deployment&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;replicas&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;template&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;labels&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;tier&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;backend&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;track&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;stable&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;containers&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;meal_plan:1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;rails&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;containerPort&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3000&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Besides the &lt;code&gt;image&lt;/code&gt; declaration, you&amp;rsquo;ll notice that we use &lt;code&gt;mealplan&lt;/code&gt; without and underscore, this is because the underscore is not allowed. This will create an application container for us, but it&amp;rsquo;s not going to work without the additional configuration values that we had been storing in the &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;Going through this file. We define the type of Kubernetes object using the &lt;code&gt;kind&lt;/code&gt; key, set the &lt;code&gt;name&lt;/code&gt; as a &lt;code&gt;metadata&lt;/code&gt; subkey, and then we set the &lt;code&gt;spec&lt;/code&gt; for the deployment. The &lt;code&gt;spec&lt;/code&gt; is a lot like what we would define as part of a &lt;code&gt;docker-compose.yml&lt;/code&gt; file. The notable differences here are the &lt;code&gt;replicas&lt;/code&gt; setting, the &lt;code&gt;template&lt;/code&gt; key, and the fact that we&amp;rsquo;re able to name the port. The labels allow us to specify ways to classify our objects.&lt;/p&gt;

&lt;p&gt;For us to utilize the environment variables that we have been using we&amp;rsquo;re going to set up a &lt;code&gt;ConfigMap&lt;/code&gt;, which is another object in Kubernetes that you can use to hold configuration data.&lt;/p&gt;

&lt;h2 id=&#34;creating-the-meal-plan-configmap&#34;&gt;Creating the Meal Plan ConfigMap&lt;/h2&gt;

&lt;p&gt;ConfigMaps exist within Kubernetes and allow us to set specific keys (literals) or entire files. Unfortunately, our application isn&amp;rsquo;t set up to read an entire file in as environment variables (you could use dotenv for that). We&amp;rsquo;re going to need to set up the values from our &lt;code&gt;.env.prod&lt;/code&gt; as literal values within a ConfigMap.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl create configmap mealplan-config &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;--from-literal&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;meal_planner &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;--from-literal&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres_password&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;dF1nu8xT6jBz01iXAfYDCmGdQO1IOc4EOgqVB703 &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;--from-literal&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;postgres_host&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;minikub ip&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;--from-literal&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;rails_env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;production &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;--from-literal&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;rails_log_to_stdout&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;true&lt;/span&gt; &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;--from-literal&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;secret_key_base&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;7a475ef05d7f1100ae91c5e7ad6ab4706ce5d303e6bbb8da153d2accb7cb53fa5faeff3161b29232b3c08d6417bd05686094d04e22950a4767bc9236991570ad&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can make sure that we set everything properly by looking at the &lt;code&gt;data&lt;/code&gt; section of the ConfigMap resource:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl get configmap mealplan-config -o yaml
apiVersion: v1
data:
  postgres_host: &lt;span class=&#34;m&#34;&gt;192&lt;/span&gt;.168.99.101
  postgres_password: dF1nu8xT6jBz01iXAfYDCmGdQO1IOc4EOgqVB703
  postgres_user: meal_planner
  rails_env: production
  rails_log_to_stdout: &lt;span class=&#34;s2&#34;&gt;&amp;#34;true&amp;#34;&lt;/span&gt;
  secret_key_base: 7a475ef05d7f1100ae91c5e7ad6ab4706ce5d303e6bbb8da153d2accb7cb53fa5faeff3161b29232b3c08d6417bd05686094d04e22950a4767bc9236991570ad
kind: ConfigMap
metadata:
  creationTimestamp: &lt;span class=&#34;m&#34;&gt;2017&lt;/span&gt;-03-19T21:08:25Z
  name: mealplan-config
  namespace: default
  resourceVersion: &lt;span class=&#34;s2&#34;&gt;&amp;#34;12711&amp;#34;&lt;/span&gt;
  selfLink: /api/v1/namespaces/default/configmaps/mealplan-config
  uid: 86160c7a-0e7a-11e7-99a4-080027b11ce5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;adding-configuration-to-the-meal-plan-deployment&#34;&gt;Adding Configuration to the Meal Plan Deployment&lt;/h2&gt;

&lt;p&gt;With the config map created we can now use these in our deployment file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;deployments/mealplan.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;extensions/v1beta1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Deployment&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;replicas&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;template&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;labels&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;tier&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;backend&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;track&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;stable&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;containers&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;meal_plan:1&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;rails&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;containerPort&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;3000&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;          &lt;/span&gt;env&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_USER&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_user&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_PASSWORD&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_password&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;POSTGRES_HOST&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres_host&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;RAILS_ENV&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;rails_env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;RAILS_LOG_TO_STDOUT&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;rails_log_to_stdout&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;            &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;SECRET_KEY_BASE&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;              &lt;/span&gt;valueFrom&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                &lt;/span&gt;configMapKeyRef&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan-config&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;                  &lt;/span&gt;key&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;secret_key_base&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For each environment variable we need to set the name as it would be exposed in the environment, all uppercase, and then we tell the deployment where it should pull this value. In this case, we want to use values from a &lt;code&gt;ConfigMap&lt;/code&gt; so we&amp;rsquo;re using the &lt;code&gt;configMapKeyRef&lt;/code&gt; option, providing the name of the &lt;code&gt;ConfigMap&lt;/code&gt; that we created, and then specifying the key from the &lt;code&gt;ConfigMap&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The configuration story here is a little tedious, but it does require us to be explicit. Now we can create our deployment using the &lt;code&gt;kubectl create&lt;/code&gt; command and our deployment file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl create -f deployments/mealplan.yml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;exposing-our-rails-application-with-a-server&#34;&gt;Exposing our Rails Application with a Server&lt;/h2&gt;

&lt;p&gt;To ensure that our application is running we should expose it using a Kubernetes service. Services can also be configured using configuration files so we&amp;rsquo;ll create that now.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mkdir services&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;services/mealplan.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;kind&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Service&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;apiVersion&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;v1&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;metadata&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;name&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;spec&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;selector&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;mealplan&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;tier&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;backend&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;protocol&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;TCP&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;port&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;targetPort&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;rails&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;type&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;LoadBalancer&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Setting up the Service works a lot like setting up the deployment earlier. One thing to notice is that we&amp;rsquo;re setting the &lt;code&gt;targetPort&lt;/code&gt; using the port name that we created in our deployment. The &lt;code&gt;selector&lt;/code&gt; section is important because that tells the Service how to find the pods to direct traffic to.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s create the service using the same &lt;code&gt;kubectl create&lt;/code&gt; command as before with our new file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl create -f services/mealplan.yml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Get the URL for this service from minikube:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ minikube service mealplan --url
http://192.168.99.100:32261&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If all went well, visiting that URL in your web browser should show you the unstyled home page of our meal planning application.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/kubernetes/rails-on-kubernetes.png&#34; alt=&#34;Rails on Kubernetes&#34; width=&#34;913&#34; height=&#34;658&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;In this tutorial, you created Kubernetes objects to run a Ruby on Rails application in a repeatable way. This didn&amp;rsquo;t cover even close to everything that we&amp;rsquo;ll be able to do with Kubernetes, but
it is a pretty good start. If you would like to improve this, you should move some of the configuration values into &lt;a href=&#34;https://kubernetes.io/docs/user-guide/secrets/&#34;&gt;Kubernetes Secrets&lt;/a&gt;. In the next tutorial, we&amp;rsquo;ll cover running stateful applications (like databases) in Kubernetes.&lt;/p&gt;

&lt;p&gt;The code from this tutorial can be found &lt;a href=&#34;https://github.com/coderjourney/meal_plan/pull/13&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Run Kubernetes Locally Using Minikube</title>
      <link>https://coderjourney.com/run-kubernetes-locally-using-minikube/</link>
      <pubDate>Tue, 14 Mar 2017 22:00:00 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/run-kubernetes-locally-using-minikube/</guid>
      <description>

&lt;p&gt;If you&amp;rsquo;re just getting started with Kubernetes then it may be a little intimidating to start running of servers in a cloud provider like Google Cloud or AWS. Thankfully, you don&amp;rsquo;t need to use a cloud provider if you&amp;rsquo;re just dabbling with Kubernetes thanks to &lt;a href=&#34;https://github.com/kubernetes/minikube&#34;&gt;minikube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Minikube will allow you to run a Kubernetes cluster on your development environment. This won&amp;rsquo;t exactly match the experience that you&amp;rsquo;ll have in a deployed environment, but it will be close enough to let you get your bearings.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/BDrcUjOczsE&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;installing-kubectl&#34;&gt;Installing Kubectl&lt;/h2&gt;

&lt;p&gt;Minikube will help when learning Kubernetes, but it won&amp;rsquo;t actually be of much use unless you have the &lt;code&gt;kubectl&lt;/code&gt; command installed.&lt;/p&gt;

&lt;p&gt;You&amp;rsquo;ll want to follow &lt;a href=&#34;https://kubernetes.io/docs/user-guide/prereqs/&#34;&gt;these instructions&lt;/a&gt; to install &lt;code&gt;kubectl&lt;/code&gt; for your operating system. I&amp;rsquo;m working on macOS so I&amp;rsquo;ll be using homebrew to install.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ brew update &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; brew install kubectl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make sure that you&amp;rsquo;re set up properly before continuing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl version
Client Version: version.Info&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;Major:&lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;, Minor:&lt;span class=&#34;s2&#34;&gt;&amp;#34;5&amp;#34;&lt;/span&gt;, GitVersion:&lt;span class=&#34;s2&#34;&gt;&amp;#34;v1.5.4&amp;#34;&lt;/span&gt;, GitCommit:&lt;span class=&#34;s2&#34;&gt;&amp;#34;7243c69eb523aa4377bce883e7c0dd76b84709a1&amp;#34;&lt;/span&gt;, GitTreeState:&lt;span class=&#34;s2&#34;&gt;&amp;#34;clean&amp;#34;&lt;/span&gt;, BuildDate:&lt;span class=&#34;s2&#34;&gt;&amp;#34;2017-03-08T02:50:34Z&amp;#34;&lt;/span&gt;, GoVersion:&lt;span class=&#34;s2&#34;&gt;&amp;#34;go1.8&amp;#34;&lt;/span&gt;, Compiler:&lt;span class=&#34;s2&#34;&gt;&amp;#34;gc&amp;#34;&lt;/span&gt;, Platform:&lt;span class=&#34;s2&#34;&gt;&amp;#34;darwin/amd64&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;installing-minikube&#34;&gt;Installing Minikube&lt;/h2&gt;

&lt;p&gt;Installing &lt;code&gt;minikube&lt;/code&gt; works in a similar way to most of the installation directions for &lt;code&gt;kubectl&lt;/code&gt;. Follow the instructions for the latest version &lt;a href=&#34;https://github.com/kubernetes/minikube/releases&#34;&gt;found here&lt;/a&gt;. Some of the commands utilize sudo, but depending on your development environment set up you may not need them to.&lt;/p&gt;

&lt;p&gt;Since I&amp;rsquo;m on macOS, I&amp;rsquo;ll use the corresponding instructions:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.17.1/minikube-darwin-amd64 &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; chmod +x minikube &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; mv minikube /usr/local/bin/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With minikube installed you&amp;rsquo;re ready to start your first cluster (this might take a little while):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ minikube start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The minikube start process configures your &lt;code&gt;kubectl&lt;/code&gt; to connect to it.&lt;/p&gt;

&lt;h2 id=&#34;your-first-deployment&#34;&gt;Your First Deployment&lt;/h2&gt;

&lt;p&gt;The atomic unit of Kubernetes is the &amp;ldquo;pod&amp;rdquo; and a pod represents everything that is necessary for an application to run. Pods include a lot of the same information that you may have seen in a &lt;code&gt;docker-compose.yml&lt;/code&gt; file (images, volumes, networks, etc). We won&amp;rsquo;t be creating a pod directly right now because we&amp;rsquo;re going to instead create a &amp;ldquo;deployment&amp;rdquo; that will create a pod behind the scenes. For this example, we&amp;rsquo;ll use the &lt;code&gt;nginx:alpine&lt;/code&gt; image since it is small and exposes a port for us to view the default page.&lt;/p&gt;

&lt;p&gt;To create a new deployment you can use the &lt;code&gt;kubectl run&lt;/code&gt; command in this way:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl run &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;name-of-deployment&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; --image&lt;span class=&#34;o&#34;&gt;=[&lt;/span&gt;image-name&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case, we&amp;rsquo;ll call the deployment &lt;code&gt;webserver&lt;/code&gt; and use the &lt;code&gt;nginx:alpine&lt;/code&gt; image.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl run webserver --image&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;nginx:alpine&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now you can take a look at the deployment &amp;amp; pod using the &lt;code&gt;kubectl get&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl get deployments
NAME        DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
webserver   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;         &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;            &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;           7s

$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
webserver-2615124133-bgjjv   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;/1       Running   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;          11s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that the pod has an extra identifier as part of the name. We don&amp;rsquo;t need to manage extra info because our deployment will do it for us.&lt;/p&gt;

&lt;p&gt;Once of the nice features of deployments is that they can keep your pods running even when something goes wrong. Let&amp;rsquo;s delete the pod that was created with the deployment and see what happens. Whenever you delete a resource like a pod, deployment, or service you&amp;rsquo;ll use the &lt;code&gt;kubectl delete&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl delete pod webserver-2615124133-bgjjv
pod &lt;span class=&#34;s2&#34;&gt;&amp;#34;webserver-2615124133-bgjjv&amp;#34;&lt;/span&gt; deleted&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we look at the pods again we would expect to not see anything, but our deployment says otherwise.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl get pods
NAME                         READY     STATUS    RESTARTS   AGE
webserver-2615124133-d03zm   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;/1       Running   &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;          10s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The deployment created a replacement pod since the previous one was destroyed.&lt;/p&gt;

&lt;h2 id=&#34;exposing-the-deployment&#34;&gt;Exposing the Deployment&lt;/h2&gt;

&lt;p&gt;This webserver isn&amp;rsquo;t all that useful to us right now because it can&amp;rsquo;t be accessed, but that can be changed by creating a &amp;ldquo;service&amp;rdquo;. We&amp;rsquo;ll create a service for our &amp;ldquo;webserver&amp;rdquo; deployment by using the &lt;code&gt;kubectl expose&lt;/code&gt; command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl expose deployment webserver --type&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;LoadBalancer --port&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re using the &lt;code&gt;LoadBalancer&lt;/code&gt; type here, but you could have also used the &lt;code&gt;NodePort&lt;/code&gt;, and we need to specify the port that will be exposed. Take a look at this service using &lt;code&gt;kubectl get&lt;/code&gt; once again:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ kubectl get services
NAME         CLUSTER-IP   EXTERNAL-IP   PORT&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;S&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;        AGE
kubernetes   &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;.0.0.1     &amp;lt;none&amp;gt;        &lt;span class=&#34;m&#34;&gt;443&lt;/span&gt;/TCP        3d
webserver    &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;.0.0.247   &amp;lt;pending&amp;gt;     &lt;span class=&#34;m&#34;&gt;80&lt;/span&gt;:30349/TCP   8s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we&amp;rsquo;re using minikube accessing this service requires another step since we can&amp;rsquo;t get an external IP. You&amp;rsquo;ll take the exposed port (in this case &lt;code&gt;30349&lt;/code&gt;) and access that on the minikube IP address. You can get all of this information in a single minikube command thankfully:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ minikube service webserver --url
http://192.168.99.101:30349&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Viewing the URL that the command gave you from your browser will show you the default nginx landing page.&lt;/p&gt;

&lt;h2 id=&#34;visualizing-kubernetes&#34;&gt;Visualizing Kubernetes&lt;/h2&gt;

&lt;p&gt;Working with a cluster of nodes, numerous pods, and services can get a little confusing, but kubernetes can be visualized through dashboards and minikube comes with one baked right in. You can launch the dashboard using this command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ minikube dashboard&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/kubernetes/kubernetes-dashboard.png&#34; alt=&#34;Kubernetes Dashboard&#34; width=&#34;1332&#34; height=&#34;699&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;You went through quite a bit in this tutorial. You created your first Kubernetes cluster using minikube &amp;amp; you made a deployment that you exposed using a service. As this series continues you&amp;rsquo;ll deploy increasingly more advance setups, but this is a really good start.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Rails – Improving Deployment (Part 9)</title>
      <link>https://coderjourney.com/learning-rails-improving-deployment-part-9/</link>
      <pubDate>Tue, 24 Jan 2017 13:00:15 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-rails-improving-deployment-part-9/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to be improving deployment of the meal plan application by setting up a web server (Nginx) in front of our application server.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/MZs5YZFBpUI&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pre-compile assets&lt;/strong&gt; as part of our image building process&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Add Nginx to our web application stack&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Handle Deploying New Application Changes&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We current have our application running in the wild, but pointing a user at an IP address with a port number isn&amp;rsquo;t a great approach. It&amp;rsquo;s also not great that there is a really long first load time when the application has to compile the status assets (javascript, styles, etc). We can fix both of these issues by using a web server and pre-compiling our assets.&lt;/p&gt;

&lt;p&gt;Before we get going too far though we&amp;rsquo;re going to improve our ability to run commands using our &lt;code&gt;docker-compose.prod.yml&lt;/code&gt; file. Let&amp;rsquo;s create &lt;code&gt;script/prod&lt;/code&gt; to make this a little easier to type:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;script/prod&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
docker-compose -f docker-compose.prod.yml &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$@&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After you save the file don&amp;rsquo;t forget to make it executable:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ chmod +x script/prod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; If you&amp;rsquo;re on windows you can created a console alias by following the instructions &lt;a href=&#34;https://msdn.microsoft.com/en-us/library/windows/desktop/ms682057(v=vs.85).aspx&#34;&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;pre-compiling-application-assets&#34;&gt;Pre-compiling Application Assets&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;re going to pre-compile assets as part of our Docker image build so that we can do it before we ever mess with our containers that are already running. This will make our application much faster on the first load and force our ruby process to do less once we have Nginx in place. We&amp;rsquo;ll start by creating a separate &lt;code&gt;Dockerfile&lt;/code&gt; for production.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ cp Dockerfile Dockerfile.prod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re calling this &lt;code&gt;Dockefile.prod&lt;/code&gt;, but it would really work for any configuration environment that we want to have our assets pre-compiled into. Next, we&amp;rsquo;ll make a few changes to the file to get our assets to be pre-compiled:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Dockerfile.prod&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; ruby:2.3.1&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; apt-get update -yqq &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get install -yqq --no-install-recommends &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    postgresql-client &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    nodejs &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get -q clean &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -rf /var/lib/apt/lists&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Pre-install gems with native extensions&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; gem install nokogiri -v &lt;span class=&#34;s2&#34;&gt;&amp;#34;1.6.8.1&amp;#34;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;WORKDIR&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; /usr/src/app&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;COPY Gemfile* ./&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; bundle install&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;COPY . .&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# Pre-compile assets&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ENV&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; RAILS_ENV production&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; rails assets:precompile&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;CMD&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; script/start&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next, we will need to set up our &lt;code&gt;docker-compose.prod.yml&lt;/code&gt; file to use the proper file to build our image.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;docker-compose.prod.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;services&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;prod_db&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/var/lib/postgresql/db-data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;prod_app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;build&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;context&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;dockerfile&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Dockerfile.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;depends_on&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;prod_db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s build it and watch the assets be precompiled using our new &lt;code&gt;script/prod&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ script/prod build prod_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can see that writes the values out to &lt;code&gt;/usr/src/app/public/assets&lt;/code&gt; within the image and even creates gzipped versions for us. This is important to notice because we&amp;rsquo;ll need to share these files from our &lt;code&gt;prod_app&lt;/code&gt; container over to our web server that we&amp;rsquo;re about to get up and running.&lt;/p&gt;

&lt;h2 id=&#34;setting-up-nginx-as-our-web-server&#34;&gt;Setting up Nginx as our Web Server&lt;/h2&gt;

&lt;p&gt;There are a few things that we want Nginx to handle for us:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Proxying for our Rails application. This will allow us to set up multiple backends when we need them.&lt;/li&gt;
&lt;li&gt;Serving static assets that have been precompiled.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For us to be able to do this without creating a custom Nginx image we will need to set up a volume to share our assets from our &lt;code&gt;prod_app&lt;/code&gt; container over to our &lt;code&gt;webserver&lt;/code&gt; container, and a volume to share our Nginx site configuration into the container also. Let&amp;rsquo;s lay out our &lt;code&gt;docker-compose.prod.yml&lt;/code&gt; file to let us accomplish this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;docker-compose.prod.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;assets&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;configs&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;services&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;webserver&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;nginx:1.11.8&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;80:80&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;443:443&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;assets&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/usr/share/nginx/html&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;configs&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/etc/nginx/conf.d&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;prod_db&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/var/lib/postgresql/db-data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;prod_app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;build&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;context&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;dockerfile&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;Dockerfile.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;assets&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/usr/share/nginx/html&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;configs&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/etc/nginx/conf.d&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;depends_on&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;prod_db&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;webserver&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re also going to need to create a new file that will represent our site configuration in Nginx so that it will proxy to our Rails app.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;site.conf&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-nginx&#34; data-lang=&#34;nginx&#34;&gt;&lt;span class=&#34;k&#34;&gt;server&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;kn&#34;&gt;listen&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;80&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Properly serve assets
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;~&lt;/span&gt; &lt;span class=&#34;sr&#34;&gt;^/(assets)/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/usr/share/nginx/html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;gzip_static&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;on&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;expires&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;max&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Cache-Control&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;public&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;add_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;ETag&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Proxy requests to rails app
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;kn&#34;&gt;location&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Host&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$host&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;X-Forwarded-For&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_pass_header&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;Set-Cookie&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
    &lt;span class=&#34;kn&#34;&gt;proxy_pass&lt;/span&gt; &lt;span class=&#34;s&#34;&gt;http://prod_app:3000&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This brings us to a &amp;ldquo;gotcha&amp;rdquo; with volumes that we hadn&amp;rsquo;t previously looked at. Once a volume has been created and is connected to a container, it won&amp;rsquo;t be removed or overwritten by simply connecting another container. This will have an effect because our &lt;code&gt;webserver&lt;/code&gt; container will create our &lt;code&gt;assets&lt;/code&gt; and &lt;code&gt;config&lt;/code&gt; containers with its own default values and then when we create our &lt;code&gt;prod_app&lt;/code&gt; container we won&amp;rsquo;t be able to simply share our assets over because they volume already exists.&lt;/p&gt;

&lt;h2 id=&#34;serving-proper-assets-on-update&#34;&gt;Serving Proper Assets on Update&lt;/h2&gt;

&lt;p&gt;Now that we have our site file up we&amp;rsquo;re going to need to rebuild our image so that it is packaged in, but before we do that we&amp;rsquo;re going to make sure that when we start our container in the production environment that we are ensuring the newest assets are in the right spot. We&amp;rsquo;ll do this by modifying our &lt;code&gt;script/start&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;script/start&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/bash -e
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; -a /tmp/puma.pid &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
  rm /tmp/puma.pid
&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$RAILS_ENV&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;production&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
  rake assets:precompile
  mkdir -p /usr/share/nginx/html
  cp -R public/* /usr/share/nginx/html/
  mkdir -p /etc/nginx/conf.d/
  cp site.conf /etc/nginx/conf.d/default.conf
&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;

rails server -b &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;.0.0.0 -P /tmp/puma.pid&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we precompile assets when we build the image doing so again here doesn&amp;rsquo;t really cost us anything. We ensure that the &lt;code&gt;html&lt;/code&gt; directory exists so that we can copy the assets from the &lt;code&gt;public&lt;/code&gt; directory over. Finally, we move our &lt;code&gt;site.conf&lt;/code&gt; file into the configuration directory for Nginx. It&amp;rsquo;s safe for us to now flip the flag we set in our &lt;code&gt;.env.prod&lt;/code&gt; file that was making rails serve and compile assets on the fly.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;POSTGRES_USER=meal_planner
POSTGRES_PASSWORD=dF1nu8xT6jBz01iXAfYDCmGdQO1IOc4EOgqVB703
POSTGRES_HOST=prod_db

RAILS_ENV=production
# RAILS_SERVE_STATIC_FILES=false
RAILS_LOG_TO_STDOUT=true
SECRET_KEY_BASE=7a475ef05d7f1100ae91c5e7ad6ab4706ce5d303e6bbb8da153d2accb7cb53fa5faeff3161b29232b3c08d6417bd05686094d04e22950a4767bc9236991570ad&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can rebuild our image and spin up our containers. We&amp;rsquo;ll start the &lt;code&gt;webserver&lt;/code&gt; container first so that we do get the Nginx static files as the first files in the &lt;code&gt;assets&lt;/code&gt; and &lt;code&gt;config&lt;/code&gt; volumes.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ script/prod up -d webserver prod_db
$ script/prod up -d --build prod_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you head to &lt;a href=&#34;http://localhost/&#34;&gt;localhost&lt;/a&gt; you should see the Nginx splash page, but that&amp;rsquo;s not the goal. The reason that you&amp;rsquo;re seeing this instead of our application is that we didn&amp;rsquo;t restart Nginx after we dropped off a new config for it to read. This is one occasion that I will actually say that using &lt;code&gt;docker-compose restart&lt;/code&gt; will work just fine for us:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ script/prod restart webserver&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if you head back to &lt;a href=&#34;http://localhost/&#34;&gt;localhost&lt;/a&gt; you should see the meal plan application being served up (with assets) although we didn&amp;rsquo;t specify a port.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Today we vastly improved the deployment of our rails application by having a web server serve our static assets and proxy requests to our application so that we don&amp;rsquo;t need to connect to port &lt;code&gt;3000&lt;/code&gt; directly. There&amp;rsquo;s still more improvement that can be done by digging deeper into Nginx, but for now, this works.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Rails – Deploying Rails (Part 8)</title>
      <link>https://coderjourney.com/learning-rails-deploying-rails-part-8/</link>
      <pubDate>Thu, 05 Jan 2017 17:30:40 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-rails-deploying-rails-part-8/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to take a big step with meal planning by deploying the application. Since our application is already built on top of Docker we will be using that as our means of deployment.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/pkiskHXb8U0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create production docker-compose file&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provision Docker host&lt;/strong&gt; in the cloud&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deploy our meal planner&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Our meal planning application isn&amp;rsquo;t exactly feature complete, but it&amp;rsquo;s in a good enough spot that we might want to get it out there for some people to beta test for us. For that to happen we need to put it onto a server that is publicly accessible. &lt;a href=&#34;https://heroku.com&#34;&gt;Heroku&lt;/a&gt; is a popular deployment target for Ruby on Rails applications because it is very easy to work with and requires very little knowledge from an operations standpoint, but since we&amp;rsquo;re already familiar with Docker we&amp;rsquo;re going to use that and deploy to our own server.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note:&lt;/em&gt; It is possible to use Docker to deploy to Heroku also, but I will leave that as an exercise for the reader if interested.&lt;/p&gt;

&lt;h2 id=&#34;prepping-the-application-for-production&#34;&gt;Prepping the Application for Production&lt;/h2&gt;

&lt;p&gt;Before we can actually deploy we need to make sure that our application can run in the production environment. Thankfully, we can run test deploys on our local docker machine before we ever provision a server and be &lt;em&gt;relatively&lt;/em&gt; certain that it will work in a production environment. We&amp;rsquo;ll start by creating a production specific docker-compose configuration that we&amp;rsquo;ll use for deployment only. We&amp;rsquo;ll start by copying our development configuration and then make some modifications:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ cp docker-compose.yml docker-compose.prod.yml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We only need to change a few lines. We can&amp;rsquo;t mount a local directory as a volume on a remote server so we need to remove that section. Additionally, we will want to use a separate list of environment variables in production than we use in development so we&amp;rsquo;ll specify a different &lt;code&gt;env_file&lt;/code&gt;. Lastly, we&amp;rsquo;ll ensure that the &lt;code&gt;RAILS_ENV&lt;/code&gt; is set to &lt;code&gt;production&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;services&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;prod_db&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/var/lib/postgresql/db-data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;prod_app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;build&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env.prod&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;depends_on&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;prod_db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can create the &lt;code&gt;.env.prod&lt;/code&gt; file by copying our original &lt;code&gt;.env&lt;/code&gt; file and changing the username/password:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ cp .env .env.prod&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;ll also want to generate a new password, and we can use ruby to do that:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose run --rm app ruby -r securerandom -e &lt;span class=&#34;s2&#34;&gt;&amp;#34;puts SecureRandom.base64(30)&amp;#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Copy the output of that command and use it in the new environment file, and also assign the &lt;code&gt;POSTGRES_HOST&lt;/code&gt; value to &lt;code&gt;prod_db&lt;/code&gt; for the time being.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;.env.prod&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;POSTGRES_USER=meal_planner
POSTGRES_PASSWORD=exh2uRzCrbjfRNj4GpiaZuToJa6QrFHCdmDbKLNe
POSTGRES_HOST=prod_db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re not quite finished though because we will need to set our &lt;code&gt;SECRET_KEY_BASE&lt;/code&gt; value and set the &lt;code&gt;RAILS_ENV&lt;/code&gt; to production. This is automatically set in development and test, but should be passed in as an environment variable in other application environments. We can generate that using &lt;code&gt;rake secret&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose run --rm app rake secret&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;.env.prod&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;POSTGRES_USER=meal_planner
POSTGRES_PASSWORD=exh2uRzCrbjfRNj4GpiaZuToJa6QrFHCdmDbKLNe
POSTGRES_HOST=prod_db
RAILS_ENV=production
SECRET_KEY_BASE=afaad8af5acc8841359153f01f970827e815def7e71d50fd5213bb8e2fcee4cc0c16d61bf30ec3a435d4849e1c4e666c653c5ddd6e407f95aa2fab938b8965b8&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;testing-production-locally&#34;&gt;Testing Production Locally&lt;/h2&gt;

&lt;p&gt;Now that the application has been configured with the environment variables that we need for production we can test this locally by creating the containers and running this the same way we normally would. A big difference here is that if we make any file changes we will need to rebuild the &lt;code&gt;prod_app&lt;/code&gt; image. First, we need to create our new database.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml build prod_app
... After the image is built
$ docker-compose -f docker-compose.prod.yml run --rm prod_app rake db:create
$ docker-compose -f docker-compose.prod.yml run --rm prod_app rake db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That should complete without any errors and we&amp;rsquo;ll now have a database. Next, we&amp;rsquo;ll start the application and make sure that we can visit the homepage. You&amp;rsquo;ll need to make sure that your containers for development are no longer running before doing this because we will be exposing the same port.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml up -d&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Visiting &lt;a href=&#34;http://localhost:3000&#34;&gt;http://localhost:3000/&lt;/a&gt; should show you our welcome page, but you&amp;rsquo;ll notice that it doesn&amp;rsquo;t have any of our styles. This is
happening because our production rails configuration is set to not serve static assets. Serving these assets is the job of a web server like nginx or apache and if we don&amp;rsquo;t have to have our ruby process do that then we won&amp;rsquo;t. For the time being though we&amp;rsquo;re going to set this up to be configurable with an environment variable so we can toggle this on an off as we need it.&lt;/p&gt;

&lt;h2 id=&#34;configuring-asset-handling&#34;&gt;Configuring Asset Handling&lt;/h2&gt;

&lt;p&gt;As of Rails 5 there is already an environment variable that can be used to determine if the rails application should serve up assets in the &lt;code&gt;/public&lt;/code&gt; directory. We will modify the &lt;code&gt;config/environments/production.rb&lt;/code&gt; file so that
also use that variable to optionally handle asset compilation if it&amp;rsquo;s necessary.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/environments/production.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;Rails&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;application&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;configure&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;# ... additional configuration left out for brevity&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Compress JavaScripts and CSS.&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;js_compressor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:uglifier&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;css_compressor&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:sass&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# Do not fallback to assets pipeline if a precompiled asset is missed.&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;assets&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;compile&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ENV&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;RAILS_SERVE_STATIC_FILES&amp;#39;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;present?&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# ... additional configuration left out for brevity&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we set the &lt;code&gt;RAILS_SERVE_STATIC_FILES&lt;/code&gt; value to &lt;code&gt;true&lt;/code&gt; in our environment file it will set our application to serve up and compile assets on the fly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;.env.prod&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;POSTGRES_USER=meal_planner
POSTGRES_PASSWORD=exh2uRzCrbjfRNj4GpiaZuToJa6QrFHCdmDbKLNe
POSTGRES_HOST=prod_db
RAILS_ENV=production
SECRET_KEY_BASE=afaad8af5acc8841359153f01f970827e815def7e71d50fd5213bb8e2fcee4cc0c16d61bf30ec3a435d4849e1c4e666c653c5ddd6e407f95aa2fab938b8965b8&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we&amp;rsquo;ve made a change to one of the ruby files we will need to rebuild the application before we can re-run it to make sure that our efforts were successful.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml stop prod_app
$ docker-compose -f docker-compose.prod.yml build prod_app
$ docker-compose -f docker-compose.prod.yml up -d prod_app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When you try to reload the application in browser you might not see anything, and if you check the logs using &lt;code&gt;docker logs mealplan_prod_app_1&lt;/code&gt; you might see something like the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;rm: cannot remove &amp;#39;/tmp/puma.pid&amp;#39;: No such file or directory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is caused by an issue in &lt;code&gt;script/start&lt;/code&gt; and we can fix that pretty easily:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;cp&#34;&gt;#!/bin/sh
&lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[[&lt;/span&gt; -a /tmp/puma.pid &lt;span class=&#34;o&#34;&gt;]]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;then&lt;/span&gt;
  rm /tmp/puma.pid
&lt;span class=&#34;k&#34;&gt;fi&lt;/span&gt;

rails server -b &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;.0.0.0 -P /tmp/puma.pid&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we will only delete the pid file if it already exists. If you rerun the docker &lt;code&gt;stop&lt;/code&gt;, &lt;code&gt;build&lt;/code&gt;, and &lt;code&gt;up&lt;/code&gt; commands again and reload the web page it will take a little longer than expected, but then render with the styles. That delay is from the assets being compiled on the first load, and subsequent page loads should be fast.&lt;/p&gt;

&lt;h2 id=&#34;creating-our-docker-host-in-digital-ocean&#34;&gt;Creating our Docker Host in Digital Ocean&lt;/h2&gt;

&lt;p&gt;Docker provides us with a really nice tool for building docker hosts easily in quite a few hosting providers. For this tutorial, we&amp;rsquo;re going to host with &lt;a href=&#34;https://m.do.co/c/3e5160725c43&#34;&gt;Digital Ocean&lt;/a&gt; (that link will get you a $10 credit for signing up) and creating our host using &lt;a href=&#34;https://docs.docker.com/machine/&#34;&gt;docker-machine&lt;/a&gt;. You&amp;rsquo;ll need to sign up with digital ocean before we begin because you&amp;rsquo;ll need to grab your API token. Once you have your account you can go &lt;a href=&#34;https://cloud.digitalocean.com/settings/api/tokens&#34;&gt;here&lt;/a&gt; to generate a new API token.&lt;/p&gt;

&lt;p&gt;I have my token store in the environment variable &lt;code&gt;DO_TOKEN&lt;/code&gt; (you can set that for yourself using &lt;code&gt;export DO_TOKEN=&amp;quot;YOUR_TOKEN&amp;quot;&lt;/code&gt;. Now that we have our API token, we can use &lt;code&gt;docker-machine&lt;/code&gt; to actually create a droplet for us and set it up to be a docker host for us.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine create --driver&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;digitalocean --digitalocean-access-token&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DO_TOKEN&lt;/span&gt; --digitalocean-size&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1gb meal-planner&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once that command has finished, it&amp;rsquo;ll make our life a little easier if we designate one terminal window/tab specifically to interacting with that docker host. From that window/tab run the following command to set docker to interact with that server instead of your local docker:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;nb&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;docker-machine env meal-planner&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;deploying-the-application&#34;&gt;Deploying the Application&lt;/h2&gt;

&lt;p&gt;Our terminal window is now set to connect to the proper server and we can go through the same steps that we went through on our local machine to get the application running in the cloud. This new docker host doesn&amp;rsquo;t have any images downloaded so it will take a little while the first time you run these commands.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml build prod_app
... After the image is built
$ docker-compose -f docker-compose.prod.yml run --rm prod_app rake db:create db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once our database is set up all that is left to do is run the application:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml up -d&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can find the docker host&amp;rsquo;s IP address and view our application running in the cloud. To get the IP address you can use the following command:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine ip meal-planner
&lt;span class=&#34;m&#34;&gt;104&lt;/span&gt;.236.250.214&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this case, I can go to &lt;a href=&#34;http://104.236.250.214:3000/&#34;&gt;http://104.236.250.214:3000/&lt;/a&gt; to view the application.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ve take our meal planning application from being nothing more than an ideal to have a lot of the functionality flushed out and being deployed publicly. This is the first iteration of an application like this, but you can take it quite a bit further and improve it in any number of ways. For our purposes though, this application is finished. Next week will improve the deployment of the application by layering Nginx into the mix as the web server, and that will conclude the introduction to Rails series.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Rails – Application Styling (Part 7)</title>
      <link>https://coderjourney.com/learning-rails-application-styling-part-7/</link>
      <pubDate>Wed, 21 Dec 2016 23:21:45 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-rails-application-styling-part-7/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to move our application from being completely unstyled to looking like something that people wouldn&amp;rsquo;t mind using. Since this tutorial series is about Rails we&amp;rsquo;ll learn how to interact with some additional front-end tools, but won&amp;rsquo;t necessarily cover all of the style details.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/smXmo44uHvw&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add Website Navigation&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pull in Bootstrap Gem&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Style application&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Styling our application won&amp;rsquo;t be the most difficult thing that we&amp;rsquo;ve done because we&amp;rsquo;re not here to learn more about CSS/SCSS or HTML. As of right now, the application is a little clunky to navigate around so we&amp;rsquo;ll start off by adding some navigation to allow a user to better move around the application. From there, we will be styling the main pages of our application. Although it&amp;rsquo;s a little cliche we will be using Twitter Bootstrap for our styles so that we don&amp;rsquo;t have to lay out a ton of CSS and we preemptively added some classes to our markup when we were writing it originally so that today&amp;rsquo;s work would be easier.&lt;/p&gt;

&lt;h2 id=&#34;installing-bootstrap&#34;&gt;Installing Bootstrap&lt;/h2&gt;

&lt;p&gt;There are multiple ways to work with front-end dependencies in Rails, but the built in one is by using sprockets and front-end packages wrapped in gems. If you&amp;rsquo;re coming from a mostly front-end development background then this will feel really wrong, and I completely understand where you&amp;rsquo;re coming from, but we won&amp;rsquo;t be covering the use of bower, yeoman, yarn, webpack, etc.&lt;/p&gt;

&lt;p&gt;The gem we will be using can be found &lt;a href=&#34;https://github.com/twbs/bootstrap-sass&#34;&gt;here&lt;/a&gt;. Let&amp;rsquo;s add this to our Gemfile now.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Gemfile&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;bootstrap-sass&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;~&amp;gt; 3.3.6&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We already have &lt;code&gt;sass-rails&lt;/code&gt; installed so we don&amp;rsquo;t need to worry about that portion of the README. After we rebuild our image and restart our application we&amp;rsquo;ll be set up to actually use Bootstrap in our application.&lt;/p&gt;

&lt;p&gt;With the gem installed we can now load this into our main sass file. First, we&amp;rsquo;re going to switch from having an &lt;code&gt;application.css&lt;/code&gt; to having an &lt;code&gt;application.scss&lt;/code&gt; file so that we can use native sass features.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we can clean out this file and import Bootstrap:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scss&#34; data-lang=&#34;scss&#34;&gt;&lt;span class=&#34;k&#34;&gt;@import&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;bootstrap-sprockets&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;@import&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;bootstrap&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lastly, we&amp;rsquo;ll set up our &lt;code&gt;application.js&lt;/code&gt; to load the additional Bootstrap JavaScripts:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-javascript&#34; data-lang=&#34;javascript&#34;&gt;&lt;span class=&#34;c1&#34;&gt;//= require jquery
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//= require bootstrap-sprockets
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//= require jquery_ujs
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;//= require_tree .
&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you refresh any page in the application now it will look slightly different based on the base styles provided by Bootstrap.&lt;/p&gt;

&lt;h2 id=&#34;adding-navigation&#34;&gt;Adding Navigation&lt;/h2&gt;

&lt;p&gt;Before we get too involved with styling our individual pages we&amp;rsquo;re going to work on our application layout so that there will be some shared navigation and each page will have a similar frame. We want the user to be able to access the following if signed in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Recipes&lt;/li&gt;
&lt;li&gt;Meal Plans&lt;/li&gt;
&lt;li&gt;Log Out&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If he/she isn&amp;rsquo;t logged in then the navigation should only show the &amp;ldquo;Sign In&amp;rdquo; option. Let&amp;rsquo;s tweak our &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt; to make this happen.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/layouts/application.html.erb&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;First we will modify some of the informational HTML tags, setting a language and a viewport:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;lang&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;MealPlan&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= csrf_meta_tags %&amp;gt;

    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= stylesheet_link_tag    &amp;#39;application&amp;#39;, media: &amp;#39;all&amp;#39; %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= javascript_include_tag &amp;#39;application&amp;#39; %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;meta&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;content&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;width=device-width, initial-scale=1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we&amp;rsquo;ll change out our header to be a bootstrap navigation item:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;header&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;nav&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;navbar navbar-default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;container-fluid&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;navbar-header&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Meal Planning&amp;#34;, root_path, class: &amp;#34;navbar-brand&amp;#34; %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;nav navbar-nav navbar-right&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% if signed_in? %&amp;gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Meal Plans&amp;#34;, meal_plans_path %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Recipes&amp;#34;, recipes_path %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Sign out&amp;#34;, sign_out_path, method: :delete %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% else %&amp;gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Sign In&amp;#34;, sign_in_path %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;nav&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;section&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;container&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;flash&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% flash.each do |key, value| %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;flash alert &amp;lt;%= alert_class(key) %&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= value %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= yield %&amp;gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will create a consistent layout and automatically style and of the flash messages that we create in our application, but we need to define the &lt;code&gt;alert_class&lt;/code&gt; method first.&lt;/p&gt;

&lt;p&gt;_app/helpers/application&lt;em&gt;helper.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;ApplicationHelper&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;alert_class&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flash_type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flash_type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;to_sym&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:notice&lt;/span&gt;
      &lt;span class=&#34;s2&#34;&gt;&amp;#34;alert-success&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:alert&lt;/span&gt;
      &lt;span class=&#34;s2&#34;&gt;&amp;#34;alert-warning&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;when&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:error&lt;/span&gt;
      &lt;span class=&#34;s2&#34;&gt;&amp;#34;alert-danger&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That added a lot more structure to our application and now we&amp;rsquo;re ready to tackle individual pages.&lt;/p&gt;

&lt;h2 id=&#34;styling-recipes&#34;&gt;Styling Recipes&lt;/h2&gt;

&lt;p&gt;When I think of recipes I actually think on Pinterest. That&amp;rsquo;s where a lot of people find recipes and I think mimicking that representation for our recipe index would be great. Thankfully, Bootstrap provides a &lt;a href=&#34;http://getbootstrap.com/components/#thumbnails&#34;&gt;thumbnail component&lt;/a&gt; that will get us most of the way there (I&amp;rsquo;ll leave the variable height blocks up to you). Let&amp;rsquo;s change our recipes to lay them out in rows of 3/2/1 in small panels depending on screen size (using the thumbnail component).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/recipes/index.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;title-container&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Recipes&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;New Recipe&amp;#34;, new_recipe_path, class: &amp;#34;btn btn-default&amp;#34; %&amp;gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;recipes&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @recipes.each do |recipe| %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;recipe&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;thumbnail&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;caption&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to truncate(recipe.name), recipe_path(recipe) %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= truncate(recipe.description, length: 150) %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Edit&amp;#34;, edit_recipe_path(recipe), class: &amp;#34;btn btn-default&amp;#34; %&amp;gt;
            &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Delete&amp;#34;, recipe_path(recipe), data: {
              confirm: &amp;#34;Are you sure you want to delete: #{recipe.name}?&amp;#34;,
            }, method: :delete %&amp;gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We did change up the markup a fair bit here, and we used the &lt;code&gt;truncate&lt;/code&gt; helper so that we can make our recipe boxes all of a specific size. For that we do need some additional CSS though that we&amp;rsquo;re going to add to our &lt;code&gt;application.scss&lt;/code&gt;. We&amp;rsquo;ll be using flexbox to help keep our layout sane and get our content to flow the way we expect it to.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/assets/stylesheets/application.scss&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scss&#34; data-lang=&#34;scss&#34;&gt;&lt;span class=&#34;nc&#34;&gt;.title-container&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;display&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;flex&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;justify-content&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;space-between&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;align-items&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;center&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;margin-bottom&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;20px&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;

  &lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
    &lt;span class=&#34;nt&#34;&gt;margin&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;nc&#34;&gt;.recipes&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;display&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;flex&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;flex-wrap&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;wrap&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;justify-content&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;space-around&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

&lt;span class=&#34;nc&#34;&gt;.recipe&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;width&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;%&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;min-width&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;300px&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &amp;ldquo;new&amp;rdquo; and &amp;ldquo;edit&amp;rdquo; views don&amp;rsquo;t have much in them, but we&amp;rsquo;ll want to wrap our titles in the &lt;code&gt;title-container&lt;/code&gt; class that we created so that our application looks consistent.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/recipes/new.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;title-container&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;New Recipe&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= render partial: &amp;#34;form&amp;#34; %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The first thing we&amp;rsquo;ll want to do is get it styled with all of the proper bootstrap form classes and then see what we can do from there. Mostly just adding &lt;code&gt;form-control&lt;/code&gt; classes and setting the submit button to look like a bootstrap button.&lt;/p&gt;

&lt;p&gt;_app/views/recipes/&lt;em&gt;form.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= render partial: &amp;#34;shared/errors&amp;#34; %&amp;gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form_for @recipe do |form| %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.label :name %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.text_field :name, class: &amp;#34;form-control&amp;#34; %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.label :description %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.text_area :description, class: &amp;#34;form-control&amp;#34; %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.submit class: &amp;#34;btn btn-primary&amp;#34; %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you submit the form now though you can see that our errors container isn&amp;rsquo;t being rendered with any flare and bootstrap gives us some styles to make that more apparent.&lt;/p&gt;

&lt;p&gt;_app/views/shared/&lt;em&gt;errors.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% if @errors.present? %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;alert alert-danger errors&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @errors.each do |error| %&amp;gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= error %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The display of a recipe isn&amp;rsquo;t actually too bad in the recipe show page so I&amp;rsquo;ll leave adjusting this styles up to the reader. You&amp;rsquo;ll probably just want to change how the controls are displayed.&lt;/p&gt;

&lt;h2 id=&#34;styling-meal-plans&#34;&gt;Styling Meal Plans&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ll tackle the &amp;ldquo;new&amp;rdquo; view for meal plans to start. This view is a bit more complicated than the edit is because we have a second form, but it won&amp;rsquo;t take us that long to tweak.&lt;/p&gt;

&lt;p&gt;_app/views/meal&lt;em&gt;plans/new.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;title-container&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;New Meal Plan&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;panel panel-default&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;panel-body&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form_for @meal_plan, url: new_meal_plan_path, method: &amp;#34;GET&amp;#34;, html: { class: &amp;#34;form-inline&amp;#34; } do |form| %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.label :start_date %&amp;gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.text_field :start_date, type: &amp;#34;date&amp;#34;, class: &amp;#34;form-control&amp;#34; %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.label :end_date %&amp;gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.text_field :end_date, type: &amp;#34;date&amp;#34;, class: &amp;#34;form-control&amp;#34; %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.submit &amp;#34;Generate Plan&amp;#34;, class: &amp;#34;btn btn-default&amp;#34; %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= render(partial: &amp;#34;form&amp;#34;) %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This changes our top form to be in a panel to make it visually separate and we also make it an inline form since it&amp;rsquo;s so small.&lt;/p&gt;

&lt;p&gt;Next, we&amp;rsquo;ll tackle the actual form, which currently looks horrible because we used the wrong class originally on our form groupings.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/meal_plans/_form.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= render partial: &amp;#34;shared/errors&amp;#34; %&amp;gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form_for @meal_plan, html: { class: &amp;#34;form-horizontal&amp;#34; } do |form| %&amp;gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.hidden_field :start_date %&amp;gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.hidden_field :end_date %&amp;gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meals&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.fields_for :meals do |meal_fields| %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meal&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.hidden_field :id %&amp;gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.hidden_field :date %&amp;gt;

        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group margin-vertical-none&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;col-sm-11 col-sm-offset-1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= localize(meal_fields.object.date) %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.label :recipe_id, class: &amp;#34;col-sm-1 control-label&amp;#34; %&amp;gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;col-sm-11&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
            &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.select :recipe_id, current_user.recipe_options, {}, class: &amp;#34;form-control&amp;#34; %&amp;gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;col-sm-11 col-sm-offset-1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.submit class: &amp;#34;btn btn-primary&amp;#34; %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This form probably has the most changes of any of our pages to improve the layout of the items. We&amp;rsquo;re not quite finished. We need to create this new class to remove vertical margin.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/assets/stylesheets/application.scss&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-scss&#34; data-lang=&#34;scss&#34;&gt;&lt;span class=&#34;nc&#34;&gt;.margin-vertical-none&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;margin-top&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;important&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
  &lt;span class=&#34;nt&#34;&gt;margin-bottom&lt;/span&gt;&lt;span class=&#34;nd&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nt&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;important&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Additionally, now is the time for us to improve how we display times. We called &lt;code&gt;localize&lt;/code&gt; on the date for each Meal, but what does that do? It uses the date format that is localized for the user&amp;rsquo;s locale. We set this up by modifying the &lt;code&gt;confing/locales/en.yml&lt;/code&gt; file and setting the date format.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/locales/en.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;en&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;date&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;formats&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;default&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;%m/%d/%Y&amp;#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This doesn&amp;rsquo;t quite deal with all of it though. We also want to change how dates are rendered into strings to handle the &lt;code&gt;to_s&lt;/code&gt; on &lt;code&gt;MealPlan&lt;/code&gt;. So we need to utilize the &lt;code&gt;localize&lt;/code&gt; method on any date we render in the views, and use &lt;code&gt;I18n.localize&lt;/code&gt; when we interpolate a Date into a String in our models. We&amp;rsquo;ll start with &lt;code&gt;MealPlan&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;_app/models/meal&lt;em&gt;plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;to_s&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;I18n&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;localize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; - &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;I18n&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;localize&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now in our views when we use &lt;code&gt;&amp;lt;%= @meal_plan %&amp;gt;&lt;/code&gt; it will always render the date&amp;rsquo;s in the proper format. I&amp;rsquo;ll leave it up to you to click around the site and see what other areas you would need to change to display all of the dates properly.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;We went through most of the pages in our application to apply some styles and make the application look better. These changes included utilizing some flex-box and Bootstrap styles. Additionally, we took a glimpse at some of the internationalization (I18n) features that we have at our disposal. There are still some more styles that need to be written and I&amp;rsquo;ll leave that up to you (or you can check the associations pull-request). Next week we will deploy this application to a server on Digital Ocean.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Rails – Meal Plan UI (Part 6)</title>
      <link>https://coderjourney.com/learning-rails-meal-plan-ui-part-6/</link>
      <pubDate>Thu, 15 Dec 2016 12:31:29 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-rails-meal-plan-ui-part-6/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to build on the meal plan functionality from the previous tutorial and create the UI for a user to view and create new meal plans.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/RqTLJP6cZyw&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Display a Meal Plan&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Allow a User&lt;/strong&gt; to create a meal plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ability to have a &lt;code&gt;MealPlan&lt;/code&gt; pre-fill its own meals took out the most complicated portion of a meal plan, and now we get to put a face on that functionality. Each &lt;code&gt;MealPlan&lt;/code&gt; is not set to be specific length so we need to have a fairly dynamic user interface that can handle multiple lengths.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s how I imagine we can work through creating a meal plan:&lt;/p&gt;

&lt;p&gt;1) Specify the meal plan start and end dates (default to today, and six days from now). Submit the form.
2) Return a form that has a pre-filled &lt;code&gt;Meal&lt;/code&gt; for each date in the date range.
3) Allow user to customize the recipe in each meal before creating the &lt;code&gt;MealPlan&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;After the &lt;code&gt;MealPlan&lt;/code&gt; has been created we will allow people to delete the plan and edit the recipes. We&amp;rsquo;ll use a &lt;code&gt;_form&lt;/code&gt; partial to handle the new/edit views since they&amp;rsquo;ll be of dynamic length based on the meal plan duration. We&amp;rsquo;ll be creating all of the CRUD actions for &lt;code&gt;MealPlan&lt;/code&gt; in the same way that we did for &lt;code&gt;Recipe&lt;/code&gt; a few tutorials back.&lt;/p&gt;

&lt;h2 id=&#34;creating-a-new-meal-plan&#34;&gt;Creating a New Meal Plan&lt;/h2&gt;

&lt;p&gt;The first thing we&amp;rsquo;re going to work on will be the initial creation of a &lt;code&gt;MealPlan&lt;/code&gt;. The previous tutorial took us through flushing out a simple plan before we ever display it to the user, and now we get to utilize that.&lt;/p&gt;

&lt;p&gt;To start we need to create our routes and controller.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/routes&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;resources&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal_plans&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;app/controllers/meal_plans_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;MealPlansController&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;before_action&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:require_login&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;new&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plans&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;start_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:start_date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;today&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;end_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:end_date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;||&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;days&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from_now&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;to_date&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build_meals&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We learned last time that we need to remember to require a user to be logged in for them to be able to work with things such as recipes or meal plans.&lt;/p&gt;

&lt;p&gt;By default we&amp;rsquo;re going to create meal plans that are for a whole week, and before we render the view we want to call &lt;code&gt;build_meals&lt;/code&gt; so that we have some pre-populated &lt;code&gt;Meal&lt;/code&gt; objects.&lt;/p&gt;

&lt;p&gt;The view for creating a new &lt;code&gt;MealPlan&lt;/code&gt; will actually be a little different than what we did for &lt;code&gt;Recipe&lt;/code&gt;, it won&amp;rsquo;t be the same view that we render for edit later on. We will actually have two forms on the page:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A form to select the date range. Submitting this will re-render the new meal plan page with the proper number of meals.&lt;/li&gt;
&lt;li&gt;The Meal Plan form that allows you to customize the meals that were pre-populated.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3 id=&#34;new-meal-plan-forms&#34;&gt;New Meal Plan Forms&lt;/h3&gt;

&lt;p&gt;Let&amp;rsquo;s build write out the date range form first.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/meal_plans/new.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;New Meal Plan&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form_for @meal_plan, url: new_meal_plan_path, method: &amp;#34;GET&amp;#34; do |form| %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-control&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.label :start_date %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.text_field :start_date, type: &amp;#34;date&amp;#34; %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-control&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.label :end_date %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.text_field :end_date, type: &amp;#34;date&amp;#34; %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;action&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.submit &amp;#34;Generate Plan&amp;#34; %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= render partial: &amp;#34;form&amp;#34; %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that this is a pretty standard form other than the fact that we&amp;rsquo;re defining a &lt;code&gt;url&lt;/code&gt; and &lt;code&gt;method&lt;/code&gt; in our &lt;code&gt;form_for&lt;/code&gt; call. We&amp;rsquo;re doing this because by default it would create a form that pointed to the &amp;ldquo;create&amp;rdquo; action in our controller and use the &amp;ldquo;POST&amp;rdquo; method. We want this to send our new dates to the &amp;ldquo;new&amp;rdquo; action and re render the page so we had to customize this a bit.&lt;/p&gt;

&lt;p&gt;Next, we&amp;rsquo;ll create the form for customizing the meals. Since we know we&amp;rsquo;ll be working with this portion of the page in the &amp;ldquo;edit&amp;rdquo; flow we&amp;rsquo;ll go ahead and put it in the &lt;code&gt;_form.html.erb&lt;/code&gt; partial now.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/meal_plans/_form.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% if @errors.present? %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;errors&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @errors.each do |error| %&amp;gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= error %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form_for @meal_plan do |form| %&amp;gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.hidden_field :start_date %&amp;gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.hidden_field :end_date %&amp;gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meals&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.fields_for :meals do |meal_fields| %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meal&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.hidden_field :id %&amp;gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.hidden_field :date %&amp;gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.object.date.to_s %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-control&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.label :recipe_id %&amp;gt;
          &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal_fields.select :recipe_id, current_user.recipe_options %&amp;gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.submit %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This form is quite a bit more complicated than our previous forms. We need to store off a good deal of information in &lt;code&gt;hidden_fields&lt;/code&gt;, but the really interesting part is the &lt;code&gt;form.fields_for :meals&lt;/code&gt; block. &lt;code&gt;fields_for&lt;/code&gt; let&amp;rsquo;s us iterate through each of the &lt;code&gt;Meal&lt;/code&gt; objects that we&amp;rsquo;ve created. &lt;code&gt;meal_fields&lt;/code&gt; is an object that works just like our original form builder (&lt;code&gt;form&lt;/code&gt;) except that it sets up the name for each field a little differently. We have hidden fields for the id of both the &lt;code&gt;MealPlan&lt;/code&gt; and each &lt;code&gt;Meal&lt;/code&gt; because we will need those when we get around to allowing a meal plan to be edited.&lt;/p&gt;

&lt;p&gt;We are calling a method on &lt;code&gt;current_user&lt;/code&gt; that doesn&amp;rsquo;t actually exist yet that will render out the options for the select box. Select fields in rails expect to receive and array of arrays in the following shape:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Displayed Name 1&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hidden_value1&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
  &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Displayed Name 2&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;hidden_value2&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To do this with the user&amp;rsquo;s &lt;code&gt;Recipe&lt;/code&gt; objects we&amp;rsquo;ll need to return the recipe name and the recipe id. Let&amp;rsquo;s add that method to &lt;code&gt;User&lt;/code&gt; now.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/user.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;recipe_options&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&#34;meal-plan-create-action&#34;&gt;Meal Plan Create Action&lt;/h3&gt;

&lt;p&gt;Now that we have our forms we should be able to actually generate the &lt;code&gt;MealPlan&lt;/code&gt;. Let&amp;rsquo;s create our &lt;code&gt;create&lt;/code&gt; and &lt;code&gt;meal_plan_params&lt;/code&gt; methods:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/meal_plans_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;create&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plans&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plan_params&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;redirect_to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meal_plan_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;notice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Meal plan created!&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@errors&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;full_messages&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:new&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

&lt;span class=&#34;kp&#34;&gt;private&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;meal_plan_params&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;permit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;:start_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;:end_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
    &lt;span class=&#34;ss&#34;&gt;meals_attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;:date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;
      &lt;span class=&#34;ss&#34;&gt;:recipe_id&lt;/span&gt;
    &lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There really isn&amp;rsquo;t a whole lot going on in the &lt;code&gt;create&lt;/code&gt; action that we haven&amp;rsquo;t seen before, but &lt;code&gt;meal_plan_params&lt;/code&gt; does look a different. Since we used &lt;code&gt;fields_for&lt;/code&gt; in our form we&amp;rsquo;re going to be receiving an array of &lt;code&gt;Meal&lt;/code&gt; object fields when the form is submitted and we need to allow those to come through the strong parameters. We&amp;rsquo;re not quite done though, because the &lt;code&gt;MealPlan&lt;/code&gt; model doesn&amp;rsquo;t know that it should be on the look out for &lt;code&gt;meals_attributes&lt;/code&gt;. We need to add a line to &lt;code&gt;MealPlan&lt;/code&gt; before we continue.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/meal_plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;accepts_nested_attributes_for&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meals&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you submit the form now, you won&amp;rsquo;t see an error, but the form will re-render. This happens because our &lt;code&gt;Meal&lt;/code&gt; objects can&amp;rsquo;t save. This happens because of the
we&amp;rsquo;re not associating the uncreated &lt;code&gt;MealPlan&lt;/code&gt; to the uncreated &lt;code&gt;Meal&lt;/code&gt;. We can hook this up by adding another key to the &lt;code&gt;has_many&lt;/code&gt; and &lt;code&gt;belongs_to&lt;/code&gt; lines of our models:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/meal_plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;has_many&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meals&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;order&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;inverse_of&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And in the &lt;code&gt;Meal&lt;/code&gt; model:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/meal.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;inverse_of&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meals&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we submit our form we should successfully create our meal plan and receive the error that we don&amp;rsquo;t have a &lt;code&gt;show&lt;/code&gt; action. Before we build &lt;code&gt;show&lt;/code&gt; though let&amp;rsquo;s clean up our view a little by removing the duplication in our application when it comes to rendering errors.&lt;/p&gt;

&lt;h3 id=&#34;drying-up-form-errors&#34;&gt;DRYing Up Form Errors&lt;/h3&gt;

&lt;p&gt;Our form partial and the recipe form share the same common error displaying markup and logic. We can extract that out so that when we change it both of the forms will be updated. Let&amp;rsquo;s create a subdirectory in &lt;code&gt;views&lt;/code&gt; to hold our shared views (called &lt;code&gt;shared&lt;/code&gt;)&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mkdir -p app/views/shared&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we&amp;rsquo;ll create a new partial called &lt;code&gt;_errors.html.erb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/shared/_errors.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% if @errors.present? %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;errors&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @errors.each do |error| %&amp;gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= error %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now in the meal plan and recipe &lt;code&gt;_form&lt;/code&gt; partials replace the error rendering block with a new &lt;code&gt;render partial&lt;/code&gt; call.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= render partial: &amp;#34;shared/errors&amp;#34; %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;showing-listing-meal-plans&#34;&gt;Showing &amp;amp; Listing Meal Plans&lt;/h2&gt;

&lt;p&gt;Displaying our meal plan won&amp;rsquo;t be too different from what we&amp;rsquo;ve done in the past. Here&amp;rsquo;s the &lt;code&gt;show&lt;/code&gt; action:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/meal_plans_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;show&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plans&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here&amp;rsquo;s the corresponding view:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/meal_plans/show.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Meal Plan: &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= @meal_plan %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Meals&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meals&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @meal_plan.meals.each do |meal| %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meal&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal.date %&amp;gt; - &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to meal.recipe, recipe_path(meal.recipe) %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;recipe-actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Edit Meal Plan&amp;#34;, edit_meal_plan_path(@meal_plan) %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Delete&amp;#34;, meal_plan_path(@meal_plan), data: {
      confirm: &amp;#34;Are you sure you want to delete meal plan: #{@meal_plan}?&amp;#34;,
    }, method: :delete %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re trying to create a link to a meal plan by passing it in as the first argument to &lt;code&gt;link_to&lt;/code&gt;. From a programmer point of view this is great, but unfortunately that won&amp;rsquo;t quite work as expected out of the gate. &lt;code&gt;link_to&lt;/code&gt; is going to look for the String representation of the first argument and render that. With that knowledge in mind we can customize &lt;code&gt;MealPlan&lt;/code&gt; and the way that it displays itself as a String.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/meal_plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;to_s&lt;/span&gt;
  &lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_date&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; - &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end_date&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now when we pass a &lt;code&gt;MealPlan&lt;/code&gt; object into a helper that renders a string or simple render it to the page using a &lt;code&gt;&amp;lt;%= meal_plan %&amp;gt;&lt;/code&gt; we will see a human readable start date and end date.&lt;/p&gt;

&lt;p&gt;We will also define &lt;code&gt;to_s&lt;/code&gt; on &lt;code&gt;Recipe&lt;/code&gt; so that it prints out the name.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/recipe.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;to_s&lt;/span&gt;
  &lt;span class=&#34;nb&#34;&gt;name&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&#34;listing-meal-plans&#34;&gt;Listing Meal Plans&lt;/h3&gt;

&lt;p&gt;Before we go about listing out meal plans we should think about what makes that index view for meal plans useful. When a user goes to this page what they probably want to see is his/her previous weeks, but more importantly the currently active plan. Because of this we&amp;rsquo;re not simply going to return a list to the view to have it rendered.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s the &lt;code&gt;index&lt;/code&gt; action:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/meal_plans_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;index&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@current_meal_plan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plans&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;where&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;start_date &amp;lt;= ? AND end_date &amp;gt;= ?&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;today&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;today&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;first&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@meal_plans&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plans&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;order&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;start_date desc&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to use a custom SQL query in our &lt;code&gt;where&lt;/code&gt; statement to ensure that we&amp;rsquo;re finding the currently active meal plan (or one of them). As for the rest of the &lt;code&gt;@meal_plans&lt;/code&gt; we just want to make sure that we&amp;rsquo;re showing the most recent plans first.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s take a look at the view that will display the plans.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/meal_plans/index.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Meal Plans&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% if @current_meal_plan.present? %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Current Meal Plan&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meals&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @current_meal_plan.meals.each do |meal| %&amp;gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meal&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= meal.date %&amp;gt; - &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to meal.recipe.to_s, recipe_path(meal.recipe) %&amp;gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;All Meal Plans&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @meal_plans.each do |meal_plan| %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;meal-plan&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to meal_plan, meal_plan_path(meal_plan) %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;New Meal Plan&amp;#34;, new_meal_plan_path %&amp;gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;deleting-a-meal-plan&#34;&gt;Deleting a Meal Plan&lt;/h2&gt;

&lt;p&gt;Similarly to how we allow a user to delete a recipe, we will allow them to delete meal plans that they no longer want. The view logic already exists to make this work so we need to implement the controller action.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/meal_plans_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;destroy&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plans&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destroy&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;redirect_to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meal_plans_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;notice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Meal plan deleted!&amp;#34;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This basically matches what we&amp;rsquo;ve done before. Remember how we create a &lt;code&gt;Meal&lt;/code&gt; for each date in the &lt;code&gt;MealPlan&lt;/code&gt;? We should probably delete those whenever we delete the parent &lt;code&gt;MealPlan&lt;/code&gt;. Thankfully, Rails/ActiveRecord makes this easy for use to set up on the association.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/meal_plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;has_many&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meals&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;order&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;},&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;inverse_of&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;dependent&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:destroy&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Adding the &lt;code&gt;dependent: :destroy&lt;/code&gt; portion ensures that when this object is destroyed that it also destroys the meals.&lt;/p&gt;

&lt;h2 id=&#34;editing-a-meal-plan&#34;&gt;Editing a Meal Plan&lt;/h2&gt;

&lt;p&gt;Lastly, we need to allow for a user to edit a meal plan. Here&amp;rsquo;s the edit view:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/meal_plans/edit.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Edit Meal Plan: &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= @meal_plan %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= render(partial: &amp;#34;form&amp;#34;) %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now onto the controller actions (&lt;code&gt;edit&lt;/code&gt; &amp;amp; &lt;code&gt;update&lt;/code&gt;). These should be looking familiar by now:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/meal_plans_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;edit&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plans&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;update&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plans&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update_attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meal_plan_params&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;redirect_to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meal_plan_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;notice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Meal plan updated!&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@errors&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;full_messages&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:edit&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;That&amp;rsquo;s the whole thing, we&amp;rsquo;ve successfully implemented the CRUD interactions for meal plans. Since this isn&amp;rsquo;t the first time we&amp;rsquo;ve implemented CRUD we went through this pretty quickly, but there were a few new things shown today:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customizing how an object is rendered to the page via &lt;code&gt;to_s&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Accepting nested attributes as part of a form submission.&lt;/li&gt;
&lt;li&gt;How to potentially clean up views by extracting shared partials. We&amp;rsquo;ve seen partials before but they were always used by views in the same controller so &lt;code&gt;shared/errors&lt;/code&gt; is a little different.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you&amp;rsquo;ve enjoyed this tutorial, next week we&amp;rsquo;ll take a detour from adding new functionality to the application to improve the aesthetics and usability of our pages.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Rails – Modeling Meal Plans (Part 5)</title>
      <link>https://coderjourney.com/learning-rails-modeling-meal-plans-part-5/</link>
      <pubDate>Thu, 08 Dec 2016 12:32:53 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-rails-modeling-meal-plans-part-5/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to start developing our main feature: meal planning. We&amp;rsquo;ll use test driven development to build out how a meal plan should work.&lt;/p&gt;

&lt;!-- more --&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/lkzYfPzEAHM&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Test Drive&lt;/strong&gt; the behavior of a meal plan.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Database modeling&lt;/strong&gt; a meal plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meal planning is the bread and butter of our application so we&amp;rsquo;re going to spend quite a bit of time thinking through how we&amp;rsquo;re going to model this so that it makes sense.&lt;/p&gt;

&lt;p&gt;We need to find a way to structure a meal plan in our database and create a good interface for us to use a meal plan to build out a sane list of recipes to cook.&lt;/p&gt;

&lt;h2 id=&#34;renaming-our-application&#34;&gt;Renaming our Application&lt;/h2&gt;

&lt;p&gt;Before we get too far we&amp;rsquo;re going to need to make a change to our application config. When we generated the rails application we used the name of &lt;code&gt;meal_plan&lt;/code&gt; which created a module for us to house our application configuration. This module is named &lt;code&gt;MealPlan&lt;/code&gt; and because of that we can&amp;rsquo;t create a model named &lt;code&gt;MealPlan&lt;/code&gt;. We&amp;rsquo;re going to change this module name to be &lt;code&gt;MealPlanner&lt;/code&gt;. Here&amp;rsquo;s the new &lt;code&gt;application.rb&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/application.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;require_relative&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;boot&amp;#39;&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rails&amp;#34;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Pick the frameworks you want:&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;active_model/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;active_job/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;active_record/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;action_controller/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;action_mailer/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;action_view/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;action_cable/engine&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sprockets/railtie&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Require the gems listed in Gemfile, including any gems&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# you&amp;#39;ve limited to :test, :development, or :production.&lt;/span&gt;
&lt;span class=&#34;no&#34;&gt;Bundler&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Rails&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;groups&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;MealPlanner&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Application&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Rails&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Application&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# Settings in config/environments/* take precedence over those specified here.&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# Application configuration should go into files in config/initializers&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# -- all .rb files in that directory are automatically loaded.&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;generators&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;test_framework&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:minitest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;modeling-a-meal-plan&#34;&gt;Modeling a Meal Plan&lt;/h2&gt;

&lt;p&gt;Up until now we haven&amp;rsquo;t really thought about what a meal plan consisted of, but in order for us to model it in our database we need to lay out what it means to be a meal plan. Here are the requirements that I can think of off hand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start Date&lt;/li&gt;
&lt;li&gt;End Date&lt;/li&gt;
&lt;li&gt;List of Recipes&lt;/li&gt;
&lt;li&gt;User&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That seems pretty simple, but it&amp;rsquo;s going to require us to create a few different database tables. The &lt;code&gt;meal_plans&lt;/code&gt; table isn&amp;rsquo;t actually going to have much on it besides the &lt;code&gt;start_date&lt;/code&gt; and &lt;code&gt;end_date&lt;/code&gt;. The more involve model will actually be the &lt;code&gt;Meal&lt;/code&gt; model which will act to join together a &lt;code&gt;Recipe&lt;/code&gt; and a &lt;code&gt;MealPlan&lt;/code&gt;. Our &lt;code&gt;Meal&lt;/code&gt; model will need to have the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;date&lt;/li&gt;
&lt;li&gt;recipe_id&lt;/li&gt;
&lt;li&gt;meal_plan_id&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need the date so that we know when we&amp;rsquo;re planning to cook the recipe. The &lt;code&gt;Meal&lt;/code&gt; will hold onto both the &lt;code&gt;meal_plan_id&lt;/code&gt; and &lt;code&gt;recipe_id&lt;/code&gt; because recipes will be on numerous meal plans. We could get around this by having the &lt;code&gt;MealPlan&lt;/code&gt; model have seven different recipe columns (&lt;code&gt;monday_recipe&lt;/code&gt;, &lt;code&gt;tuesday_recipe&lt;/code&gt;, etc), but this is less than ideal because what do we do when we also want to plan out lunches instead of just dinner? By having a separate model to associate recipes and meal plans we can be more explicit about what a meal is and that will allow us to be flexible moving forward.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s create these models now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rails g migration create_meal_plans
      invoke  active_record
      create    db/migrate/20161126154052_create_meal_plans.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Modifying the migration that was created we&amp;rsquo;ll add our date fields.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;db/migrate/20161126154052_create_meal_plans.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;CreateMealPlans&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Migration&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;change&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;create_table&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal_plans&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;date&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:start_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;date&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:end_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;references&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;foreign_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timestamps&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can generate our &lt;code&gt;meals&lt;/code&gt; table:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rails g migration create_meals
      invoke  active_record
      create    db/migrate/20161126154355_create_meals.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;db/migrate/20161126154355_create_meals.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;CreateMeals&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Migration&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;change&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;create_table&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meals&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;date&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;references&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;foreign_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;references&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;foreign_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timestamps&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we have two new models we will go ahead and also create our factories now, leaving the implementations empty for a second:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rails g factory_girl:model MealPlan
      create  test/factories/meal_plans.rb
$ rails g factory_girl:model Meal
      create  test/factories/meals.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we&amp;rsquo;ll run our migrations and get ready to test drive these new models:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;rake db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;validating-the-mealplan-and-meal-models&#34;&gt;Validating the MealPlan and Meal Models&lt;/h2&gt;

&lt;p&gt;The initial set up of our &lt;code&gt;MealPlan&lt;/code&gt; model will be pretty simple so we&amp;rsquo;re going to quickly write the tests for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/model/meal_plan_test.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test_helper&amp;#34;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;MealPlan&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;validity&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;MealPlan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;before&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;valid?&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires a start_date&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:start_date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires an end_date&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:end_date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires a user&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can implement this right away based on what we&amp;rsquo;ve learned in a previous tutorial.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/model/meal_plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;MealPlan&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:start_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:end_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Moving onto &lt;code&gt;Meal&lt;/code&gt; we&amp;rsquo;ll have similarly simple tests to write:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/models/meal_test.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test_helper&amp;#34;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Meal&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;validity&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Meal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;before&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;valid?&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires a date&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires a meal_plan&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires a recipe&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The initial implementation for &lt;code&gt;Meal&lt;/code&gt; is also simple:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/model/meal.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Meal&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;generating-a-meal-plan&#34;&gt;Generating a Meal Plan&lt;/h2&gt;

&lt;p&gt;While we will definitely allow users to create meal plans customizing all of the recipes that are used, but we&amp;rsquo;re really wanting meal planning to take little thought so we&amp;rsquo;ll generate the initial list of recipes ourselves. Thankfully we can write tests to ensure that this works. Let&amp;rsquo;s open the test file for &lt;code&gt;MealPlan&lt;/code&gt; back up and go through what we would like it to look like to generate a meal plan.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/models/meal_plan_test.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test_helper&amp;#34;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;MealPlan&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;# Validation tests ...&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;generating a weekly plan&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;before&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;times&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;populates a meal for each date between start and end&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_equal&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build_meals&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_equal&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running the test right now will show you that we haven&amp;rsquo;t implemented our factory yet, so let&amp;rsquo;s do that now:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/factories/meal_plans.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;factory&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;start_date&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;today&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;end_date&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;days&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from_now&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;association&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Running the tests now (&lt;code&gt;rake tests&lt;/code&gt;), we get the error that &lt;code&gt;build_meals&lt;/code&gt; doesn&amp;rsquo;t exist, which is just what we needed. Let&amp;rsquo;s follow strict TDD and add an empty method.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/meal_plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;build_meals&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With that we get an expected error saying that we expected 7 but got 0. Now we get to actually implement this method. We need to create a meal for each date so we can use a ruby range for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/meal_plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;build_meals&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;user_recipe_ids&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pluck&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;each&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;available_recipe_ids&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;user_recipe_ids&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;recipe_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;available_recipe_ids&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will get our test passing, but just looking at this it won&amp;rsquo;t handle the case where a user doesn&amp;rsquo;t have enough recipes to fill out a full week. Let&amp;rsquo;s write some tests to handle that and tweak this to work.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/models/meal_plan_test.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;  &lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;generating a weekly plan&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;before&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;times&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;populates a meal for each date between start and end&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_equal&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build_meals&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_equal&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;builds valid meals&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build_meals&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;all?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:valid?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_equal&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;uses unique recipes&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build_meals&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;uniq_ids&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uniq&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;uniq_ids&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_equal&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;with more days than recipes&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:meal_plan&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;end_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;days&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;from_now&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;build valid meals&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build_meals&lt;/span&gt;

        &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;all?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:valid?&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_equal&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;reuses recipes where necessary&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build_meals&lt;/span&gt;

        &lt;span class=&#34;n&#34;&gt;uniq_ids&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meal_plan&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uniq&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;uniq_ids&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_equal&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;
      &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our extra test cases make this work by extending the length of the meal plan to have more days than recipes we created. These two tests will fail because we will attempt to build meals with &lt;code&gt;nil&lt;/code&gt; for the recipe_id. Here&amp;rsquo;s how we can fix this:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/meal_plan.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;build_meals&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;user_recipe_ids&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pluck&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;start_date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;..&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;end_date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;each&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;unused_recipes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;user_recipe_ids&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;map&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;available_recipes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unused_recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;empty?&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;?&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;user_recipe_ids&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unused_recipes&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;meals&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;date&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;recipe_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;available_recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sample&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This change will change the recipe ids we pull from after we&amp;rsquo;ve used all of the unique ones, and will get our tests passing.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ve created a few more models that we&amp;rsquo;ll use to create a useful meal planning application and we wrote some logic to actually randomize a list of meals. In the next tutorial we&amp;rsquo;ll use this logic to build out a meal plan and pre-populate the user interface while still allowing the user to customize the recipes that are being used.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Rails – Recipes Controller and Views (Part 4)</title>
      <link>https://coderjourney.com/learning-rails-recipes-controller-and-views/</link>
      <pubDate>Tue, 29 Nov 2016 15:05:49 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-rails-recipes-controller-and-views/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to use the Recipe that we created in the previous controller, setting up controller actions and views so that a user can create and manage his or her recipes.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/KlyObpu0rVc&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create CRUD actions&lt;/strong&gt; for the Recipe model.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Restrict Routes&lt;/strong&gt; to only logged in Users.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the previous tutorial we did most of the heavy lifting around Recipes. Knowing that our data makes sense, and preventing obvious data corruption problems was a good start. Today we&amp;rsquo;re going to create the common workflow views that a User will take to manipulate recipes.&lt;/p&gt;

&lt;p&gt;For this to work we&amp;rsquo;re going to need to set up the following routes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/recipes&lt;/code&gt; - Listing out all of the recipes that a User has. Will also show a link to create a new recipe.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/recipes/new&lt;/code&gt; - Shows a form for creating a new Recipe. Should be able to cancel and return to the listing.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/recipes/:id&lt;/code&gt; - Shows the details for an individual recipe. Should also show buttons to edit and delete the recipe.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of the interactions we&amp;rsquo;ve just described are often referred to as &amp;ldquo;CRUD&amp;rdquo; which stands for &lt;strong&gt;C&lt;/strong&gt;reate &lt;strong&gt;R&lt;/strong&gt;ead &lt;strong&gt;U&lt;/strong&gt;pdate &lt;strong&gt;D&lt;/strong&gt;elete.&lt;/p&gt;

&lt;h2 id=&#34;recipes-controller-views-and-routes&#34;&gt;Recipes Controller, Views, and Routes&lt;/h2&gt;

&lt;p&gt;Before we get too far into the code that will actually perform the CRUD we&amp;rsquo;ll set up the portions that view content to the user. We&amp;rsquo;re not going to spend any time making this look pretty, but we will make sure that the html structure is semantic so that when we come back later to style this we don&amp;rsquo;t have a bad time.&lt;/p&gt;

&lt;p&gt;To start we know we&amp;rsquo;re going to need a new view directory for &lt;code&gt;recipes&lt;/code&gt; so we&amp;rsquo;ll create that now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mkdir -p app/views/recipes&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re also going to need the controller so we&amp;rsquo;ll add an empty on at &lt;code&gt;app/controllers/recipes_controller.rb&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;RecipesController&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationController&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lastly, we&amp;rsquo;re going to need to set up our routes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/routes.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;Rails&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;application&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;routes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;draw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;welcome#show&amp;#34;&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;resources&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipes&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we check our &lt;code&gt;rake routes&lt;/code&gt; it should now include the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;           recipes GET    /recipes(.:format)                      recipes#index
                   POST   /recipes(.:format)                      recipes#create
        new_recipe GET    /recipes/new(.:format)                  recipes#new
       edit_recipe GET    /recipes/:id/edit(.:format)             recipes#edit
            recipe GET    /recipes/:id(.:format)                  recipes#show
                   PATCH  /recipes/:id(.:format)                  recipes#update
                   PUT    /recipes/:id(.:format)                  recipes#update
                   DELETE /recipes/:id(.:format)                  recipes#destroy&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;rendering-recipes&#34;&gt;Rendering Recipes&lt;/h2&gt;

&lt;p&gt;Now that we have the backbone of this portion of the app there we can start building on it. The first thing we&amp;rsquo;re going to do is display the existing recipes. We&amp;rsquo;ll do this in the &lt;code&gt;index.html.erb&lt;/code&gt; view.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/recipes/index.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Recipes&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;recipes&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @recipes.each do |recipe| %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;recipe&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to recipe.name, recipe_path(recipe) %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= recipe.description %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;recipe-actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Edit&amp;#34;, edit_recipe_path(recipe) %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Delete&amp;#34;, recipe_path(recipe), data: {
          confirm: &amp;#34;Are you sure you want to delete: #{recipe.name}?&amp;#34;
        }, method: :delete %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to create the &lt;code&gt;@recipes&lt;/code&gt; instance variable in the &lt;code&gt;index&lt;/code&gt; action of the &lt;code&gt;RecipesController&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;RecipesController&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;index&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@recipes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;all&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if you go to &lt;code&gt;localhost:3000/recipes&lt;/code&gt; you should see the following:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/no_recipes.png&#34; alt=&#34;No recipes&#34; width=&#34;725&#34; height=&#34;537&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;creating-fake-recipes&#34;&gt;Creating Fake Recipes&lt;/h2&gt;

&lt;p&gt;When you bring a new person onto an application it&amp;rsquo;s usually good to set them up with some example data. Thankfully, Rails provides us with a means to do this easily through the &lt;code&gt;db/seeds.rb&lt;/code&gt; file and the &lt;code&gt;rake db:seed&lt;/code&gt; rake task. If you run &lt;code&gt;rake db:seeds&lt;/code&gt; in a development environment we&amp;rsquo;ll delete the data that&amp;rsquo;s currently in the system and set up a new User who has 20 Recipes. To make the data &lt;em&gt;slightly&lt;/em&gt; more useful we&amp;rsquo;re going to pull in the &amp;ldquo;faker&amp;rdquo; gem to make our recipes more unique. Let&amp;rsquo;s first grab the gem:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Gemfile&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# other gems&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;group&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:development&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:test&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;byebug&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;platform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:mri&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;minitest-rails&amp;#39;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;factory_girl_rails&amp;#39;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;faker&amp;#39;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# other gems&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We put it into the development and test groups so that we can use Faker in our
recipe factory. Let&amp;rsquo;s change the factory to use that now:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/factories/recipes.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;factory&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Faker&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Hipster&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sentence&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;description&lt;/span&gt;  &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Faker&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Hipster&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;paragraph&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;association&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Putting the Faker portions in a block (the &lt;code&gt;{ ... }&lt;/code&gt;) it means that every time FactoryGirl generates a recipe it will call those methods again. If we didn&amp;rsquo;t do that then every factory would come out have the same name and description. Now we can set up our seeds file&lt;/p&gt;

&lt;p&gt;&lt;em&gt;db/seeds.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;nb&#34;&gt;exit&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Rails&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;env&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;development?&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;puts&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Deleting Records&amp;#34;&lt;/span&gt;
&lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;delete_all&lt;/span&gt;
&lt;span class=&#34;no&#34;&gt;User&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;delete_all&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;puts&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Creating User&amp;#34;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test@example.com&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;puts&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Creating Recipes&amp;#34;&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;times&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we&amp;rsquo;re taking the very destructive action of deleting all Recipes and Users we want to make sure that this file will never accidentally be run in an environment that isn&amp;rsquo;t used for development purposes. It would currently fail to finish in say production because the &amp;ldquo;faker&amp;rdquo; gem would be missing, but it wouldn&amp;rsquo;t hit that failure until after the damage was already done.&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;rake db:seed&lt;/code&gt; now and you&amp;rsquo;ll populate your database with some recipes. If you then refresh &lt;code&gt;localhost:3000/recipes&lt;/code&gt; you should see something like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/recipe_index.png&#34; alt=&#34;Recipes index page&#34; width=&#34;725&#34; height=&#34;537&#34; /&gt;&lt;/p&gt;

&lt;p&gt;While it&amp;rsquo;s not pretty, the data is structured in the way that we expect.&lt;/p&gt;

&lt;h2 id=&#34;viewing-an-individual-recipe&#34;&gt;Viewing an Individual Recipe&lt;/h2&gt;

&lt;p&gt;While it&amp;rsquo;s great to see the entire list of recipes we also need to be able to see and link to a single recipe (by clicking on its name). For this to work we need to build the &amp;ldquo;show&amp;rdquo; action and view. Let&amp;rsquo;s build the action first.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;show&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Pretty simple, we just need to grab the recipe from the database. Onto the view:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/recipes/show.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= @recipe.name %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;Description:&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= @recipe.description %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;p&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;recipe-actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Back&amp;#34;, recipes_path %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Edit&amp;#34;, edit_recipe_path(@recipe) %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#34;Delete&amp;#34;, recipe_path(@recipe), data: {
      confirm: &amp;#34;Are you sure you want to delete: #{@recipe.name}?&amp;#34;
    }, method: :delete %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We duplicated the recipe actions from our index page, but we added an additional item for &amp;ldquo;Back&amp;rdquo; which will take the user back to the list of recipes. We also had to make sure that we were using &lt;code&gt;@recipe&lt;/code&gt; in our embedded ruby instead of &lt;code&gt;recipe&lt;/code&gt; like we did on the index page.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/recipe_show.png&#34; alt=&#34;Recipe show page&#34; width=&#34;725&#34; height=&#34;537&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s wire up the &amp;ldquo;Delete&amp;rdquo; link to remove the recipe.&lt;/p&gt;

&lt;h2 id=&#34;deleting-a-recipe&#34;&gt;Deleting a Recipe&lt;/h2&gt;

&lt;p&gt;Our &amp;ldquo;Delete&amp;rdquo; link is already set up to go to the proper route, but the thing that makes it different is that it&amp;rsquo;s set up to use the &lt;code&gt;method&lt;/code&gt; of &lt;code&gt;delete&lt;/code&gt;. This is referring to the HTTP method, and if you look at the routes again, you&amp;rsquo;ll see that the line including the &amp;ldquo;DELETE&amp;rdquo; shows that it should go to &amp;ldquo;recipes#destroy&amp;rdquo;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;DELETE /recipes/:id(.:format) recipes#destroy
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is the action that we&amp;rsquo;ll need to set up in the controller to make this link work properly. Let&amp;rsquo;s create that now.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;destroy&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destroy&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;redirect_to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recipes_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;notice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Deleted Recipe: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;First we find the recipe. We then call the &lt;code&gt;destroy&lt;/code&gt; method which will trigger any callbacks that may exist and remove the database row. We then redirect back to the index page and include a flash message to say that the recipe was deleted. Notice that we were still able to access the name of the recipe after we &amp;ldquo;destroyed&amp;rdquo; it.&lt;/p&gt;

&lt;h2 id=&#34;creating-a-new-recipe&#34;&gt;Creating a New Recipe&lt;/h2&gt;

&lt;p&gt;The create and update portions of CRUD are remarkably similar. This will allow us to build out the &amp;ldquo;New Recipe&amp;rdquo; workflow and basically get the &amp;ldquo;Edit Recipe&amp;rdquo; workflow for free.&lt;/p&gt;

&lt;p&gt;The first thing that we need to do is set up the &amp;ldquo;new&amp;rdquo; action and view.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;new&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;app/views/recipes/new.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;New Recipe&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= render partial: :form %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re going to separate out the &amp;ldquo;form&amp;rdquo; portion of this view into a &amp;ldquo;partial&amp;rdquo; view so that we can use it in multiple views. Partial views have special names that begin with an underscore, so our &amp;ldquo;form&amp;rdquo; partial will be &amp;ldquo;_form.html.erb&amp;rdquo; Here&amp;rsquo;s what that&amp;rsquo;s going to look like:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/recipes/_form.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% if @errors.present? %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;errors&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% @errors.each do |error| %&amp;gt;
        &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= error %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;li&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ul&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;

&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form_for @recipe do |form| %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.label :name %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.text_field :name %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-group&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.label :description %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.text_area :description %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;actions&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= form.submit %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are quite a few things going on here, but those will make more sense after we finish the &amp;ldquo;create&amp;rdquo; action. If you head to &amp;ldquo;localhost:3000/recipes/new&amp;rdquo; you should see the form now.&lt;/p&gt;

&lt;p&gt;Before we try to use the form let&amp;rsquo;s build out the &amp;ldquo;create&amp;rdquo; action (otherwise the form will fail on submit).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;create&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipe_params&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;redirect_to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recipe_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;notice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Recipe Created!&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@errors&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;full_messages&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:new&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;recipe_params&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;permit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;create&lt;/code&gt; method is where the magic happens, but we&amp;rsquo;re also using a feature of Rails called &amp;ldquo;strong parameters&amp;rdquo; in the &lt;code&gt;recipe_params&lt;/code&gt; method. Strong parameters allow us to specify which parameters are allowed to be submitted and ensures that we&amp;rsquo;re not passing malicious fields from the user to our models (and thus our database connection). This is a great security feature.&lt;/p&gt;

&lt;p&gt;Looking at the action again, if the new recipe with the data from the form successfully saves then we will redirect to the show page for the recipe. If the call to &lt;code&gt;save&lt;/code&gt; fails, then we&amp;rsquo;ll store the errors that occurred in a variable so that we can display these on the form that we render. To see this in action submit the form without filling in any of the values. You should see this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/form_errors.png&#34; alt=&#34;Recipe form errors&#34; width=&#34;725&#34; height=&#34;537&#34; /&gt;&lt;/p&gt;

&lt;p&gt;This is great besides the missing user bit. Up to this point we&amp;rsquo;ve just been working with Recipes without worrying about the user, but that also meant that we were showing and allowing any visitor to edit/delete recipes. Time to add some security.&lt;/p&gt;

&lt;h2 id=&#34;authenticating-the-recipes-controller&#34;&gt;Authenticating the Recipes Controller&lt;/h2&gt;

&lt;p&gt;Thankfully, we won&amp;rsquo;t have to make a ton of changes to get the recipes controller locked down and working with the logged in user&amp;rsquo;s content. The first thing that we need to do is set up a &lt;code&gt;before_action&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;RecipesController&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;before_action&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:require_login&lt;/span&gt;

  &lt;span class=&#34;c1&#34;&gt;# ...&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With just that change, going to the recipes index page will redirect us to the sign in page. That did the entire job of restricting access to the pages, but it didn&amp;rsquo;t ensure that the user is only working with his or her recipes. To do that we&amp;rsquo;re going to remove all of the uses of &lt;code&gt;Recipe&lt;/code&gt; in this controller, instead accessing the recipes through the &lt;code&gt;current_user&lt;/code&gt;. Here&amp;rsquo;s our current controller, modified to work this way:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;RecipesController&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;before_action&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:require_login&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;index&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@recipes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;order&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;show&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;new&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;create&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;build&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipe_params&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;redirect_to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recipe_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;notice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Recipe Created!&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
      &lt;span class=&#34;vi&#34;&gt;@errors&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;full_messages&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:new&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;destroy&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;destroy&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;redirect_to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recipes_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;notice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Deleted Recipe: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

  &lt;span class=&#34;kp&#34;&gt;private&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;recipe_params&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;permit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In a nut-shell, we&amp;rsquo;ve made the following changes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;quot;Recipe.all&amp;quot; became &amp;quot;current_user.recipes&amp;quot;
&amp;quot;Recipe.new&amp;quot; became &amp;quot;current_user.recipes.build&amp;quot;
&amp;quot;Recipe.find&amp;quot; became &amp;quot;current_user.recipes.find&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That won&amp;rsquo;t quite work yet though because the User class doesn&amp;rsquo;t know that it has recipes yet.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/user.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;User&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class=&#34;kp&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Clearance&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;User&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;has_many&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipes&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we go to &amp;ldquo;localhost:3000/recipes/new&amp;rdquo; and submit the form without any data again we should see a slightly different set of errors:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/form_errors_with_user.png&#34; alt=&#34;Form error with user&#34; width=&#34;725&#34; height=&#34;537&#34; /&gt;&lt;/p&gt;

&lt;p&gt;If we fill out the form properly and submit again we will have successfully created a recipe!&lt;/p&gt;

&lt;h2 id=&#34;editing-a-recipe&#34;&gt;Editing a Recipe&lt;/h2&gt;

&lt;p&gt;I mentioned before that creating a new recipe and editing a recipe were very close to being the same thing. We&amp;rsquo;re going to reuse the &amp;ldquo;form&amp;rdquo; partial so our edit view will be the following:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/views/recipes/edit.html.erb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h1&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Edit&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;/h1&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;sr&#34;&gt;&amp;lt;%= render partial: &amp;#34;form&amp;#34; %&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Looks pretty familiar. From here we need to set up the &amp;ldquo;edit&amp;rdquo; and &amp;ldquo;update&amp;rdquo; actions in our controller. Those will also look pretty familiar:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/controllers/recipes_controller.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;edit&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;update&lt;/span&gt;
  &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;current_user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;find&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;params&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

  &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update_attributes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;recipe_params&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;redirect_to&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recipe_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;),&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;notice&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Recipe Updated!&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;
    &lt;span class=&#34;vi&#34;&gt;@errors&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;vi&#34;&gt;@recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;full_messages&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:edit&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The differences here are that instead of using &lt;code&gt;build&lt;/code&gt; we&amp;rsquo;re using &lt;code&gt;find&lt;/code&gt; because the recipes already exist, and instead of &lt;code&gt;save&lt;/code&gt; we use &lt;code&gt;update_attributes&lt;/code&gt;. Besides those small changes these actions have the exact same shape as the &amp;ldquo;new&amp;rdquo; and &amp;ldquo;create&amp;rdquo; actions.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;We covered a lot in this tutorial. Our application can actually do things! Since we have the UI and associated actions wrapped around recipes it could actually work as a functional recipe book for a User. The application is better rigged up
to onboard new team members with our seed and fake data generation. You&amp;rsquo;ve now seen a lot of the features of Rails that thousands of developers use every day to be productive in their jobs.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Rails – Modeling a Recipe and Testing (Part 3)</title>
      <link>https://coderjourney.com/learning-ruby-on-rails-modeling-recipe-and-testing-part-3/</link>
      <pubDate>Tue, 22 Nov 2016 17:30:49 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-ruby-on-rails-modeling-recipe-and-testing-part-3/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to build out the data model for managing recipes. In Rails, models are very important so we&amp;rsquo;re going to do a deep dive on just that portion of the feature. We&amp;rsquo;ll also write automated tests to help us better understand the code that we&amp;rsquo;re writing.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/6fkpKmI3elg&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create a new model&lt;/strong&gt; for Recipe.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Write specs&lt;/strong&gt; to ensure we&amp;rsquo;re modeling our data correctly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understand model validations&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One of the main features of our application is that you can create recipes and eventually be able to generate meal plans from it. Before we can have meal plans we&amp;rsquo;re going to need Recipes. We&amp;rsquo;ll tackle most of how a Recipe will work today.&lt;/p&gt;

&lt;p&gt;Most of what we do today will be in code, but we&amp;rsquo;re going to need to run some things from the command line also, so we&amp;rsquo;re going to keep a bash prompt opened up to our rails container:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;docker-compose &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; app bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;modeling-a-recipe&#34;&gt;Modeling a Recipe&lt;/h2&gt;

&lt;p&gt;Our Recipe model is going to start out &lt;em&gt;very&lt;/em&gt; simple, but we will likely make it more complicated in the future. We&amp;rsquo;re going to have our recipes&amp;rsquo; have a unique name and a description. The first thing that we need to do is create our database table using the migration generator:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rails generate migration create_recipes&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re only creating the file with the timestamp using that generator, we&amp;rsquo;ll write the contents ourselves. Your file name will be slightly different.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;db/migrate/20161119131322_create_recipes.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;CreateRecipes&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Migration&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;change&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;create_table&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipes&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;string&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;text&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;foreign_key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;t&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;timestamps&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;null&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;add_index&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:user_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That will set up the fields that we want and ensure that a single user doesn&amp;rsquo;t create the same recipe over and over again. Don&amp;rsquo;t forget to run this migration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rake db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;introducing-test-driven-development-tdd&#34;&gt;Introducing Test Driven Development (TDD)&lt;/h2&gt;

&lt;p&gt;Since Recipe is going to be one of the main models that we use in our application we want to make sure that we&amp;rsquo;re setting it up properly. In Ruby, writing automated tests is a common practice, as it should be in most settings. Testing is even more important in Ruby since we don&amp;rsquo;t have a compiler to check our work as we go. We&amp;rsquo;re going to test drive our Recipe model so that we know it works the way we expect it to.&lt;/p&gt;

&lt;p&gt;When we generated this application we skipped test, but we&amp;rsquo;re going to set it up now to use minitest.&lt;/p&gt;

&lt;h2 id=&#34;setting-up-minitest-factorygirl&#34;&gt;Setting up Minitest &amp;amp; FactoryGirl&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ll use the &lt;code&gt;minutest-rails&lt;/code&gt; gem and the generators and rake tasks that it provides to get our test suite up and running. This gem needs to be added to the &lt;code&gt;development&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt; groups, because it&amp;rsquo;s not necessary when we put our application into production. We&amp;rsquo;ll also pull in &lt;code&gt;factory_girl_rails&lt;/code&gt; to help us generate data in our tests.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Gemfile&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Other gems&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;group&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:development&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:test&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;byebug&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;platform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:mri&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;minitest-rails&amp;#39;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;factory_girl_rails&amp;#39;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Other gems&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From there we&amp;rsquo;ll, need to rebuild our image and restart our container:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose stop app &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-compose build &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-compose up -d app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From within the container (docker-compose exec back in), we&amp;rsquo;ll run the generate to create our test helper:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rails g minitest:install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;ll modify the test helper to not load fixtures since we won&amp;rsquo;t be using them:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/test_helper.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;ENV&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;RAILS_ENV&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;File&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;expand_path&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;../../config/environment&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;__FILE__&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rails/test_help&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;minitest/rails&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# To add Capybara feature tests add `gem &amp;#34;minitest-rails-capybara&amp;#34;`&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# to the test group in the Gemfile and uncomment the following:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# require &amp;#34;minitest/rails/capybara&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Uncomment for awesome colorful output&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# require &amp;#34;minitest/pride&amp;#34;&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;ActiveSupport&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;TestCase&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;# Add more helper methods to be used by all tests here...&lt;/span&gt;
  &lt;span class=&#34;kp&#34;&gt;include&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Syntax&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Methods&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;ll make some modifications to how generators work so that rails knows to create a minutest-spec file if we generate something that would create a test in the future. Here&amp;rsquo;s the complete config that our application has thus far:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/application.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;require_relative&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;boot&amp;#39;&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;rails&amp;#34;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Pick the frameworks you want:&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;active_model/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;active_job/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;active_record/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;action_controller/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;action_mailer/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;action_view/railtie&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;action_cable/engine&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;sprockets/railtie&amp;#34;&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Require the gems listed in Gemfile, including any gems&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# you&amp;#39;ve limited to :test, :development, or :production.&lt;/span&gt;
&lt;span class=&#34;no&#34;&gt;Bundler&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;require&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Rails&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;groups&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;module&lt;/span&gt; &lt;span class=&#34;nn&#34;&gt;MealPlan&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Application&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Rails&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Application&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# Settings in config/environments/* take precedence over those specified here.&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# Application configuration should go into files in config/initializers&lt;/span&gt;
    &lt;span class=&#34;c1&#34;&gt;# -- all .rb files in that directory are automatically loaded.&lt;/span&gt;

    &lt;span class=&#34;c1&#34;&gt;# Configure Generators&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;config&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;generators&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;g&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;test_framework&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:minitest&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we&amp;rsquo;ll set up our test directory to have some subdirectories.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mkdir -p test/&lt;span class=&#34;o&#34;&gt;{&lt;/span&gt;factories,models&lt;span class=&#34;o&#34;&gt;}&lt;/span&gt;
$ touch test/factories/.gitkeep&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, we will create our first spec to make sure that we set everything up properly. It&amp;rsquo;s important that we name our file properly, with a &amp;ldquo;_test&amp;rdquo; at the end. We&amp;rsquo;re looking to make a test that fails with the error we expect.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/models/recipe_test.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test_helper&amp;#34;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;will fail&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;assert&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;false&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can run this test:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rails test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we should see the following failure:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/test_failure.png&#34; alt=&#34;Test failure&#34; width=&#34;791&#34; height=&#34;425&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;test-driving-our-recipe-model&#34;&gt;Test Driving our Recipe Model&lt;/h2&gt;

&lt;p&gt;Now that we have our testing environment it&amp;rsquo;s time to actually do the testing. The idea with Test Driven Development is that we&amp;rsquo;ll write our tests first, showing how we want our finished code to behave. Running the test it will fail, and we will incrementally make the test pass by reading the errors that are given and making those errors go away. When you&amp;rsquo;re first starting out with a language I think TDD is great for helping you get to know the error messages.&lt;/p&gt;

&lt;p&gt;Our tests will revolve around making sure that our recipe validations work properly. We&amp;rsquo;ll write all of the specs up front, but when we&amp;rsquo;ll only worry about fixing them one at a time.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/models/recipe_test.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;test_helper&amp;#34;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;describe&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;validity&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;let&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;Recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;new&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;before&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;valid?&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires a user&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires a description&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires a name&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;can&amp;#39;t be blank&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;requires the name be unique for the same user&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;existing_recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;existing_recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;existing_recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;valid?&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;must_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;has already been taken&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

    &lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;does not require the name be unique with different users&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;existing_recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;create&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;existing_recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;name&lt;/span&gt;
      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;valid?&lt;/span&gt;

      &lt;span class=&#34;n&#34;&gt;recipe&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;wont_include&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;has already been taken&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before we can run these tests we&amp;rsquo;ll need to create our factories. We&amp;rsquo;ll use the &lt;code&gt;factory_girl:model&lt;/code&gt; generator to create the files and then fill out the values that we need.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rails g factory_girl:model User
$ rails g factory_girl:model Recipe&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let&amp;rsquo;s fill in the information that would work to create a valid User:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/factories/users.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;factory&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;sequence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:email&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;example_user_&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;n&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;@example.com&amp;#34;&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;password&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;password&amp;#34;&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We didn&amp;rsquo;t create any validations on our User, but the module that we included from Clearance did. One of those validations is that the email must be unique. Because of this we use a sequence to make sure that every time we use FactoryGirl to create a User it will have a different email address.&lt;/p&gt;

&lt;p&gt;Next we will need to create our &lt;code&gt;recipe&lt;/code&gt; factory.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;test/factories/recipes.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;FactoryGirl&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;define&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;factory&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:recipe&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
    &lt;span class=&#34;nb&#34;&gt;name&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Mom&amp;#39;s Spaghetti&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;description&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;The best pasta in the world.&amp;#34;&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;association&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The only thing that&amp;rsquo;s really notable here is that we use the &lt;code&gt;association(:user)&lt;/code&gt; method to make sure that every recipe we create has an associated &lt;code&gt;User&lt;/code&gt; object. We can specify a different user when we use the factory, but by default it will create a new one.&lt;/p&gt;

&lt;p&gt;Now we should be able to run our tests:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/all_tests_fail.png&#34; alt=&#34;All tests failing&#34; width=&#34;769&#34; height=&#34;858&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;getting-the-tests-to-pass&#34;&gt;Getting the Tests to Pass&lt;/h2&gt;

&lt;p&gt;A few of our tests fail because of an undefined method &lt;code&gt;user=&lt;/code&gt;, since this is failing before we even hit the assertion we should fix that first. The reason for this failure is because the Recipe model doesn&amp;rsquo;t actually know that is associated to a &lt;code&gt;User&lt;/code&gt; yet. It&amp;rsquo;ll only take one line to fix this error.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/recipe.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we rerun the tests now we won&amp;rsquo;t see the undefined method error any more. Next, we&amp;rsquo;re going to fix the errors from the missing &amp;ldquo;can&amp;rsquo;t be blank&amp;rdquo; errors. These message come from the &amp;ldquo;presence&amp;rdquo; validation that we haven&amp;rsquo;t set up yet.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/recipe.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Rerunning the tests now will show that we only have one test failing. We&amp;rsquo;re missing a &amp;ldquo;uniqueness&amp;rdquo; validation on the name attribute. Let&amp;rsquo;s add that now and see what happens:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/recipe.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;uniqueness&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we&amp;rsquo;re getting a different failure. The validation that we currently have for uniqueness ensures that there will only ever be one recipe in the database with a specific name, but that&amp;rsquo;s not exactly what we want. We want to make sure that &lt;em&gt;each User&lt;/em&gt; can only have one recipe of a specific name, but multiple users can have recipes that share a common name. We can accomplish this by tweaking our uniqueness validation a little to use a scope.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;app/models/recipe.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;Recipe&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationRecord&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;belongs_to&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;

  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;uniqueness&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;scope&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user_id&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:description&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;validates&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;presence&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;kp&#34;&gt;true&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Rerunning the tests show that they&amp;rsquo;re all passing! Using a hash instead of a true value allowed us to be a little more specific and say that the uniqueness only matters if the recipe rows have the same &amp;ldquo;user_id&amp;rdquo; value.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;This was a feature packed portion even though we didn&amp;rsquo;t completely finish a feature. Models and validations are really important when working with Rails so it&amp;rsquo;s really good to build a good understanding of them. We also went through a whirlwind tour of testing. Automated testing is one of my favorite tools to use in programming, both for learning and also for ensuring that I don&amp;rsquo;t write bugs as I continue development on a project. Since the project is set up for testing now it will be a lot easier for us to use them moving forward.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Ruby on Rails – User Sign Up and Authentication (Part 2)</title>
      <link>https://coderjourney.com/learning-ruby-on-rails-user-sign-up-and-auth-part-2/</link>
      <pubDate>Thu, 17 Nov 2016 23:30:16 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-ruby-on-rails-user-sign-up-and-auth-part-2/</guid>
      <description>

&lt;p&gt;Today we continue our series learning Ruby on Rails. Having set up the project in the first episode, we can now start developing our first feature: User sign up, log in, and log out.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/KADfCLGQWmI&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;p&gt;** &lt;em&gt;Set up Authentication&lt;/em&gt; in a Rails App.
** &lt;em&gt;Weigh Gem Pros/Cons&lt;/em&gt; to pick dependencies.
** &lt;em&gt;Create simple Controller, View, and Route&lt;/em&gt; for the home page.&lt;/p&gt;

&lt;p&gt;User sign up and authentication is pretty much a solved problem. So many applications have user sign in. Because of this, we&amp;rsquo;re not going to build this feature from scratch. We&amp;rsquo;re going to pull in a library to handle this part of the application for us.&lt;/p&gt;

&lt;p&gt;Before we can get started we&amp;rsquo;re going to need to pick a library, and we&amp;rsquo;ll be picking one from these three:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/thoughtbot/clearance&#34;&gt;Clearance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/plataformatec/devise&#34;&gt;Devise&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/Sorcery/sorcery&#34;&gt;Sorcery&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The features that we really want are: user authentication over email/password, and password reset.&lt;/p&gt;

&lt;h2 id=&#34;deciding-on-a-gem&#34;&gt;Deciding on a Gem&lt;/h2&gt;

&lt;p&gt;All three of the gems we reviewed are great. Devise is without a doubt the most popular gem for authentication and is well battle tested. Sorcery is the least intrusive solution, providing us with methods that we manually set up and not having an opinion on routes/views. Clearance is simple and maintained by a very reputable company in the Ruby/Rails community.&lt;/p&gt;

&lt;p&gt;Clearance is what we&amp;rsquo;re going to go with for this project. It meets our requirements, and doesn&amp;rsquo;t try to do much more.&lt;/p&gt;

&lt;h2 id=&#34;installing-the-gem&#34;&gt;Installing the Gem&lt;/h2&gt;

&lt;p&gt;Clearance has good documentation, and we need to follow the installation portion right now. The firs thing that we need to do is add the gem to our &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# ... Other gems&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;clearance&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;~&amp;gt; 1.15.1&amp;#39;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# ... Other gems&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Take note of the &lt;code&gt;~&amp;gt;&lt;/code&gt; sign in the version number. That does &amp;ldquo;pessimistic&amp;rdquo; version pinning, which means that it will allow installation of iterations in the right most version position. In our case this means we could install 1.15.1 now, but if 1.15.2 came out tomorrow we could &lt;code&gt;bundle update&lt;/code&gt; to that without changing our &lt;code&gt;Gemfile&lt;/code&gt;. We would not be able to update to &lt;code&gt;1.16.0&lt;/code&gt; without changing this line though. We would write the current line as &lt;code&gt;~&amp;gt; 1.15&lt;/code&gt; if we wanted to be able to install any minor version above 15.&lt;/p&gt;

&lt;p&gt;Since we&amp;rsquo;ve added a new gem we need to bundle install that. We&amp;rsquo;re going to stop our containers, rebuild, and start them back up. Building does the &lt;code&gt;bundle install&lt;/code&gt; step that we need, but it also bakes the gems into the image.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose build &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker-compose run --rm app bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Once the application container is rebuilt we&amp;rsquo;re going to do a few more things before restarting it.&lt;/p&gt;

&lt;h2 id=&#34;setting-up-clearance&#34;&gt;Setting Up Clearance&lt;/h2&gt;

&lt;p&gt;Clearance comes packaged with some commands to help us get up and running quickly. The first one we&amp;rsquo;re going to use is &lt;code&gt;clearance:install&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rails generate clearance:install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That command will create or change the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create the &lt;code&gt;User&lt;/code&gt; model or change it if you already had one&lt;/li&gt;
&lt;li&gt;Generate a migration to set up the fields on &lt;code&gt;User&lt;/code&gt; that clearance needs&lt;/li&gt;
&lt;li&gt;Change the &lt;code&gt;ApplicationController&lt;/code&gt; to include the clearance methods (through a module)&lt;/li&gt;
&lt;li&gt;Create an initializer to allow us to configure clearance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The output from the installation also gives us a few more changes we can make and tells us to migrate our database. We&amp;rsquo;ll do those things also, doing the migration first.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rake db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here is the change we&amp;rsquo;ll make to our &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;cp&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;MealPlan&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;title&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= csrf_meta_tags %&amp;gt;

    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= stylesheet_link_tag    &amp;#39;application&amp;#39;, media: &amp;#39;all&amp;#39; %&amp;gt;
    &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= javascript_include_tag &amp;#39;application&amp;#39; %&amp;gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;head&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% if signed_in? %&amp;gt;
        Signed in as: &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= current_user.email %&amp;gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= button_to &amp;#39;Sign out&amp;#39;, sign_out_path, method: :delete %&amp;gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% else %&amp;gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= link_to &amp;#39;Sign in&amp;#39;, sign_in_path %&amp;gt;
      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;header&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

    &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

      &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;flash&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% flash.each do |key, value| %&amp;gt;
          &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;class&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;flash &amp;lt;%= key %&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= value %&amp;gt;&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;% end %&amp;gt;
      &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;div&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;

      &lt;span class=&#34;err&#34;&gt;&amp;lt;&lt;/span&gt;%= yield %&amp;gt;
    &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;section&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;body&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;html&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have the clearance initializer we can start the application.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;docker-compose up -d&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;signing-up-and-creating-a-home-page&#34;&gt;Signing Up (and Creating a Home Page)&lt;/h2&gt;

&lt;p&gt;Clearance by default provides us with routes and views through a rails engine. This means that we don&amp;rsquo;t need to set up much of any code in our application to get up and running. It&amp;rsquo;s suggested that you not use this feature so that you have more control, so we will actually create routes/views, but for the time being we&amp;rsquo;re going to take this for a spin.&lt;/p&gt;

&lt;p&gt;You can head to &lt;code&gt;localhost:3000/sign_up&lt;/code&gt; to actually create a User for yourself. The form isn&amp;rsquo;t pretty, but that&amp;rsquo;s ok since it&amp;rsquo;s our responsibility to style our site.&lt;/p&gt;

&lt;p&gt;After you sign up you&amp;rsquo;ll be redirect back to the &amp;ldquo;Yay! You&amp;rsquo;re on Rails&amp;rdquo; page, which doesn&amp;rsquo;t actually show us the change we made to our application layout. To get around this we&amp;rsquo;re going to create our home page.&lt;/p&gt;

&lt;p&gt;First we need to create our controller, we&amp;rsquo;ll call it the &lt;code&gt;WelcomeController&lt;/code&gt; and put it at &lt;code&gt;app/controllers/welcome_controller.rb&lt;/code&gt;. In Rails the naming of classes and files is very important so make sure that these match up.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;k&#34;&gt;class&lt;/span&gt; &lt;span class=&#34;nc&#34;&gt;WelcomeController&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;no&#34;&gt;ApplicationController&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;show&lt;/span&gt;
  &lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s all we need in the controller because there won&amp;rsquo;t be any dynamic data passed to the view we&amp;rsquo;re going to display (our &lt;code&gt;show&lt;/code&gt; view). Next, we&amp;rsquo;ll create the directory in views, and the view itself.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mkdir -p app/views/welcome
$ &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;h1&amp;gt;Welcome&amp;lt;/h1&amp;gt;&amp;#34;&lt;/span&gt; &amp;gt; app/views/welcome/show.html.erb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lastly, we need to set up our &lt;code&gt;root&lt;/code&gt; route in &lt;code&gt;config/routes.rb&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;no&#34;&gt;Rails&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;application&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;routes&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;draw&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;c1&#34;&gt;# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;root&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;to&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;welcome#show&amp;#34;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we look at &lt;code&gt;localhost:3000&lt;/code&gt; again we can see that we&amp;rsquo;re logged in:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/welcome-show-view.png&#34; alt=&#34;Welcome show view&#34; width=&#34;916&#34; height=&#34;230&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Later on, we will customize the views and routes that clearance has given us, but for the time being we&amp;rsquo;ve successfully implemented the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User Sign Up&lt;/li&gt;
&lt;li&gt;User Sign In/Out&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Moving forward we will implement features that are specific to our domain so we won&amp;rsquo;t be able to use a gem to do all of the work.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learning Ruby on Rails – Project Setup &amp; Planning (Part 1)</title>
      <link>https://coderjourney.com/learning-rails-project-setup-and-planning/</link>
      <pubDate>Tue, 08 Nov 2016 23:27:24 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-rails-project-setup-and-planning/</guid>
      <description>

&lt;p&gt;Today we kick off our series to learn Ruby on Rails. In this tutorial, we&amp;rsquo;re going to be laying out our project structure, preview the features that we&amp;rsquo;re going to build, and do some project planning. We&amp;rsquo;re not going to write a ton of code today, but we will look into some of the very important non-coding work that goes into building a web application.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/JdBWb7jWALg&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explore Project Goals&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Create basic Rails app&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use Git and Github&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Plan Project features&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application that we&amp;rsquo;re going to be building over the course of this tutorial series is an application for planning meals based on recipes that a user stores. I originally built some of this application for a conference talk I gave in April 2016, but I built it using Elixir and Elm. We&amp;rsquo;ll be rebuilding this application from scratch using Ruby and Rails 5, but we can take a look at the original application for a general idea of some early features to build.&lt;/p&gt;

&lt;p&gt;This entire tutorial series is going to be developed using Docker to run our development environment. I released a two part tutorial about using Docker while developing a Rails app, so check those out before we get started:&lt;/p&gt;

&lt;p&gt;&lt;a href=&#34;https://coderjourney.com/docker-for-development/&#34;&gt;Docker in Development&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&#34;exploring-the-existing-project&#34;&gt;Exploring the Existing Project&lt;/h2&gt;

&lt;p&gt;Before we start anything related to code, let&amp;rsquo;s go over the problem that we&amp;rsquo;re trying to solve.&lt;/p&gt;

&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;My wife and I use a weekly meal plan to help us determine what we should buy when we go grocery shopping, but it&amp;rsquo;s annoying to come up with the actual meal plan each week. We have a list of recipes that we rotate through, but it&amp;rsquo;s a little too big to think about each week so we often repeat the same meal multiple times before remembering one of the other ones that we like. It would be great if there was an easy way for us to generate our meal plan so that it wasn&amp;rsquo;t so taxing on us &lt;em&gt;and&lt;/em&gt; we could more evenly rotate through our meals.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;

&lt;p&gt;The application we&amp;rsquo;ll build to solve this problem could be incredibly complex, but we&amp;rsquo;re going to try to build this piece by piece so that it&amp;rsquo;s useful all while we&amp;rsquo;re building it. Additionally, we&amp;rsquo;re going to build this to work for more than just my wife and me, so we&amp;rsquo;ll need to have the concept of a User, authentication, and authorization.&lt;/p&gt;

&lt;p&gt;In the Elixir version that I built for my talk, I only built the user sign up, authentication flow, and basic recipe creation, editing, and deletion.&lt;/p&gt;

&lt;p&gt;If you use your imagination you can probably think about how we could extend this system to eventually generate a grocery list based on ingredients or balance a weekly menu based on meat selection.&lt;/p&gt;

&lt;h2 id=&#34;generating-our-app-skeleton&#34;&gt;Generating our App Skeleton&lt;/h2&gt;

&lt;p&gt;The first thing that we&amp;rsquo;re going to do is generate our rails application, using a container to do so like we have in the past:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker run --rm -v &lt;span class=&#34;nv&#34;&gt;$PWD&lt;/span&gt;:/usr/src -w /usr/src ruby:2.3 bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From inside the container, we&amp;rsquo;ll install rails and generate our application with some predefined configuration:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ gem install rails
$ rails new meal_plan --skip-turbolinks --skip-spring -d postgresql --skip-bundle --skip-test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have our rails application so we can exit the container. Before we call our application finished though we&amp;rsquo;ll create our &lt;code&gt;Dockerfile&lt;/code&gt;, &lt;code&gt;docker-compose.yml&lt;/code&gt;, &lt;code&gt;.dockerignore&lt;/code&gt; and &lt;code&gt;.env&lt;/code&gt; files:&lt;/p&gt;

&lt;p&gt;Dockerfile:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FROM ruby:2.3.1

RUN apt-get update -yqq \
  &amp;amp;&amp;amp; apt-get install -yqq --no-install-recommends \
    postgresql-client \
    nodejs \
  &amp;amp;&amp;amp; apt-get -q clean \
  &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists

# Pre-install gems with native extensions
RUN gem install nokogiri -v &amp;quot;1.6.8.1&amp;quot;

WORKDIR /usr/src/app
COPY Gemfile* ./
RUN bundle install
COPY . .

CMD rails server -b 0.0.0.0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;docker-compose.yml&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;services&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/var/lib/postgresql/db-data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;build&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/usr/src/app&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;depends_on&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;.dockerignore:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;.git
.gitignore
README.md

Dockerfile
docker-compose.yml
.dockerignore

log/*
tmp/*
.rake_tasks*&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;.env:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;nv&#34;&gt;POSTGRES_USER&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;coderjourney
&lt;span class=&#34;nv&#34;&gt;POSTGRES_PASSWORD&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;abcd1234&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;re going to strip down the &lt;code&gt;Gemfile&lt;/code&gt; a bit and add &lt;code&gt;nokogiri&lt;/code&gt; so we can pin it to &lt;code&gt;1.6.8.1&lt;/code&gt;. That will speed up our image building time any time after the initial build.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;n&#34;&gt;source&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;https://rubygems.org&amp;#39;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;rails&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;~&amp;gt; 5.0.0&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;= 5.0.0.1&amp;#39;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;pg&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;~&amp;gt; 0.18&amp;#39;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;puma&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;~&amp;gt; 3.0&amp;#39;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;sass-rails&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;~&amp;gt; 5.0&amp;#39;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;uglifier&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;&amp;gt;= 1.3.0&amp;#39;&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;jquery-rails&amp;#39;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;nokogiri&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;1.6.8.1&amp;#39;&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;group&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:development&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:test&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;byebug&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;platform&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:mri&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

&lt;span class=&#34;n&#34;&gt;group&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:development&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;do&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;web-console&amp;#39;&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;listen&amp;#39;&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;end&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# Windows does not include zoneinfo files, so bundle the tzinfo-data gem&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;gem&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;tzinfo-data&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;platforms&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;ss&#34;&gt;:mingw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:mswin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:x64_mingw&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:jruby&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lastly, we need to adjust our &lt;code&gt;config/database.yml&lt;/code&gt; file to work with containers:&lt;/p&gt;

&lt;p&gt;database.yml:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;default&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&amp;amp;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;adapter&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgresql&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;encoding&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;unicode&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;host&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;username&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&amp;lt;%=&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ENV&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;POSTGRES_USER&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;%&lt;span class=&#34;sd&#34;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  password: &amp;lt;%= ENV[&amp;#34;POSTGRES_PASSWORD&amp;#34;] %&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  pool: &amp;lt;%= ENV.fetch(&amp;#34;RAILS_MAX_THREADS&amp;#34;) { 5 } %&amp;gt;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;development&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&amp;lt;&amp;lt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;*default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;database&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;meal_plan_development&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;test&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&amp;lt;&amp;lt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;*default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;database&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;meal_plan_test&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;production&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&amp;lt;&amp;lt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;*default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;host&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&amp;lt;%=&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ENV&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;POSTGRES_HOST&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;%&lt;span class=&#34;sd&#34;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  database: meal_plan_production&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now that we have all of the pre-requisite files that we want, we can build our image and generate our database:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose run --rm app rake db:create db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Finally, let&amp;rsquo;s make sure our rails app is running. Start the containers, daemonized, and navigate to &lt;a href=&#34;http://localhost:3000&#34;&gt;http://localhost:3000&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose up -d&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;saving-our-work&#34;&gt;Saving our Work&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;re going to treat this project like we would a client project. Looking at it through that lens, one of the first things I would do would be to get this into source control and set up the repository on a git server somewhere. We&amp;rsquo;ll initialize the repo and create our first commit:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ git init
$ git add . &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit -m &lt;span class=&#34;s1&#34;&gt;&amp;#39;Initial creation of dockerized rails application&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Github is going to act as our git server, so we need to create a repo there. If you&amp;rsquo;re unfamiliar with git and github then I suggest following Github&amp;rsquo;s &lt;a href=&#34;https://guides.github.com/activities/hello-world/&#34;&gt;awesome tutorials&lt;/a&gt;. I&amp;rsquo;m going to house my version of this application &lt;a href=&#34;https://github.com/coderjourney/meal_plan&#34;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now we can push up our existing code:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ git remote add origin git@github.com:coderjourney/meal_plan.git
$ git push -u origin master&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;planning-out-features&#34;&gt;Planning Out Features&lt;/h2&gt;

&lt;p&gt;For managing our project we&amp;rsquo;re going to use the &amp;ldquo;Projects&amp;rdquo; tab in Github. Our project is going to have 4 columns to track the status of our features: &amp;ldquo;Backlog&amp;rdquo;, &amp;ldquo;In Progress&amp;rdquo;, &amp;ldquo;Completed&amp;rdquo;, &amp;ldquo;Deployed&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/project_structure.png&#34; alt=&#34;Project structure&#34; width=&#34;1440&#34; height=&#34;872&#34; /&gt;&lt;/p&gt;

&lt;p&gt;When we start implementing a feature or fixing a bug we will move a card from &amp;ldquo;Backlog&amp;rdquo; into &amp;ldquo;In Progress&amp;rdquo;. When the feature is completed we will open a pull request in Github to merge the feature brach into master. After our branch is merged we will move our card from &amp;ldquo;In Progress&amp;rdquo; to &amp;ldquo;Completed&amp;rdquo;. Each time we deploy our &amp;ldquo;master&amp;rdquo; branch to a server we will move the card collected in &amp;ldquo;Completed&amp;rdquo; into the &amp;ldquo;Deployed&amp;rdquo; column.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll start off by creating cards for the features that we want to build and try to order them in a way that makes sense. Here are the features that I&amp;rsquo;m imagining we start with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User Sign Up&lt;/li&gt;
&lt;li&gt;User Login/Logout&lt;/li&gt;
&lt;li&gt;Allow User to View/Create/Edit/Delete Recipes&lt;/li&gt;
&lt;li&gt;Allow User to generate Meal Plan from Recipes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&#34;https://coderjourney.com/img/recipes/project_with_tasks.png&#34; alt=&#34;Project with tasks&#34; width=&#34;1440&#34; height=&#34;872&#34; /&gt;&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ve laid out the plan for building our rails application, and generated our initial project structure. In addition to the things we&amp;rsquo;ve done before, we used git for source code version control and github for project planning. In the next tutorial we will take our first card from the backlog and start building the user registration process.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Command Line Intro – Part 2</title>
      <link>https://coderjourney.com/command-line-intro-part-2/</link>
      <pubDate>Tue, 01 Nov 2016 17:02:51 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/command-line-intro-part-2/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to dig a little deeper into using the command line, focusing on some of the most useful commands that you&amp;rsquo;ll likely use in day-to-day development. We&amp;rsquo;ll specifically look at working with files and searching.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/ZzGDWXKjptc&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create, move, and remove&lt;/strong&gt; files and directories.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understand file permissions&lt;/strong&gt; on a Unix system.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learn to install new tools&lt;/strong&gt; on Ubuntu/Debian Linux.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learn how to search&lt;/strong&gt; within file and by file name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We learned in how to move around with in a terminal in &lt;a href=&#34;https://coderjourney.com/command-line-intro-part-1/&#34;&gt;the previous tutorial&lt;/a&gt;, and today we&amp;rsquo;re going to focus on manipulating files.&lt;/p&gt;

&lt;p&gt;Files are the core of the computer from the user&amp;rsquo;s view. We put our source code in files, our executables are files, and images and other data formats are all files. Because of this, being confident when working with files is very important to how we operate as programmers.&lt;/p&gt;

&lt;p&gt;There are some differences between how some commands work between macOS and linux, so for this tutorial I&amp;rsquo;m going to work from within a Linux container. If you have Docker installed and have a docker server that you can connect to, run this command to follow along:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker run --rm -it  -w /usr/src ubuntu:16.04 bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;creating-files-and-understanding-permissions&#34;&gt;Creating Files and Understanding Permissions&lt;/h2&gt;

&lt;p&gt;To learn how file&amp;rsquo;s work we&amp;rsquo;re going to cover how to create, copy, move, and delete them. Let&amp;rsquo;s start with creating files.&lt;/p&gt;

&lt;p&gt;Creating files on a unix system can happen in a few different ways. You can create a file by writing it from your text editor, if the file doesn&amp;rsquo;t exist it will be created when you save your changes. The other way that we create files is by using the &lt;code&gt;touch&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ touch example.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we use &lt;code&gt;ls -al&lt;/code&gt; we should see the new file:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ ls -al
total &lt;span class=&#34;m&#34;&gt;8&lt;/span&gt;
drwxr-xr-x  &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;4096&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;29&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;:36 .
drwxr-xr-x &lt;span class=&#34;m&#34;&gt;12&lt;/span&gt; root root &lt;span class=&#34;m&#34;&gt;4096&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;29&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;:36 ..
-rw-r--r--  &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; root root    &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;29&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;16&lt;/span&gt;:36 example.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s break down that first section of our line for &lt;code&gt;example.txt&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;-rw-r--r--&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The first dash represents whether or not the item is a file or directory. If &lt;code&gt;example.txt&lt;/code&gt; were a directory we would see a &lt;code&gt;d&lt;/code&gt; there like we do for the &lt;code&gt;..&lt;/code&gt; line.&lt;/p&gt;

&lt;p&gt;Positions 2-4 represent the permissions for the owner of the file. Positions 5-7 represent the permission for the file&amp;rsquo;s group members. Lastly, positions 7-9 represent the permissions for anyone on the system. All of these sections work the same way, but they represent access for a different level of user.&lt;/p&gt;

&lt;p&gt;The three positions in each of the groupings represent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;r&lt;/strong&gt;ead&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;w&lt;/strong&gt;rite&lt;/li&gt;
&lt;li&gt;e&lt;strong&gt;x&lt;/strong&gt;ecute&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Knowing that we can see that the &lt;code&gt;root&lt;/code&gt; user (that&amp;rsquo;s us in this container) can read and write the file, anyone in the &lt;code&gt;root&lt;/code&gt; group can read the file, and anyone on the system can read the file.&lt;/p&gt;

&lt;p&gt;There are tools specifically for changing file permissions and ownership. I&amp;rsquo;m going to list them out with a brief description, but I encourage you to look them up using &lt;code&gt;man&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;chmod&lt;/code&gt; - Change the file&amp;rsquo;s permissions.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chown&lt;/code&gt; - Change the file&amp;rsquo;s owner.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;chgrp&lt;/code&gt; - Change the file&amp;rsquo;s group.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;moving-copying-and-removing-files&#34;&gt;Moving, Copying, and Removing Files&lt;/h2&gt;

&lt;p&gt;Using our &lt;code&gt;example.txt&lt;/code&gt; file, we can go over the rest of the common actions that you&amp;rsquo;ll perform on files, but before we do that we&amp;rsquo;re going to create a new directory to move it to.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;mkdir&lt;/code&gt; is the tool that you&amp;rsquo;ll use to make directories.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mkdir -p test/examples&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That command actually creates two directories for us. If the &lt;code&gt;test&lt;/code&gt; directory doesn&amp;rsquo;t exist it will create it, and then it will also create an &lt;code&gt;examples&lt;/code&gt; directory underneath of &lt;code&gt;test&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now we can move our file to one of these different directories. When moving a file sometimes what we actually want to do is create a copy of the file in a different spot. Let&amp;rsquo;s do that now using &lt;code&gt;cp&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ cp example.txt test/examples
$ ls test/examples
example.txt
$ ls
example.txt test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can see that we now have an &lt;code&gt;example.txt&lt;/code&gt; in the &lt;code&gt;test/examples&lt;/code&gt; directory, but what would it look like if we wanted to move a file completely? For that we&amp;rsquo;ll use the &lt;code&gt;mv&lt;/code&gt; utility.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ mv test/examples/example.txt test/sample.txt
$ ls &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
examples sample.txt
$ ls test/examples
$&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That completely moved the file from &lt;code&gt;test/examples/example.txt&lt;/code&gt; to be at &lt;code&gt;test/sample.txt&lt;/code&gt;. In the process we also renamed the file. The &lt;code&gt;mv&lt;/code&gt; tool is also the tool that you would use if you want to rename a file in the same directory.&lt;/p&gt;

&lt;p&gt;We no longer need the &lt;code&gt;test&lt;/code&gt; directory or files in it so let&amp;rsquo;s look at how we would get rid of those using &lt;code&gt;rm&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rm test/sample.txt
$ ls &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
examples
$ rm &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
rm: cannot remove &lt;span class=&#34;s1&#34;&gt;&amp;#39;test&amp;#39;&lt;/span&gt;: Is a directory&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;rm&lt;/code&gt; is used for removing files by default. It is also the tool that we&amp;rsquo;ll use to remove directories, but we&amp;rsquo;ll have to provide it with a specific flag, &lt;code&gt;-r&lt;/code&gt; (for recursive).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rm -r &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
$ ls
example.txt&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The recursive flag means that it will also remove the contents of the directory. We no longer have either &lt;code&gt;test&lt;/code&gt; or &lt;code&gt;test/examples&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;searching-and-finding-files&#34;&gt;Searching and Finding Files&lt;/h2&gt;

&lt;p&gt;Knowing how to manipulate files will allow you to perform the file maintenance that you&amp;rsquo;ll need to do from day-to-day, but one of the more useful things that you&amp;rsquo;ll need to be able to do is search for files by name and by content. We&amp;rsquo;ll use the tools &lt;code&gt;find&lt;/code&gt; and &lt;code&gt;grep&lt;/code&gt; respectively to accomplish these goals.&lt;/p&gt;

&lt;p&gt;Before we can search through files we&amp;rsquo;re going to need to have something of substance to search through. For that we&amp;rsquo;re going to pull down the rails application that we worked with before &lt;a href=&#34;https://github.com/DefactoSoftware/Hours&#34;&gt;Hours&lt;/a&gt;, but we can&amp;rsquo;t easily get that into our container without installing some additional tools.&lt;/p&gt;

&lt;h3 id=&#34;installing-packages-on-ubuntu-debian&#34;&gt;Installing Packages on Ubuntu/Debian&lt;/h3&gt;

&lt;p&gt;We&amp;rsquo;re going to use the built-in package manager for Ubuntu and Debian to install &lt;code&gt;wget&lt;/code&gt; so that we can download the zip archive of the Hours project.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ apt-get update -yqq &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get install -yqq wget&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This line actually does quite a bit. We&amp;rsquo;re first updating the list of known packages on our system so that it knows what we can download and install. From there we use &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt; to chain on another command, this time we&amp;rsquo;re installing the &lt;code&gt;wget&lt;/code&gt; command. In both of these commands we&amp;rsquo;re passing the &lt;code&gt;-yqq&lt;/code&gt; flag to suppress some of the output that these commands give (making them more &amp;ldquo;quiet&amp;rdquo;) and we&amp;rsquo;re also saying &amp;ldquo;yes we want to perform this action&amp;rdquo;. Without the &lt;code&gt;-y&lt;/code&gt; we would need to type &lt;code&gt;y&lt;/code&gt; again to allow the command to complete.&lt;/p&gt;

&lt;h3 id=&#34;downloading-and-unzipping-hours&#34;&gt;Downloading and Unzipping Hours&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;wget&lt;/code&gt; installed we can grab the zip link from github to download the repo.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ wget https://github.com/DefactoSoftware/Hours/archive/development.zip&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have a &lt;code&gt;development.zip&lt;/code&gt; directory that we can unzip using the pre-installed &lt;code&gt;unzip&lt;/code&gt; command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ unzip development.zip -d Hours&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That will give us a sufficiently big project to search through.&lt;/p&gt;

&lt;h2 id=&#34;finding-files-by-name&#34;&gt;Finding Files by Name&lt;/h2&gt;

&lt;p&gt;If you are working with a codebase that you&amp;rsquo;re not very familiar with it can be helpful to search for files that contain specific words as a way of exploring. We&amp;rsquo;ll do this now by looking for file names that contain the word &amp;ldquo;secret&amp;rdquo;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ find . -name &lt;span class=&#34;s2&#34;&gt;&amp;#34;*secret*&amp;#34;&lt;/span&gt;
./Hours-development/config/initializers/secret_token.rb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;.&lt;/code&gt; after &lt;code&gt;find&lt;/code&gt; indicates that we want to look at all files under our current directory. By passing the &lt;code&gt;-name&lt;/code&gt; flag we&amp;rsquo;re stating that we want to search by name. The token &lt;code&gt;&amp;quot;*secret*&amp;quot;&lt;/code&gt; means we want to look for any file name including &lt;code&gt;secret&lt;/code&gt; and we don&amp;rsquo;t care what characters come before or after it. The &lt;code&gt;*&lt;/code&gt; wildcard character is very helpful when using find, otherwise we would be looking for a file that&amp;rsquo;s entire name was &amp;ldquo;secret&amp;rdquo;.&lt;/p&gt;

&lt;h2 id=&#34;searching-file-contents&#34;&gt;Searching File Contents&lt;/h2&gt;

&lt;p&gt;Admittedly, you&amp;rsquo;ll search for files by name every now and then, but you&amp;rsquo;ll search the contents of files all the time if you&amp;rsquo;re anything like me.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s amazing how often I need to see where a specific class or method is used in a code base. For that we use tools like &lt;code&gt;grep&lt;/code&gt;. Let&amp;rsquo;s see where in the codebase the &lt;code&gt;Tag&lt;/code&gt; model is used.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ grep -Rn &lt;span class=&#34;s2&#34;&gt;&amp;#34;Tag&amp;#34;&lt;/span&gt; .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;There are quite a few things that match &lt;code&gt;Tag&lt;/code&gt; there so I won&amp;rsquo;t put all of the contents here, but some of the matches are for things unrelated to our model. For this we&amp;rsquo;ll make our search a little more specific.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ grep -Rn &lt;span class=&#34;s2&#34;&gt;&amp;#34;Tag\.&amp;#34;&lt;/span&gt; .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This search looks for anytime we use &lt;code&gt;Tag&lt;/code&gt; explicitly followed by a &lt;code&gt;.&lt;/code&gt;. If we didn&amp;rsquo;t escape the period with a \ then wouldn&amp;rsquo;t work the way we expect because &lt;code&gt;.&lt;/code&gt; is a wildcard character when searching with grep.&lt;/p&gt;

&lt;p&gt;Breaking this command down all of the way we&amp;rsquo;re using the &lt;code&gt;-R&lt;/code&gt; flag to search in all directories recursively. The &lt;code&gt;-n&lt;/code&gt; flag tells grep to return the line numbers where the matches are found in the files. Finally, the &lt;code&gt;.&lt;/code&gt; at the end is the path for grep to search. We could be more specific with the directory to further fine tune our output. For instance we could exclude the test results by using &lt;code&gt;Hours-development/app&lt;/code&gt; as the directory to search.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Now that you know the basics of working with and searching files you should feel much more comfortable in the command line. Between working with files and understanding how the shell reads command and where commands come from you&amp;rsquo;re in a good spot to use the terminal and command line as part of your normal development tool chain.&lt;/p&gt;

&lt;p&gt;Let me know if there are any other command line specific topics you&amp;rsquo;d like me to cover, if not I&amp;rsquo;ll likely cover new things in passing as we use them in tutorials for other topics.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Command Line Intro – Part 1</title>
      <link>https://coderjourney.com/command-line-intro-part-1/</link>
      <pubDate>Wed, 26 Oct 2016 11:26:34 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/command-line-intro-part-1/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to take a few steps back to cover a tool that we&amp;rsquo;ve used in every tutorial, but never actually talked about it: the command line.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/9ld63_ULbUE&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Explore the command line shell&lt;/strong&gt; and prompt.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Understand the $PATH&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you first see a command line prompt (probably in a TV show) it can be a little intimidating. Most people imagine a mysterious, black screen with bright green letters on it. After you learn how to use the command line or shell it&amp;rsquo;s amazingly powerful, and sadly I skipped right past it when I was first thinking about tutorial topics.&lt;/p&gt;

&lt;p&gt;Nearly every tutorial I&amp;rsquo;ve created has used the shell at some point, so it&amp;rsquo;s best that we&amp;rsquo;re all familiar with what is going on.&lt;/p&gt;

&lt;h2 id=&#34;my-favorite-tool-the-shell&#34;&gt;My Favorite Tool: The Shell&lt;/h2&gt;

&lt;p&gt;The shell is probably my favorite tool. I use the shell so much while I&amp;rsquo;m programming that it&amp;rsquo;s actually the main reason that I switched from Windows to Mac: Bash (the default shell) was too powerful for me not to use. Thankfully, today Bash is actually useable on Windows (with the anniversary update to Windows 10). Follow these instructions to &lt;a href=&#34;https://msdn.microsoft.com/en-us/commandline/wsl/install_guide&#34;&gt;install bash on Windows&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The shell is the starting point for a lot of programming tasks because you can do things in a way that is reproducible and easy to share with others. It&amp;rsquo;s hard to share what you&amp;rsquo;re doing with your mouse with someone else. It would take a long time to teach someone how to use Docker if you were only able to create containers by clicking, dragging, and hovering over items on the screen. It&amp;rsquo;s quite easy for me to tell you to type the following with confidence about what will happen:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker run -it ubuntu &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello, World!&amp;#34;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;exploring-the-shell&#34;&gt;Exploring the Shell&lt;/h2&gt;

&lt;p&gt;Debatably, the most commonly used tools that your command line gives you are &lt;code&gt;cd&lt;/code&gt; and &lt;code&gt;ls&lt;/code&gt;. We&amp;rsquo;ve used these quite a few times up to this point. These are important because you&amp;rsquo;ll need to move around from directory to directory and see what&amp;rsquo;s around you.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll use &lt;code&gt;pwd&lt;/code&gt; to demonstrate a little of what these other two tools do. &lt;code&gt;pwd&lt;/code&gt; *p*rints your *w*orking *d*irectory, it&amp;rsquo;s useful for when you need to see where you&amp;rsquo;re currently at.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ &lt;span class=&#34;nb&#34;&gt;pwd&lt;/span&gt;
/Users/explorer&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The user that I use to make tutorials is named &lt;code&gt;explorer&lt;/code&gt; and this output will definitely be different for you.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; allows you to *C*hange your current working *D*irectory. Here are a few examples:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; code
code $ &lt;span class=&#34;nb&#34;&gt;pwd&lt;/span&gt;
/Users/explorer/code&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can see there that our working directory changed. We&amp;rsquo;ll switch back to our home folder to explore &lt;code&gt;ls&lt;/code&gt;. To do that we can use either a full path or a relative path, either of these two lines would work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;code $ &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; ..
~ $ &lt;span class=&#34;nb&#34;&gt;pwd&lt;/span&gt;
/Users/explorer&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;or with the full path:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;code $ &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; /Users/explorer
~ $ &lt;span class=&#34;nb&#34;&gt;pwd&lt;/span&gt;
/Users/explorer&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;code&gt;ls&lt;/code&gt; is used to list out the files and directories inside of the directory that you pass it (or the current directory).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ ls
Applications	 Documents Library Pictures	code
Desktop	Downloads	Movies Public	src
Dockerfile	 Dropbox Music Videos&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s not super useful at first glance. They&amp;rsquo;re in alphabetical order by column (why not row?), but not giving us a lot of information beyond that. Thankfully, &lt;code&gt;ls&lt;/code&gt; can take quite a few flags so that we can change the output that it gives us. The &lt;code&gt;-l&lt;/code&gt; flag will list them out vertically and give us the permissions and last changed times.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ ls -l
drwx------   &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;170&lt;/span&gt; Sep &lt;span class=&#34;m&#34;&gt;11&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;07&lt;/span&gt;:43 Applications
drwx------@  &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;136&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;11&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;17&lt;/span&gt;:06 Desktop
-rw-r--r--   &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt; explorer  staff    &lt;span class=&#34;m&#34;&gt;76&lt;/span&gt; Jul &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;15&lt;/span&gt;:09 Dockerfile
drwx------@  &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;102&lt;/span&gt; Jul &lt;span class=&#34;m&#34;&gt;26&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;:15 Documents
drwx------+  &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;170&lt;/span&gt; Oct  &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;08&lt;/span&gt;:31 Downloads
drwx------@ &lt;span class=&#34;m&#34;&gt;23&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;782&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;18&lt;/span&gt;:43 Dropbox
drwx------@ &lt;span class=&#34;m&#34;&gt;63&lt;/span&gt; explorer  staff  &lt;span class=&#34;m&#34;&gt;2142&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;18&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;20&lt;/span&gt;:05 Library
drwx------+ &lt;span class=&#34;m&#34;&gt;13&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;442&lt;/span&gt; Oct  &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;:26 Movies
drwx------+  &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;136&lt;/span&gt; Jul &lt;span class=&#34;m&#34;&gt;30&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;10&lt;/span&gt;:08 Music
drwx------+  &lt;span class=&#34;m&#34;&gt;3&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;102&lt;/span&gt; Jul &lt;span class=&#34;m&#34;&gt;26&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;:15 Pictures
drwxr-xr-x+  &lt;span class=&#34;m&#34;&gt;5&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;170&lt;/span&gt; Jul &lt;span class=&#34;m&#34;&gt;26&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;:15 Public
drwxr-xr-x  &lt;span class=&#34;m&#34;&gt;14&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;476&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;18&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;18&lt;/span&gt;:55 Videos
drwxr-xr-x   &lt;span class=&#34;m&#34;&gt;2&lt;/span&gt; explorer  staff    &lt;span class=&#34;m&#34;&gt;68&lt;/span&gt; Oct &lt;span class=&#34;m&#34;&gt;25&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;19&lt;/span&gt;:12 code
drwxr-xr-x   &lt;span class=&#34;m&#34;&gt;4&lt;/span&gt; explorer  staff   &lt;span class=&#34;m&#34;&gt;136&lt;/span&gt; Jul &lt;span class=&#34;m&#34;&gt;28&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;07&lt;/span&gt;:35 src&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Much&lt;/em&gt; more useful. The version that I usually use also includes the &lt;code&gt;-a&lt;/code&gt; flag so that I can see hidden files. This can sometimes return you a lot of files though, but the extra ones are normally hidden, you likely won&amp;rsquo;t see them in Finder.app on Mac or Windows Explorer.&lt;/p&gt;

&lt;h2 id=&#34;where-do-these-commands-come-from&#34;&gt;Where Do These Commands Come From?&lt;/h2&gt;

&lt;p&gt;One question you might be asking yourself is &amp;ldquo;Where does &lt;code&gt;ls&lt;/code&gt; come from?&amp;ldquo;, and that&amp;rsquo;s a great question. One of the biggest reasons that I think the command line seems strange at first is because there is a lot that isn&amp;rsquo;t shown to you unless you &lt;em&gt;ask&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We can see where a specific command comes from using the &lt;code&gt;which&lt;/code&gt; command. Let&amp;rsquo;s see where &lt;code&gt;ls&lt;/code&gt; lives:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ which ls
/bin/ls&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That means that there is an actual executable file at in the &lt;code&gt;/bin&lt;/code&gt; directory named &lt;code&gt;ls&lt;/code&gt; that provides the functionality that we&amp;rsquo;ve seen for &lt;code&gt;ls&lt;/code&gt;. That doesn&amp;rsquo;t entirely answer our question though because we didn&amp;rsquo;t type &lt;code&gt;/bin/ls&lt;/code&gt;, we simply typed &lt;code&gt;ls&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This leads us to the &amp;ldquo;PATH&amp;rdquo;. The &lt;code&gt;PATH&lt;/code&gt; is an environment variable that tells your shell which directories to look for to find commands. Let&amp;rsquo;s see what my &lt;code&gt;PATH&lt;/code&gt; looks like using &lt;code&gt;echo&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ &lt;span class=&#34;nb&#34;&gt;echo&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;$PATH&lt;/span&gt;
/Users/explorer/.gem/ruby/2.3.1/bin:/Users/explorer/.rubies/ruby-2.3.1/lib/ruby/gems/2.3.0/bin:/Users/explorer/.rubies/ruby-2.3.1/bin:/Users/explorer/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/share/dotnet&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;Notice:&lt;/em&gt; that we had to use a &lt;code&gt;$&lt;/code&gt; when we referenced the variable name. That&amp;rsquo;s how you access the value of a variable in bash, otherwise it&amp;rsquo;s just a string &amp;ldquo;PATH&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;My path is pretty long because it includes a lot of ruby related directories, but we can still break it down. If we take all of the ruby related paths out this is what we&amp;rsquo;re left with:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;/Users/explorer/bin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/usr/local/share/dotnet&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we type &lt;code&gt;ls&lt;/code&gt; the shell will attempt to find an executable in &lt;code&gt;/Users/explorer/bin&lt;/code&gt;. If no executable is found there it will move onto &lt;code&gt;/usr/local/bin&lt;/code&gt;, so on and so forth until it either finds an executable or it will exit with an error like this (trying use the &lt;code&gt;obj&lt;/code&gt; tool):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ pbj
-bash: pbj: &lt;span class=&#34;nb&#34;&gt;command&lt;/span&gt; not found&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you ever see that error you know that what you typed isn&amp;rsquo;t in your &lt;code&gt;$PATH&lt;/code&gt;. This can either be because the file doesn&amp;rsquo;t exist or isn&amp;rsquo;t installed, or because you had a typo (pretty common).&lt;/p&gt;

&lt;h2 id=&#34;learning-more&#34;&gt;Learning More&lt;/h2&gt;

&lt;p&gt;Almost every time we&amp;rsquo;re typing into our command line we&amp;rsquo;re running some program on our system. Most of these tools give us a way to learn more about them through either a &lt;code&gt;--help&lt;/code&gt; flag or by giving us a &amp;ldquo;man page&amp;rdquo;. If you want to learn more about a command I would suggest first using the &lt;code&gt;man&lt;/code&gt; tool like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ man pwd&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will open up a scrollable &amp;ldquo;page&amp;rdquo; that you can move down by hitting or holding your &lt;code&gt;j&lt;/code&gt; key, move up with &lt;code&gt;k&lt;/code&gt;, or quit by hitting the &lt;code&gt;q&lt;/code&gt; key.&lt;/p&gt;

&lt;p&gt;That doesn&amp;rsquo;t also work, and when it doesn&amp;rsquo;t then it&amp;rsquo;s a safe bet to try using &lt;code&gt;--help&lt;/code&gt;. Not all tools respond to this, but if they don&amp;rsquo;t they&amp;rsquo;ll probably tell you what you could have typed to make the tool work. &lt;code&gt;cd&lt;/code&gt; is a good example of this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;~ $ &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; --help
cd: usage: &lt;span class=&#34;nb&#34;&gt;cd&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;-L&lt;span class=&#34;p&#34;&gt;|&lt;/span&gt;-P&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;dir&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Other tools will give you &amp;ldquo;man page&amp;rdquo; style information without opening in a page so you can scroll through your terminal how you normally would (&lt;code&gt;docker&lt;/code&gt; is a good example of this).&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;I might be a little too enthusiastic about the shell, but I use it every day and the more that I learn to do from my prompt the better I seem to be at my job. This tutorial was meant to demystify the command line a little and give you a means to learn more on your own. I&amp;rsquo;ll dig deeper in a later tutorial to show how we can customize our shell experience and some of my favorite command line utilities to use.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Getting Started with Python Functions</title>
      <link>https://coderjourney.com/getting-started-python-functions/</link>
      <pubDate>Wed, 19 Oct 2016 00:02:48 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/getting-started-python-functions/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to learn how to package up small chunks of code for reuse using functions.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/l_4ItVEbtp4&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create our first function&lt;/strong&gt; to execute code multiple times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learn about &lt;code&gt;range&lt;/code&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learn about function arguments&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In most of our programming, we won&amp;rsquo;t be working with a script that we&amp;rsquo;re going to run from top to bottom. Most of our time is going to be spent grouping code together in a way that makes sense to use and then combining the piece that we build up in order to create our final product. The simplest way we can package up our code is by using a function.&lt;/p&gt;

&lt;h2 id=&#34;python-functions-are-pretty-awesome&#34;&gt;Python Functions are Pretty Awesome&lt;/h2&gt;

&lt;p&gt;Functions are the building block that virtually every programming language has in common, and are even the most important building block in some languages. Python functions aren&amp;rsquo;t the &lt;em&gt;most&lt;/em&gt; important, but they are very powerful.&lt;/p&gt;

&lt;p&gt;I like to think of functions in programming in the way that you might learn about functions in mathematics. Let&amp;rsquo;s break down a math function and turn it into a Python function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;f(x) = x + 1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our function has the name of &lt;code&gt;f&lt;/code&gt; and it requires a single variable &lt;code&gt;x&lt;/code&gt;. We will define this function in Python using the &lt;code&gt;def&lt;/code&gt; keyword:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We follow our function name and arguments with a &lt;code&gt;:&lt;/code&gt; and then we will indent the actual logic of the function by 4 spaces. After the body of the function we&amp;rsquo;ll insert a blank line which will end the function.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;ve defined our function, now let&amp;rsquo;s take it for a spin:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That&amp;rsquo;s not quite right. In our math function if we use &lt;code&gt;1&lt;/code&gt; for &lt;code&gt;x&lt;/code&gt; then the answer should be &lt;code&gt;2&lt;/code&gt;, but we didn&amp;rsquo;t get anything. Our function works this way because unlike mathematical functions which always produce an output, Python functions can take an action and then return nothing to us. To make this work like the math function we need to use the keyword &lt;code&gt;return&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;x&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we try to run the function again, we should get &lt;code&gt;2&lt;/code&gt; back:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;f&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;beyond-math-onto-fizz-buzz&#34;&gt;Beyond Math&amp;hellip; Onto Fizz Buzz&lt;/h2&gt;

&lt;p&gt;Figuring out how to represent a math function in Python is one thing, but that really doesn&amp;rsquo;t event scratch the surface of Python functions.&lt;/p&gt;

&lt;p&gt;Functions are not restricted to being a single line, so we can package up a series of expressions to execute. We&amp;rsquo;ll demonstrate this using a problem from programming interviews called &amp;ldquo;fizz buzz&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;For &amp;ldquo;fizz buzz&amp;rdquo; we&amp;rsquo;re going to take a number and print from 1 to that number and for each number we will print one of the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;ldquo;Fizz&amp;rdquo; if the number is divisible by 3&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Buzz&amp;rdquo; if the number if divisible by 5&lt;/li&gt;
&lt;li&gt;&amp;ldquo;Fizz Buzz&amp;rdquo; if the number is divisible by 3 &lt;em&gt;and&lt;/em&gt; 5&lt;/li&gt;
&lt;li&gt;The number itself if not divisible by 3 &lt;em&gt;or&lt;/em&gt; 5&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here&amp;rsquo;s an example of one way we could write this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fizz_buzz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Fizz &amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Buzz&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This function combines loops, conditionals, strings, conditionals, printing, and even throws in something new: &lt;code&gt;range&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;range&lt;/code&gt; is a sequence of numbers, in our case it&amp;rsquo;s from &lt;code&gt;1&lt;/code&gt; to whatever the passed in &lt;code&gt;limit&lt;/code&gt; is, excluding the &lt;code&gt;limit&lt;/code&gt; itself. Ranges are great for when you want to iterate through something a specific number of times or in our case where we want to do something with each number, but we don&amp;rsquo;t want to create a list ourselves.&lt;/p&gt;

&lt;p&gt;This is a fairly complex function, and now we can run it over whatever limit we want, as many times as we want.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fizz_buzz&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;17&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Fizz&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Buzz&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Fizz&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Fizz&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Buzz&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;11&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Fizz&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;13&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;14&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Fizz&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Buzz&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;16&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;fizz-buzz-but-better&#34;&gt;Fizz Buzz, but Better&lt;/h2&gt;

&lt;p&gt;Our original example was a good example of creating a more complex function body, but there is more that we can do in the function declaration that can make it even better. For instance we can give &lt;code&gt;limit&lt;/code&gt; a default (we&amp;rsquo;re going to call this &lt;code&gt;fizz_buzz2&lt;/code&gt; to keep them separate):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fizz_buzz2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Fizz &amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Buzz&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we call &lt;code&gt;fizz_buzz2&lt;/code&gt; without any arguments it will automatically use &lt;code&gt;20&lt;/code&gt; as the value for &lt;code&gt;limit&lt;/code&gt;. Pretty neat!&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s take this even one step forward and make the &amp;ldquo;fizz&amp;rdquo; and &amp;ldquo;buzz&amp;rdquo; messages configurable (this is &lt;code&gt;fizz_buzz3&lt;/code&gt;):&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;fizz_buzz3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fizz&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Fizz&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buzz&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Buzz&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;range&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;limit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
        &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fizz&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buzz&lt;/span&gt;
        &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;output&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This version of fizz buzz is the best we&amp;rsquo;re going to create. We&amp;rsquo;re now using multiple arguments, some with defaults and some without. Let&amp;rsquo;s look at some of the ways we can call this function:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fizz_buzz3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Red&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Blue&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Red&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Blue&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Red&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fizz_buzz3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;buzz&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Boom!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Fizz&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Boom&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;!&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Fizz&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In our first example we used all positional arguments, meaning the order we passed them in would be interpreted as the order we defined them. The second time we ran it though, we used what&amp;rsquo;s known as a &lt;em&gt;keyword argument&lt;/em&gt;. We let &lt;code&gt;fizz&lt;/code&gt; take its default value, but we explicitly set &lt;code&gt;buzz&lt;/code&gt; to be &lt;code&gt;Boom!&lt;/code&gt;&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;re finally getting into the more exciting parts of programming. Before today, most of what we&amp;rsquo;ve learned about were the small building blocks that we&amp;rsquo;ll use to build up an individual line of code, but with functions we&amp;rsquo;re learning the tools we need to write more complex programs. From here, there are only a few more broad topics that we&amp;rsquo;ll need to cover before we can start digging into the problem solving of programming.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learn How to Use Loops in Python</title>
      <link>https://coderjourney.com/loops-in-python/</link>
      <pubDate>Wed, 12 Oct 2016 00:12:54 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/loops-in-python/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to learn how to execute the same block of code multiple times using loops, and how to take actions on each element in a list.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/ba9Obrz4Qjg&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Create our first loop&lt;/strong&gt; to execute code multiple times.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Learn how to iterate&lt;/strong&gt; through a list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Last time we worked with Python, we learned about lists and tuples, but we didn&amp;rsquo;t really do anything with them. For lists to really be useful we will need to be able to do things with the data. That means we either need to be able to find and work on a specific piece of data (which we know how to do already), or we need to take &lt;em&gt;each element&lt;/em&gt; of the list or tuple and do something with it. We probably won&amp;rsquo;t do this with tuples, so from this point on I&amp;rsquo;ll just be talking about lists.&lt;/p&gt;

&lt;p&gt;To work on each element we another language feature: loops.&lt;/p&gt;

&lt;h2 id=&#34;the-original-loop-the-while-loop&#34;&gt;The Original Loop: The &lt;em&gt;While&lt;/em&gt; Loop&lt;/h2&gt;

&lt;p&gt;Like a lot of things in Python, loops are incredible readable, and because of that make a lot of sense when you see them. Let&amp;rsquo;s start by taking a look at the &lt;code&gt;while&lt;/code&gt; loop:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;This is a: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The while loop takes an expression and executes the block underneath if that expression is true, much the same way that an &lt;code&gt;if&lt;/code&gt; statement would. The difference here is that it will look at that expression over and over again until it is false.&lt;/p&gt;

&lt;p&gt;This type of loop allows us to do something over and over again, but if you forget to modify a variable used in the expression it is possible to run into an infinite loop, so look out for that.&lt;/p&gt;

&lt;p&gt;There are a few other keywords associated with loops: &lt;code&gt;break&lt;/code&gt;, &lt;code&gt;continue&lt;/code&gt;, and &lt;code&gt;else&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Looking at &lt;code&gt;else&lt;/code&gt; first, it&amp;rsquo;s used to run something when the looping finishes. Building on our first loop this is how we could utilize &lt;code&gt;else&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;This is a: &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;We&amp;#39;ve reached 5&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;We&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;ve reached 5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To learn about &lt;code&gt;break&lt;/code&gt; and &lt;code&gt;continue&lt;/code&gt; we&amp;rsquo;ll take a look at the
other type of list that you&amp;rsquo;ll use in Python: the &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;

&lt;h2 id=&#34;looping-over-lists-the-for-loop&#34;&gt;Looping Over Lists: The &lt;em&gt;For&lt;/em&gt; Loop&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;while&lt;/code&gt; loop is powerful and can be used to accomplish any type of looping that we need, but most of the time what we want to do is iterate over a list, and for that we have the &lt;code&gt;for&lt;/code&gt; loop.&lt;/p&gt;

&lt;p&gt;This next example will show both a &lt;code&gt;for&lt;/code&gt; loop and the &lt;code&gt;continue&lt;/code&gt; keyword in action:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;         &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;is even&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;         &lt;span class=&#34;k&#34;&gt;continue&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;is odd&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;odd&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;even&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;odd&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;even&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;odd&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Looking at the creation of the &lt;code&gt;for&lt;/code&gt; loop you can see the readability that I mentioned earlier. We create a temporary variable for each element in our list called &lt;code&gt;num&lt;/code&gt; and then we can use that in our loop block. Once we&amp;rsquo;ve gone through every item of the list then our loop is finished.&lt;/p&gt;

&lt;p&gt;We wrote this loop specifically to showcase the &lt;code&gt;continue&lt;/code&gt; keyword and we would normally write this differently, but it gets the point across. &lt;code&gt;continue&lt;/code&gt; allows us to stop executing our current loop iteration and move onto the next one. If we hadn&amp;rsquo;t used &lt;code&gt;continue&lt;/code&gt; here we would have printed that some numbers were both even &lt;em&gt;and&lt;/em&gt; odd.&lt;/p&gt;

&lt;p&gt;The last keyword that loops have is &lt;code&gt;break&lt;/code&gt;, so let&amp;rsquo;s see how that works.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;num&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;         &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;num&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;is less than 6&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;     &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;         &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;...&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;less&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;than&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;less&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;than&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;less&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;than&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Looking at the list we should have been able to see all but one of the items print out, except we hit the &lt;code&gt;break&lt;/code&gt; statement. Where &lt;code&gt;continue&lt;/code&gt; halts a single iteration of a loop, &lt;code&gt;break&lt;/code&gt; halts the entire loop. The &lt;code&gt;4&lt;/code&gt; and &lt;code&gt;5&lt;/code&gt; that were in the loop after the &lt;code&gt;6&lt;/code&gt; were never iterated over because the &lt;code&gt;break&lt;/code&gt; was triggered when we iterated over the &lt;code&gt;6&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Now you know how to create loops in Python. Loops are one of the most common tools that we will use in programming (&lt;code&gt;for&lt;/code&gt; more than &lt;code&gt;while&lt;/code&gt;), so commit these to memory sooner rather than later.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Convert an Existing Rails Application to Work with Docker</title>
      <link>https://coderjourney.com/convert-rails-app-to-docker/</link>
      <pubDate>Tue, 04 Oct 2016 23:40:02 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/convert-rails-app-to-docker/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to take an existing Ruby on Rails application and convert it so that it be developed/deployed using Docker.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/dF6VQOZPZBM&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Dockerizing an existing rails application.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Up to this point we&amp;rsquo;ve been working with &amp;ldquo;hello world&amp;rdquo; applications when working with Docker, but today we&amp;rsquo;re going to take an existing application (that I didn&amp;rsquo;t write) and get it to
work with Docker.&lt;/p&gt;

&lt;h2 id=&#34;dockerizing-a-rails-application&#34;&gt;Dockerizing a Rails Application&lt;/h2&gt;

&lt;p&gt;The application that we&amp;rsquo;re going to convert today is an open source Rails application for time tracking called &lt;a href=&#34;https://github.com/DefactoSoftware/Hours&#34;&gt;&amp;ldquo;Hours&amp;rdquo;&lt;/a&gt;. This particular application requires a few different services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ruby/Rails&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/_/postgres/&#34;&gt;PostgreSQL&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/_/memcached/&#34;&gt;Memcached&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since this project isn&amp;rsquo;t currently set up to be used with Docker, the first thing we&amp;rsquo;ll do is clone the repo and create a &lt;code&gt;docker-compose.yml&lt;/code&gt; file to lay out all of our services.&lt;/p&gt;

&lt;p&gt;Cloning:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ git clone git@github.com:DefactoSoftware/Hours.git&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now let&amp;rsquo;s crack open our &lt;code&gt;docker-compose.yml&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;docker-compose.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;services&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;cache&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;memcached&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1.4&lt;/span&gt;-alpine&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;	  &lt;/span&gt;environment&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;		  &lt;/span&gt;POSTGRES_USER&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;		  &lt;/span&gt;POSTGRES_PASSWORD&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;9.5&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/usr/local/pgsql/data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;	&lt;/span&gt;jobs&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;	  &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;build&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;	    &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/usr/src/app&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;		&lt;/span&gt;command&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;bundle&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;exec&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;rake&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;jobs&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;work&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;depends_on&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;	  &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;build&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;	    &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/usr/src/app&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;8080:8080&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;depends_on&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;cache&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we need to set up our &lt;code&gt;Dockerfile&lt;/code&gt; so that we can build an image to run our application on. This application uses Capybara-webkit for testing so we&amp;rsquo;ll need to install some extra dependencies for that to work:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; ruby:2.3.1&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; apt-get update -yqq &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get install -yqq --no-install-recommends &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    postgresql-client &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    nodejs &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    qt5-default &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    libqt5webkit5-dev &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get -q clean &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -rf /var/lib/apt/lists&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;WORKDIR&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; /usr/src/app&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;COPY Gemfile* ./&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; bundle install&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;COPY . .&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;CMD&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; bundle exec unicorn -c ./config/unicorn.rb&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We&amp;rsquo;ll need to create &lt;code&gt;config/database.yml&lt;/code&gt; and &lt;code&gt;config/secrets.yml&lt;/code&gt; before our application will work. Hours is build around deploying to Heroku, and Heroku manages some of this configuration for you.&lt;/p&gt;

&lt;p&gt;Database:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/database.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# config/database.yml&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;default&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;&amp;amp;default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;adapter&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgresql&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;host&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&amp;lt;%=&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ENV&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;POSTGRES_HOST&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;%&lt;span class=&#34;sd&#34;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  username: &amp;lt;%= ENV[&amp;#34;POSTGRES_USER&amp;#34;] %&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  password: &amp;lt;%= ENV[&amp;#34;POSTGRES_PASSWORD&amp;#34;] %&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  encoding: utf8
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  min_messages: warning
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  pool: 2
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  timeout: 5000&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;development&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&amp;lt;&amp;lt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;*default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;database&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;hours_development&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;test&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&amp;lt;&amp;lt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;*default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;database&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;hours_test&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;production&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&amp;lt;&amp;lt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;*default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;database&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;hours_production&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;config/secrets.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;development&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;secret_key_base&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&amp;lt;%=&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ENV&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;SECRET_KEY_BASE&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;%&lt;span class=&#34;sd&#34;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;development:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;secret_key_base&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&amp;lt;%=&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ENV&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;SECRET_KEY_BASE&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;%&lt;span class=&#34;sd&#34;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;production:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;secret_key_base&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&amp;lt;%=&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ENV&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;SECRET_KEY_BASE&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;%&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&amp;rsquo;ll notice that we&amp;rsquo;ve used quite a few environment variables thus far. Environment variables are potentially the easiest way to configure our application, but they can be tedious. Thankfully, &lt;code&gt;docker-compose&lt;/code&gt; allows us to use a &lt;code&gt;.env&lt;/code&gt; file to store the values that we would like to use in our containers and we don&amp;rsquo;t need to set them in our own environment.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s create our own &lt;code&gt;.env&lt;/code&gt; file now by copying the &lt;code&gt;.sample.env&lt;/code&gt; file and making some adjustments.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;POSTGRES_HOST=db
POSTGRES_USER=hours
POSTGRES_PASSWORD=super_secure

SECRET_KEY_BASE=development_secret
GMAIL_USERNAME=&amp;#34;example@mail.com&amp;#34;
GMAIL_PASSWORD=&amp;#34;password&amp;#34;
HELPFUL_URL=https://example.io/incoming_message
HELPFUL_ACCOUNT=helpful_account
SINGLE_TENANT_MODE=true
S3_BUCKET_NAME=&amp;#34;s3_bucket_name&amp;#34;
AWS_ACCESS_KEY_ID=&amp;#34;aws_access_key_id&amp;#34;
AWS_SECRET_ACCESS_KEY=&amp;#34;aws_secret_access_key&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we&amp;rsquo;re ready to take our group of containers for a spin.&lt;/p&gt;

&lt;h2 id=&#34;spinning-up-our-containers&#34;&gt;Spinning up our Containers&lt;/h2&gt;

&lt;p&gt;Like we had to when learning to develop a Rails application using Docker, we&amp;rsquo;re going to need to do a few things before our application will actually run. First, we&amp;rsquo;re going to need to create our database. We can do that by starting our services that are going to run from images, those shouldn&amp;rsquo;t have any issues.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose up -d db cache&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will create the network that all of our containers connect to to communicate with one another and also start our memcached and postgres containers.&lt;/p&gt;

&lt;p&gt;Next up, we&amp;rsquo;ll need to build our &lt;code&gt;app&lt;/code&gt; image before we can run commands. This is going to need to install all of the gems and dependencies so it will likely take awhile. A nearly identical image will be used for our &lt;code&gt;jobs&lt;/code&gt; container so we&amp;rsquo;ll build that now also.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose build app jobs&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After we&amp;rsquo;ve build our image we can run some commands with it. First, we need to create and migrate our database:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose run --rm app rake db:create db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Second, we want to create a user for ourselves within the application.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose run --rm app rake create_user
First name: Coder
Last name: Journey
email: keith@coderjourney.com
Password:
The user is created&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we&amp;rsquo;re good to spin up our &lt;code&gt;app&lt;/code&gt; and &lt;code&gt;jobs&lt;/code&gt; containers.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose up -d app jobs&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before moving any further we should make sure that all of our containers are running using &lt;code&gt;docker-compose ps&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose ps
    Name                   Command               State           Ports
-------------------------------------------------------------------------------
hours_app_1     /bin/sh -c bundle &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; uni ...   Up      &lt;span class=&#34;m&#34;&gt;0&lt;/span&gt;.0.0.0:8080-&amp;gt;8080/tcp
hours_cache_1   docker-entrypoint.sh memcached   Up      &lt;span class=&#34;m&#34;&gt;11211&lt;/span&gt;/tcp
hours_db_1      /docker-entrypoint.sh postgres   Up      &lt;span class=&#34;m&#34;&gt;5432&lt;/span&gt;/tcp
hours_jobs_1    bundle &lt;span class=&#34;nb&#34;&gt;exec&lt;/span&gt; rake jobs:work       Up&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we can head over to &lt;code&gt;localhost:8080&lt;/code&gt; and check out our new time tracking application.&lt;/p&gt;

&lt;h2 id=&#34;fixing-the-test-suite&#34;&gt;Fixing the Test Suite&lt;/h2&gt;

&lt;p&gt;Right now, if we try to run the test suite we&amp;rsquo;ll get some errors because it can&amp;rsquo;t find certain pieces of the page to click on. This is caused by this application already using a &lt;code&gt;.env&lt;/code&gt; file to load environment variables into the application and us having explicitly defined environment variables in our containers. We&amp;rsquo;re going to get around this by overloading the environment in the test so that it&amp;rsquo;s always the same.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;spec/spec_helper.rb&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Environment set to &amp;#34;test&amp;#34; above&lt;/span&gt;

&lt;span class=&#34;nb&#34;&gt;require&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;dotenv&amp;#34;&lt;/span&gt;
&lt;span class=&#34;no&#34;&gt;Dotenv&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;overload&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;.sample.env&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;c1&#34;&gt;# environment file loaded below&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It&amp;rsquo;s important that we put these two lines in the right spot so that we set the environment variables before loading the rails app for our tests, just in case those ENV values are stored in constants somewhere.&lt;/p&gt;

&lt;p&gt;Now we can see if it worked by running:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ rake&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The tests should all be green! Congrats on converting your first application to using Docker.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;All of the code for this tutorial can be found on &lt;a href=&#34;https://github.com/coderjourney/Hours/tree/dockerize-application&#34;&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m looking for feedback on upcoming topics. Head over and answer my &lt;a href=&#34;https://www.surveymonkey.com/r/NMLQ6DQ&#34;&gt;single question survey&lt;/a&gt; go let me know what you think I should cover.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Deploy with Docker and Digital Ocean</title>
      <link>https://coderjourney.com/deploy-docker-digital-ocean/</link>
      <pubDate>Sat, 24 Sep 2016 15:56:51 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/deploy-docker-digital-ocean/</guid>
      <description>

&lt;p&gt;Building on top of our docker-machine tutorial, we&amp;rsquo;re going to use the docker toolbox to create provision a server and deploy a Ruby on Rails application to the cloud.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/jlVrYgVEl6M&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a Docker host with docker-machine.&lt;/li&gt;
&lt;li&gt;Deploy a Ruby on Rails application to the server using docker-compose.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Up to this point we&amp;rsquo;ve looked at how to utilize the Docker in our development environment, how to package up our own images, and how to use docker-compose to orchestrate different services in our development environment. These things are all great for having a sharable development, but there&amp;rsquo;s nothing stopping us from using this for deploying applications.&lt;/p&gt;

&lt;h2 id=&#34;our-rails-application&#34;&gt;Our Rails Application&lt;/h2&gt;

&lt;p&gt;We’re actually going to build on top of the previous &lt;a href=&#34;https://coderjourney.com/docker-for-development/&#34;&gt;Docker in Development&lt;/a&gt; tutorial for our application. It shouldn’t be too difficult to take the basic application that we created in that tutorial and run it in the cloud.&lt;/p&gt;

&lt;p&gt;The first thing that we need to do though is grab the code. We’ll use &lt;a href=&#34;https://git-scm.com/&#34;&gt;git&lt;/a&gt; to pull the sample code from the previous tutorial from &lt;a href=&#34;https://github.com/coderjourney/03-learn-to-use-docker-in-development&#34;&gt;github&lt;/a&gt;. We’re placing a &lt;code&gt;.&lt;/code&gt; at the end of this command so that the contents of the repository are placed in our current directory.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ git clone git@github.com:coderjourney/03-learn-to-use-docker-in-development.git .&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ll need to change into the &lt;code&gt;blog&lt;/code&gt; directory, but besides that we’re good to go with a Rails application.&lt;/p&gt;

&lt;h2 id=&#34;looking-at-the-docker-setup&#34;&gt;Looking at the Docker Setup&lt;/h2&gt;

&lt;p&gt;Before we get too far we should refresh our memories as to how we’ve set up Docker and docker-compose in this application.&lt;/p&gt;

&lt;p&gt;Dockerfile:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-dockerfile&#34; data-lang=&#34;dockerfile&#34;&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; ruby:2.3&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; apt-get update -yqq &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;  &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get install -yqq --no-install-recommends &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    postgresql-client &lt;span class=&#34;se&#34;&gt;\
&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;&lt;/span&gt;    &lt;span class=&#34;o&#34;&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -rf /var/lib/apt/lists&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;WORKDIR&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; /usr/src/app&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;COPY Gemfile* ./&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;RUN&lt;/span&gt; bundle install&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;COPY . .&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;EXPOSE&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; 3000&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;CMD&lt;/span&gt;&lt;span class=&#34;s&#34;&gt; rails server -b 0.0.0.0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;docker-compose.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;services&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/var/lib/postgresql/db-data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;build&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/usr/src/app&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;depends_on&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ve also packaged up the &lt;code&gt;.env&lt;/code&gt; file that holds the environment variables that we’re passing into the containers. Normally I wouldn’t store this file in version control because it contains secrets and passwords. Let’s look at that file again.&lt;/p&gt;

&lt;p&gt;.env:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;POSTGRES_USER=coderjourney
POSTGRES_PASSWORD=abcd1234&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Everything here looks pretty good so let’s see if we can deploy this as is.&lt;/p&gt;

&lt;h2 id=&#34;docker-machine-digital-ocean&#34;&gt;Docker-machine &amp;amp; Digital Ocean&lt;/h2&gt;

&lt;p&gt;There are essentially two things that we need to deploy a container for a web application into the wild:&lt;/p&gt;

&lt;p&gt;1) A docker host server to run the container
2) An image to download or a Dockerfile to build the image from&lt;/p&gt;

&lt;p&gt;Thankfully, Docker provides us with a really nice tool for building docker hosts easily in quite a few hosting providers. For this tutorial, we&amp;rsquo;re going to host with &lt;a href=&#34;https://m.do.co/c/3e5160725c43&#34;&gt;Digital Ocean&lt;/a&gt; (that link will get you a $10 credit for signing up) and creating our host using &lt;a href=&#34;https://docs.docker.com/machine/&#34;&gt;docker-machine&lt;/a&gt;. You&amp;rsquo;ll need to sign up with digital ocean before we begin because you&amp;rsquo;ll need to grab your API token. Once you have your account you can go &lt;a href=&#34;https://cloud.digitalocean.com/settings/api/tokens&#34;&gt;here&lt;/a&gt; to generate a new API token.&lt;/p&gt;

&lt;p&gt;I have my token store in the environment variable &lt;code&gt;DO_TOKEN&lt;/code&gt; (you can set that for yourself using &lt;code&gt;export DO_TOKEN=&amp;quot;YOUR_TOKEN&amp;quot;&lt;/code&gt;. Now that we have our API token, we can use &lt;code&gt;docker-machine&lt;/code&gt; to actually create a droplet for us and set it up to be a docker host for us.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine create --driver&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;digitalocean --digitalocean-access-token&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;$DO_TOKEN&lt;/span&gt; --digitalocean-size&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;1gb blog&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have our first Docker host running &amp;ldquo;in the cloud&amp;rdquo; 😀. There are a lot more configuration values that you can pass to the digital ocean driver, so check those out in the &lt;a href=&#34;https://docs.docker.com/machine/drivers/digital-ocean/&#34;&gt;Docker docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After our machine is up and running we&amp;rsquo;ll want to set that as our active machine using the &lt;code&gt;env&lt;/code&gt; command &lt;code&gt;docker-machine&lt;/code&gt; gives us:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;docker-machine env blog&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;deploying-with-docker&#34;&gt;Deploying with Docker&lt;/h2&gt;

&lt;p&gt;Like we had to when learning to develop a Rails application using Docker, we&amp;rsquo;re going to need to do a few things before our application will actually run. First, we&amp;rsquo;re going to need to create our database. We can do that by starting our services that are going to run from images, those shouldn&amp;rsquo;t have any issues.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose up -d db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will create the network that all of our containers connect to to communicate with one another and also start our postgres container.&lt;/p&gt;

&lt;p&gt;Next up, we&amp;rsquo;ll need to build our &lt;code&gt;app&lt;/code&gt; image before we can run commands. This is going to need to install all of the gems and dependencies so it will likely take awhile.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose build app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After we&amp;rsquo;ve build our image we can run some commands with it. First, we need to create and migrate our database:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose run --rm app rake db:create db:migrate
/usr/src/app/Gemfile not found&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Well that’s not good. This is an issue caused by our &lt;code&gt;docker-compose.yml&lt;/code&gt; file sharing through our local volume so that we could develop using our normal tools and run the application in a container. That doesn’t work with a remote docker host like we’re working with now.&lt;/p&gt;

&lt;p&gt;To fix this problem we need to change the &lt;code&gt;docker-compose.yml&lt;/code&gt; file, but that will mean that we won’t be able to work with our application in development 😱. Thankfully, we can get past that by create a different compose file for our “production” deploys.&lt;/p&gt;

&lt;p&gt;Let’s make a copy of our current file and call it &lt;code&gt;docker-compose.prod.yml&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ cp docker-compose.yml docker-compose.prod.yml&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We can make a few tweaks to this file and we’ll be well on our way to having this app deployed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;docker-compose.prod.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;version&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;2&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;external&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kc&#34;&gt;false&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;services&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;db&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;image&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;postgres&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;volumes&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db-data&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;/var/lib/postgresql/db-data&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;app&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;build&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;env_file&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;.env&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;environment&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;RAILS_ENV&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;production&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;ports&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;3000:3000&amp;#34;&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;depends_on&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;-&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;db&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’ll also adjust the “production” block of our &lt;code&gt;config/database.yml&lt;/code&gt; and add &amp;ldquo;POSTGRES_HOST&amp;rdquo; to our &lt;code&gt;.env&lt;/code&gt; file to make sure we can connect to the database.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;config/database.yml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Extra values excluded&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;production&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&amp;lt;&amp;lt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;cp&#34;&gt;*default&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;host&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&amp;lt;%=&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;ENV&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;POSTGRES_HOST&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;%&lt;span class=&#34;sd&#34;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&#34;sd&#34;&gt;  database: blog_production&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;.env:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;POSTGRES_HOST=db
POSTGRES_USER=coderjourney
POSTGRES_PASSWORD=abcd1234&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Since we’ve made a modification to the files that are in the image we’ll need to rebuild our &lt;code&gt;app&lt;/code&gt; image before we continue, thankfully the caching will allow this to be quick. Notice that we&amp;rsquo;re using the &lt;code&gt;-f&lt;/code&gt; flag to specify a different docker-compose file.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml build app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After that’s finished we should be able to create our database:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml run --rm app rake db:create db:migrate&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Yay, Our database was successfully created! Let&amp;rsquo;s start our application and see if it works. We&amp;rsquo;ll run in the foreground so that we can see the logs.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml up app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;connecting-to-the-app&#34;&gt;Connecting to the App&lt;/h2&gt;

&lt;p&gt;We should be running now. Our next step is to try to access the application. For that we’ll need the IP address of our machine (your IP will be different).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine ip blog
&lt;span class=&#34;m&#34;&gt;45&lt;/span&gt;.55.89.18&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we go to &lt;code&gt;http://45.55.89.18:3000&lt;/code&gt; we should see our application… Except we get this message:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;An unhandled lowlevel error occurred. The application logs may have details.
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&#34;fixing-the-app&#34;&gt;Fixing the App&lt;/h2&gt;

&lt;p&gt;Thankfully, if we look at our logs we see this error:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;#&amp;lt;RuntimeError: Missing `secret_key_base` for &amp;#39;production&amp;#39; environment, set this value in `config/secrets.yml`&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to define a &lt;code&gt;SECRET_KEY_BASE&lt;/code&gt; in our .env file since that&amp;rsquo;s the environment variable used in &lt;code&gt;config/secrets.yml&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;POSTGRES_HOST=db
POSTGRES_USER=coderjourney
POSTGRES_PASSWORD=abcd1234
SECRET_KEY_BASE=cb6b786b1ec490b51694594a1243cffef162655f93f5f0927ef7de7553039d7440560cba832a5ec53c0e7293f3382ce707628367bde3b8290255ada8a3f64737&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After that&amp;rsquo;s finished we&amp;rsquo;ll run our application again, this time in the background (confidence!).&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-compose -f docker-compose.prod.yml up -d app&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we try to connect to &lt;code&gt;http://45.55.89.18:3000&lt;/code&gt; now we should see our fancy &amp;ldquo;Hello from Docker&amp;rdquo; message.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;We&amp;rsquo;ve successfully deployed a &amp;ldquo;hello world&amp;rdquo; rails application to a docker host running in the cloud. There were a few snags that we had to deal with that don&amp;rsquo;t happen when running in development, from a local VM, but we made it through it. This deploy is not &amp;ldquo;good&amp;rdquo;. There&amp;rsquo;s quite a bit more that we should have done to get this production ready, but we did get the application to run.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Use Docker-machine to Create Docker Servers</title>
      <link>https://coderjourney.com/docker-machine-intro/</link>
      <pubDate>Tue, 20 Sep 2016 10:09:42 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/docker-machine-intro/</guid>
      <description>

&lt;p&gt;Continuing our series looking into Docker, we&amp;rsquo;re going to bust open the docker toolbox and look at docker-machine.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/OWhhOQAiGt0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Create a local Docker host using docker-machine.&lt;/li&gt;
&lt;li&gt;Look at the difference between docker-machine and Docker for Mac/Windows.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Up to this point we&amp;rsquo;ve used Docker for Mac (or Windows) exclusively as our Docker server, but you&amp;rsquo;re more than likely going to run Docker on a Linux machine when not in development. The docker-toolbox has a tool to make it easy to spin up Docker hosts in a variety of linux environments, &lt;code&gt;docker-machine&lt;/code&gt;. We&amp;rsquo;re going to use &lt;code&gt;docker-machine&lt;/code&gt; in combination with &lt;a href=&#34;https://www.virtualbox.org/wiki/Downloads&#34;&gt;VirtualBox&lt;/a&gt; to manage a Docker host VM locally. Docker for Mac and Windows are graphical applications for working your local Docker host and depending on the platform utilizes different technologies under the hood. Docker for Mac utilizes &lt;a href=&#34;https://github.com/docker/HyperKit/&#34;&gt;HyperKit&lt;/a&gt; to manage a Linux virtual machine for you, and Docker for Windows utilizes &lt;a href=&#34;https://technet.microsoft.com/library/hh831531.aspx&#34;&gt;Microsoft Hyper-V&lt;/a&gt;. VirtualBox is a cross-platform solution for running virtual machines, and was the primary way of running docker on Mac or Windows before the GUIs were released. There are also performance differences that you might run into using the various technologies.&lt;/p&gt;

&lt;h2 id=&#34;creating-a-docker-host-with-docker-machine&#34;&gt;Creating a Docker Host with Docker-machine&lt;/h2&gt;

&lt;p&gt;Once you&amp;rsquo;ve installed &lt;a href=&#34;https://www.virtualbox.org/wiki/Downloads&#34;&gt;VirtualBox&lt;/a&gt; to your system you can head to your command line to create your first VM manually.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine create --driver&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;virtualbox test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will create a light-weight, Linux VM running a distro called &lt;code&gt;Boot2Docker&lt;/code&gt;.  You&amp;rsquo;ll notice that the output says to run &lt;code&gt;docker-machine env test&lt;/code&gt; to learn how to connect to the machine, so let&amp;rsquo;s do that now.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine env &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;DOCKER_TLS_VERIFY&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;1&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;DOCKER_HOST&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;tcp://192.168.99.100:2376&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;DOCKER_CERT_PATH&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;/Users/explorer/.docker/machine/machines/test&amp;#34;&lt;/span&gt;
&lt;span class=&#34;nb&#34;&gt;export&lt;/span&gt; &lt;span class=&#34;nv&#34;&gt;DOCKER_MACHINE_NAME&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# Run this command to configure your shell:&lt;/span&gt;
&lt;span class=&#34;c1&#34;&gt;# eval $(docker-machine env test)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Your values will be different, but it should look similar.&lt;/p&gt;

&lt;p&gt;All that we need to do to connect to our new Docker host is set some environment variables. This works because Docker uses a clint-server architecture and our &lt;code&gt;docker&lt;/code&gt; command line tool is the client. We configure the client so that it knows which server to talk to using these four environment variables. This makes it easy for us to access multiple Docker hosts from the same machine by changing some of these values. We&amp;rsquo;ll run the command that it suggests to configure our docker client.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ &lt;span class=&#34;nb&#34;&gt;eval&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;docker-machine env &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If we run Docker commands now we should get results because it actually has a docker host to connect to. Let&amp;rsquo;s try this out by listing our our images.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We didn&amp;rsquo;t receive any images because we&amp;rsquo;ve never run a &lt;code&gt;docker pull&lt;/code&gt; when connected to our new VM. Since images are stored on the docker host, we&amp;rsquo;ll have our images again when we connect back up to the Docker for Mac or Windows VM.&lt;/p&gt;

&lt;h2 id=&#34;starting-stopping-and-removing-a-docker-host&#34;&gt;Starting, Stopping, and Removing a Docker Host&lt;/h2&gt;

&lt;p&gt;Now that we have our VM and we&amp;rsquo;re connected to it, we&amp;rsquo;re back to where we were before in terms of using Docker. Rather than go through more docker commands, we&amp;rsquo;re going to look into what else we can do with &lt;code&gt;docker-machine&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The most basic thing that we&amp;rsquo;ll do with &lt;code&gt;docker-machine&lt;/code&gt; is look at the status of the machines that we&amp;rsquo;re managing.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine ls
NAME   ACTIVE   DRIVER       STATE     URL                         SWARM   DOCKER    ERRORS
one    -        virtualbox   Stopped                                       Unknown
&lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;   *        virtualbox   Running   tcp://192.168.99.100:2376           v1.12.1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We now see the list of machines and some basic information about them.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;state&lt;/code&gt; is helpful for seeing if the machine is currently running, and &lt;code&gt;active&lt;/code&gt; will let us know which machine our &lt;code&gt;docker&lt;/code&gt; command line tool is configured to connect to.&lt;/p&gt;

&lt;p&gt;We can start and stop the machines easily to avoid using too many resources on our own machine using similar commands and the name of the machine that we want to work with.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine stop &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
Stopping &lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;...
Machine &lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt; was stopped.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now if we look at the listing they should both have a state of &amp;ldquo;stopped&amp;rdquo;. Starting &lt;code&gt;test&lt;/code&gt; back up takes a similar command.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine start &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
Starting &lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt;...
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; Check network to re-create &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; needed...
&lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt; Waiting &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; an IP...
Machine &lt;span class=&#34;s2&#34;&gt;&amp;#34;test&amp;#34;&lt;/span&gt; was started.
Waiting &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the &lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt;docker-machine env&lt;span class=&#34;sb&#34;&gt;`&lt;/span&gt; command.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And we&amp;rsquo;re back to where we were originally.&lt;/p&gt;

&lt;p&gt;The last thing we&amp;rsquo;re going to look at is how to remove a machine if we no longer  need it. Removing them will be particularly useful in this case so that we&amp;rsquo;re not wasting hard drive space on our computers, but will be essential later on so we don&amp;rsquo;t pay for server that we no longer need.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker-machine rm &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
About to remove &lt;span class=&#34;nb&#34;&gt;test&lt;/span&gt;
Are you sure? &lt;span class=&#34;o&#34;&gt;(&lt;/span&gt;y/n&lt;span class=&#34;o&#34;&gt;)&lt;/span&gt;: y
Successfully removed test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Today we learned how to create Docker hosts, specifically local VMs using &lt;code&gt;docker-machine&lt;/code&gt;. After we created our VM we then went through some of the life-cycle operations that we can perform on the machine. These operations will be important as we start moving into using Docker on machines other than our development machines. I wanted to make sure that we have a good grasp on how Docker hosts work before we get into deployments with Docker.&lt;/p&gt;

&lt;p&gt;In the next tutorial we&amp;rsquo;re going to use &lt;code&gt;docker-machine&lt;/code&gt; to create a server on &lt;a href=&#34;https://m.do.co/c/3e5160725c43&#34;&gt;Digital Ocean&lt;/a&gt;, and deploy a Ruby on Rails application to it for the public to access.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learn Python – Lists and Tuples</title>
      <link>https://coderjourney.com/tutorials/python-lists-and-tuples/</link>
      <pubDate>Sun, 11 Sep 2016 17:26:58 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/tutorials/python-lists-and-tuples/</guid>
      <description>

&lt;p&gt;Continuing our series on Python, we&amp;rsquo;re going to look at how we can work with grouped data using two of the data structures in Python: Lists and Tuples.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/UiSEQPLh700&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to store data in Lists.&lt;/li&gt;
&lt;li&gt;Learn what a Tuple is and how to use it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Up to this point, we&amp;rsquo;ve only worked with individual values. Whether it&amp;rsquo;s been numbers or strings we&amp;rsquo;ve only worked with 1 or 2 of them at a time. For us to write programs that solve real problems we&amp;rsquo;ll &lt;strong&gt;probably&lt;/strong&gt; need to work with groups of data.&lt;/p&gt;

&lt;h2 id=&#34;the-primary-collection-list&#34;&gt;The Primary Collection: List&lt;/h2&gt;

&lt;p&gt;The main collection type that we&amp;rsquo;ll use while programming Python is the list. Let&amp;rsquo;s open up the REPL and see what they can do.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker run --rm -it python:3.5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lists are not limited to holding the same type, but it&amp;rsquo;s in your best interest to keep them the same. That being said, the following is a completely valid list:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mixed_list&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;mixed_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;2.5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3 id=&#34;reading-adding-and-editing-a-list&#34;&gt;Reading, Adding, and Editing a List&lt;/h3&gt;

&lt;p&gt;Whenever we create a list, it&amp;rsquo;s likely that we&amp;rsquo;ll want to access the information within the list at some point. Let&amp;rsquo;s first look at how we can access 1 item at a time:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Index a single element, indexes start at 0 and iterate up.&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Using an index that&amp;#39;s higher than the length of the list.&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;ne&#34;&gt;IndexError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;list&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;out&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;of&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;range&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Some languages don&amp;rsquo;t raise errors when you try to access an index that is out of range for an Array/List, but Python does, so be careful.&lt;/p&gt;

&lt;p&gt;Besides just accessing one item in a list, we can slice a list to give us a subset of the items. We saw the slice syntax briefly when learning how to reverse a string, but most of the time you&amp;rsquo;ll use this feature when working with lists.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Includes index 1, up to, but not including index 3.&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# From the beginning up to index 3.&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# From index 2 to the end (including the end).&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[::&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# From beginning to end, every other item&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now we have a better grasp on how to read from a list, but what if we want to add to it or change what&amp;rsquo;s in it? Adding to a list is easy enough, there&amp;rsquo;s a method for it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;append&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;len&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Get the length of the list&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;7&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our list will grow as we &lt;code&gt;append&lt;/code&gt; new data to it, but this will get a little tedious if we need to add many items to it. We were also able to see how long our list had become using the &lt;code&gt;len&lt;/code&gt; function. Thankfully, lists support the &lt;code&gt;+&lt;/code&gt; operation so we can insert multiple items at once. We&amp;rsquo;ll reset &lt;code&gt;my_list&lt;/code&gt; to equal &lt;code&gt;[1, 2, 3]&lt;/code&gt; just so it&amp;rsquo;s a little short for our examples.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that the plus operation returns a different list that contains all of the items, but it does not change the contents of our variable &lt;code&gt;my_list&lt;/code&gt;. If we want to store off this new combined list we would have to set assign the result to a variable.&lt;/p&gt;

&lt;p&gt;Sometimes you want to replace content within a list. The syntax for assigning values looks like a mix between reading from the list and assigning a variable.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Replacing a single value, at index 0.&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Replacing a slice&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[:]&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Notice that we were able to replace the entire list&amp;rsquo;s contents by creating a slice from beginning to end and assigning &lt;code&gt;[1]&lt;/code&gt; to it. When you are replacing a slice the lengths don&amp;rsquo;t need to be the same.&lt;/p&gt;

&lt;h2 id=&#34;removing-an-item-from-a-list&#34;&gt;Removing an Item from a List&lt;/h2&gt;

&lt;p&gt;We now know how to create, read from, and update lists, but we need to also know how to remove items from the list. We&amp;rsquo;ll use a few different ways to remove items, depending on what we&amp;rsquo;re trying to do. The first one is the method &lt;code&gt;pop&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Removes the last item in the list&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pop&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Given an argument removes item(s) at the given indexes&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_list&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can use &lt;code&gt;pop&lt;/code&gt; to remove elements at a specific position in the list, or by default it will remove the last item.&lt;/p&gt;

&lt;h2 id=&#34;tuples&#34;&gt;Tuples&lt;/h2&gt;

&lt;p&gt;Lists are flexible and can be changed, they&amp;rsquo;re what is called &amp;ldquo;mutable&amp;rdquo;. Tuples on the other hand will have the same contents and length from the time they are created; we can&amp;rsquo;t change them. We&amp;rsquo;ve seen tuples in action a few times before when we&amp;rsquo;ve used &lt;code&gt;print&lt;/code&gt;, here&amp;rsquo;s an example:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;There are &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; planets and &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;.&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;Pluto&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;There&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;are&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;planets&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Pluto&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;(8, &amp;quot;Pluto&amp;quot;)&lt;/code&gt; is the tuple. Tuples are similar to lists in that they are what&amp;rsquo;s known as a &amp;ldquo;sequence&amp;rdquo; in Python, but you&amp;rsquo;ll usually use them the data of different types unlike you normally will with a list. The data within a tuple will normally be accessed by indexing, whereas you&amp;rsquo;re more likely to iterate over a list.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Today, we took a look at two of the collection data types that we&amp;rsquo;ll use in Python. Lists are one of the most used things in all of programming so we&amp;rsquo;ll need those before we begin writing more complicated programs in Python.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learn about Python Variables and Control Flow</title>
      <link>https://coderjourney.com/python-variables-and-control-flow/</link>
      <pubDate>Sat, 03 Sep 2016 18:13:26 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/python-variables-and-control-flow/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to continue to our series on Python. We’re going to learn how to name data using variables, and how to make our programs behave differently based on the values in that are passed in.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/Av8vNCMSdoc&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Learn how to use variables to name data.&lt;/li&gt;
&lt;li&gt;Learn how to use if/else for control flow.&lt;/li&gt;
&lt;li&gt;Learn how to take user input from the command line in our scripts.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Today’s tutorial is going to take place almost exclusively in a script file, so have your favorite text editor handy and lets make sure we have a container created that we can run our script in.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker run --rm -it -v &lt;span class=&#34;nv&#34;&gt;$PWD&lt;/span&gt;:/usr/src/python -w /usr/src/python python:3.5 bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We’re going to create a script that will allow the user to input a string and it will output whether or not the string is a palindrome (a word or phrase that reads the same in both directions excluding spaces and punctuation, examples: “radar” or “nurses run”). Here are the steps that we’re going to take to accomplish this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Store user’s input into a variable, I’m going to call it “phrase”.&lt;/li&gt;
&lt;li&gt;Create another string by removing spaces from “phrase” so that we give the proper response for phrases like “nurses run”. We’ll call this one “sanitized_phrase”.&lt;/li&gt;
&lt;li&gt;Compare “sanitized_phrase” with “sanitized_phrase” backwards. If they are the same then output that the phrase was a palindrome, otherwise output that the phrase isn’t that exciting.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&#34;naming-data-with-variables&#34;&gt;Naming Data with Variables&lt;/h2&gt;

&lt;p&gt;Up to this point in our exploration of Python, we’ve run each line as though it wasn’t connected to any of the code around it, but today we’re going to learn to how to keep a piece of data around for awhile so that we can do change it and use it in comparisons before completing our program. Let’s look at how to create a variable in the Python REPL.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_var&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;This is my var&amp;#34;&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You’ll notice that it didn’t output anything because nothing was returned or written to the screen. If we enter &lt;code&gt;my_var&lt;/code&gt; by itself we can see the string we entered.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my_var&lt;/span&gt;
&lt;span class=&#34;s1&#34;&gt;&amp;#39;This is my var&amp;#39;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Anytime we use &lt;code&gt;my_var&lt;/code&gt; it will give us this value, until we set a different value for that variable.&lt;/p&gt;

&lt;h2 id=&#34;accepting-user-input&#34;&gt;Accepting User Input&lt;/h2&gt;

&lt;p&gt;Now to start our palindrome checker script, open up &lt;code&gt;palindrome.py&lt;/code&gt;. The first step in our process is to take in
user input so that we can see if it’s a palindrome. Let’s learn how to do do that now.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;palindrome.py&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Enter a phrase: &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Your phrase was &amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#39;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Before we talk about what we just wrote let’s run it:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;err&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;python&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;palindrome&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;py&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Enter&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;a&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;This&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;is&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;my&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Your&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;was&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;This is my phrase&amp;#39;&lt;/span&gt;
&lt;span class=&#34;err&#34;&gt;$&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our first line creates a prompt and waits for the user to hit the return key. Additionally, &lt;code&gt;input&lt;/code&gt; also returns the text that was entered before the return key was hit. We then echo that back out to the screen just to make sure that it worked.&lt;/p&gt;

&lt;h2 id=&#34;removing-spaces&#34;&gt;Removing Spaces&lt;/h2&gt;

&lt;p&gt;Up to this point we’ve only used functions that we pass data into, types have functions that are tied to them known as methods and we get to use some of those now. To remove the spaces from the string we’re going to use the method &lt;code&gt;replace&lt;/code&gt; the type string has. We will be replacing spaces with empty strings, which causes them to be removed.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;palindrome.py&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Enter a phrase: &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;sanitized_phrase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;The phrase without spaces &amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#39;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sanitized_phrase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;reversing-a-string&#34;&gt;Reversing a String&lt;/h2&gt;

&lt;p&gt;Reversing a string in Python is pretty interesting, but it’s not the most intuitive. Strings are essentially groups of characters and we can break them into smaller groups by slicing them. I’ll explain slices a little more when we talk about Arrays, but for now we’re going to go straight to reversing a string.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;palindrome.py&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Enter a phrase: &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;sanitized_phrase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sanitized_phrase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[::&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;])&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;[::-1]&lt;/code&gt; means we want the string starting from the beginning, going all the way to the end, but we want to step through them backwards (that’s the &lt;code&gt;-1&lt;/code&gt; in action).&lt;/p&gt;

&lt;h2 id=&#34;if-palindrome-then&#34;&gt;If palindrome then …&lt;/h2&gt;

&lt;p&gt;We’re to the final step of our first script. We have our &lt;code&gt;sanitized_phrase&lt;/code&gt; and we know how to reverse it, and now we just need to compare it to it’s reversed self. We’ll make our comparison with the &lt;code&gt;==&lt;/code&gt; operator, but that doesn’t get us 100% of the way to printing out different messages. Of that we need &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;else&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;palindrome.py&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;input&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Enter a phrase: &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;sanitized_phrase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;replace&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34; &amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sanitized_phrase&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sanitized_phrase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[::&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#39; is a palindrome!&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;
    &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;#39;&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#39; isn&amp;#39;t that exciting.&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;phrase&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A few things to note here:
1. &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;else&lt;/code&gt; both need to be followed by a &lt;code&gt;:&lt;/code&gt;
2. The code inside of each conditional branch needs to be indented 4 more spaces than the if/else.&lt;/p&gt;

&lt;p&gt;This is the first time that we’ve seen the whitespace dependency of Python. Indenting is how we separate code groups into different levels.&lt;/p&gt;

&lt;p&gt;If we run our script now and use a phrase like &lt;code&gt;nurses run&lt;/code&gt; we should see “‘nurses run’ is a palindrome!”. If we use a phrase like “bananas” then we’ll see “‘bananas’ isn’t that exciting.”&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Today we wrote our first more involved program. This script required us to use variables, explore the methods in Python, and use if/else to do different things based on the string that was input from outside of the program. This is just the beginning of our programming adventure, and I hope this has sparked your curiosity to write other little tools. Let me know what you’re building with what you’re learning.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learn Python – Booleans, Comparisons, and Logic</title>
      <link>https://coderjourney.com/learn-python-booleans-comparisons-and-logic/</link>
      <pubDate>Tue, 30 Aug 2016 11:14:07 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learn-python-booleans-comparisons-and-logic/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to continue to our series on Python. We&amp;rsquo;ll learn about Booleans and how to compare values.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/8CbMGy0sLtc&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Learn about Booleans and comparison operators.&lt;/li&gt;
&lt;li&gt;Learn how to compare 2 different values.&lt;/li&gt;
&lt;li&gt;Learn how to use logic operators&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We&amp;rsquo;re going to start today&amp;rsquo;s tutorial where we left off with last weeks. Go to the folder you are going to be using to follow along with the tutorial and run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;err&#34;&gt;$&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;docker&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;run&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;--&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;rm&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;it&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;python&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mf&#34;&gt;3.5&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;true-false-and-comparisons&#34;&gt;True, False, and Comparisons&lt;/h2&gt;

&lt;p&gt;Often times when writing programs we need to see if 2 items or equal or we need to take a different approach if something is larger than a specific value. To do this we need to be able to compare things. Let&amp;rsquo;s take a look at the most common
tools that we&amp;rsquo;ll use when making comparisons in our code.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;comparing number&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Equal to&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Not Equal to&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;!=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Less than&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Greater than&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Greater than or equal to&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Less than or equal to&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&amp;rsquo;ll notice that all of these comparisons give us either &lt;code&gt;True&lt;/code&gt; or &lt;code&gt;False&lt;/code&gt;, these are the boolean values in Python. &amp;ldquo;Boolean&amp;rdquo; values represent true and false from logic. Some languages use true and false all lowercase, but python uses the capitalized variation so you need to make sure that you always capitalize those words.&lt;/p&gt;

&lt;p&gt;We can compare more than just numbers, for instance &lt;code&gt;&amp;quot;a&amp;quot; == &amp;quot;a&amp;quot;&lt;/code&gt; would work just fine, but the two types that we&amp;rsquo;re comparing need to be able to compare with one another or be coerced from one type to another. For instance this is what we see if we try to compare a string to a number using greater than or less than:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;can&amp;rsquo;t compare&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Traceback&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;most&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;recent&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;call&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;
  &lt;span class=&#34;n&#34;&gt;File&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;&amp;lt;stdin&amp;gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;line&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;in&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;module&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&#34;ne&#34;&gt;TypeError&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;unorderable&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;types&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;str&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;logical-operators&#34;&gt;Logical Operators&lt;/h2&gt;

&lt;p&gt;Now that we have True and False we can also look at what are called the logical operators. These are keywords in python of &lt;code&gt;and&lt;/code&gt;, &lt;code&gt;or&lt;/code&gt;, and &lt;code&gt;not&lt;/code&gt;. Let&amp;rsquo;s look at them one at a time.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;and&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&amp;rsquo;ll notice that &lt;code&gt;1 and 0&lt;/code&gt; returns &lt;code&gt;0&lt;/code&gt; and that&amp;rsquo;s because &lt;code&gt;0&lt;/code&gt; is a falsy value. &lt;code&gt;and&lt;/code&gt; will return the first falsy object that is comes across because it&amp;rsquo;s impossible for them both to be true if one is false. If both are truthy then it returns the item on the right.&lt;/p&gt;

&lt;p&gt;If we never need to know whether a value is true or false we can pass it into the &lt;code&gt;bool&lt;/code&gt; function like so:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;bool&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Let&amp;rsquo;s continue looking at the logical operators using the &lt;code&gt;or&lt;/code&gt; keyword. I&amp;rsquo;m going to go back to using &lt;code&gt;True&lt;/code&gt; and &lt;code&gt;False&lt;/code&gt; to make these operations easier to
read.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;or&lt;/code&gt; operator return the first truthy value that it comes across going from left to right. If neither of the items is truthy then it returns the item on the right side.&lt;/p&gt;

&lt;p&gt;Only one more logical operator to go in the form of &lt;code&gt;not&lt;/code&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;0&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;bp&#34;&gt;False&lt;/span&gt;
&lt;span class=&#34;bp&#34;&gt;True&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the same way the &lt;code&gt;bool&lt;/code&gt; function returns the truthiness of a value, &lt;code&gt;not&lt;/code&gt; returns the opposite.&lt;/p&gt;

&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Today we took a look what it looks like to compare values in Python using comparison and logical operators, learning along the way how the truth works in python. Comparisons will become very important as we start structuring our code to do things based on inputs that will vary. The logical operators might not seem immediately useful right now, but trust me, we&amp;rsquo;ll use them a lot.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learn Python – Strings, Numbers, and the REPL</title>
      <link>https://coderjourney.com/learn-python-part-1/</link>
      <pubDate>Sun, 28 Aug 2016 22:22:21 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learn-python-part-1/</guid>
      <description>

&lt;p&gt;Today we&amp;rsquo;re going to start our first series on a programming language, and we&amp;rsquo;ll be digging into Python. Python is a wonderful language to learn and to start with because it is used in so many different fields, from web programming, to data-science, all the way to scripting animations. We&amp;rsquo;re going to start from the beginning, assuming no prior knowledge of programming and see where this journey takes us. In today&amp;rsquo;s episode specifically we&amp;rsquo;re going to become familiar with the a few basic types in python and how we can run our code as we&amp;rsquo;re developing it.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/QgaPZG_OzW0&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;h2 id=&#34;goal-for-this-tutorial&#34;&gt;Goal for this Tutorial:&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Become comfortable in the REPL for trying out code in Python.&lt;/li&gt;
&lt;li&gt;Create our first python script and learn to run it from the command line.&lt;/li&gt;
&lt;li&gt;Investigate a few of the basic types in Python (strings, comments, and numbers).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For this tutorial we&amp;rsquo;re going to use the &lt;a href=&#34;https://hub.docker.com/_/python&#34;&gt;official Python image&lt;/a&gt; from Docker Hub so that everyone is at the same starting point. If you&amp;rsquo;ve never used Docker please watch my series on using &lt;a href=&#34;https://www.youtube.com/c/coderjourney/docker&#34;&gt;Docker for Development&lt;/a&gt;. To get the image that we&amp;rsquo;ll be using you can run:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker pull python:3.5&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;After you&amp;rsquo;ve downloaded the image start a container running bash so that we can run commands as though we were running python on our machine:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker run --rm -it python:3.5 bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;getting-started-with-python&#34;&gt;Getting Started with Python&lt;/h2&gt;

&lt;p&gt;The first thing we&amp;rsquo;re going to do is run the &lt;code&gt;python&lt;/code&gt; command from the command line:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ python&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You should see something like this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;n&#34;&gt;Python&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;3.5&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;Aug&lt;/span&gt;  &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;2016&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;20&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;58&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;38&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;GCC&lt;/span&gt; &lt;span class=&#34;mf&#34;&gt;4.9&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;on&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;linux&lt;/span&gt;
&lt;span class=&#34;n&#34;&gt;Type&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;help&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;copyright&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;credits&amp;#34;&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;or&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;license&amp;#34;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;for&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;more&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;information&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This puts us at a prompt known as a REPL, which stands for Read, Evaluate, Print, Loop. We can type lines of Python code here and they will be run write away. REPLs are a great place to play with a language and learn what works and what doesn&amp;rsquo;t without worrying about setting up a script and running the script.&lt;/p&gt;

&lt;p&gt;The first thing every programmer does in any programming language is write his/her &amp;ldquo;Hello World&amp;rdquo; program. This program prints the words &amp;ldquo;Hello World!&amp;rdquo; to the screen and depending on the language can take quite a few lines of code, but that&amp;rsquo;s not the case in Python. Let&amp;rsquo;s write our Hello World now:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;Hello World!&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You&amp;rsquo;ll notices that right underneath the line with three greater than symbols it now says &amp;ldquo;Hello World!&amp;rdquo; because we printed it out. Breaking this down we needed to use the built-in function &lt;code&gt;print&lt;/code&gt; to get our words the print to the screen and we passed in the String &amp;ldquo;Hello World!&amp;rdquo;. A string is anything within either single or double quotes in Python (and more programming languages). We&amp;rsquo;ll be using these a lot, and a good way to think of strings is that they are used if we want to represent words, phrases, or numbers with specific formatting, for instance currency &amp;ldquo;$1.00&amp;rdquo;.&lt;/p&gt;

&lt;h2 id=&#34;introducing-numbers-and-math&#34;&gt;Introducing Numbers and Math&lt;/h2&gt;

&lt;p&gt;Beyond printing our strings, one of the things that we&amp;rsquo;ll use a lot in Python are numbers. It is pretty common to want to do Math and numbers for the most part work as expected. There are 2 main types of numbers that we&amp;rsquo;ll work with in Python: Integers and Floats.&lt;/p&gt;

&lt;p&gt;Examples of Integers would be the numbers 1 or -12.
Examples of Floats would be the numbers 2.5 or -0.5. Floats are the type that we use to represent decimal numbers.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s do some math using these new number types:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Addition&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;10&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Subtraction&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;6&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Division, notice that it returns a float instead of an int&lt;/span&gt;
&lt;span class=&#34;mf&#34;&gt;1.6666666666666667&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;//&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Floor division, always returns an int&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Multiplication&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;27&lt;/span&gt;
&lt;span class=&#34;o&#34;&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;3&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# Modulo division, returns an int representing the remainder&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;creating-a-python-script&#34;&gt;Creating a python script&lt;/h2&gt;

&lt;p&gt;We now know how to interact with the Python REPL and work with strings and number types. The last thing we&amp;rsquo;re going to look at is how to put our code in a script so that we can work with it over type and run more than one line at a time.&lt;/p&gt;

&lt;p&gt;For this we&amp;rsquo;re going to need to stop our container so that we can share through our local directory as a volume to allow us to work with our python script in our text editor. Exiting the REPL requires either hitting Ctrl+d or using the function &lt;code&gt;exit()&lt;/code&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ docker run --rm -it -v &lt;span class=&#34;nv&#34;&gt;$PWD&lt;/span&gt;:/usr/src/ -w /usr/src python bash&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;-w&lt;/code&gt; flag is being used here so that as soon as we&amp;rsquo;re in the container we&amp;rsquo;re already in the proper directory to see our source code.&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s open up a new file in our text editor called &lt;code&gt;planets.py&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;hello.py&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;+&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;
&lt;span class=&#34;mi&#34;&gt;5&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;4&lt;/span&gt;

&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;There are &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; planets&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;9&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Save the file and then from within your running container run&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;$ python planets.py
There are &lt;span class=&#34;m&#34;&gt;9&lt;/span&gt; planets&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Our first 2 lines did the math behind the seen and they returned &lt;code&gt;1&lt;/code&gt; and &lt;code&gt;1.2&lt;/code&gt; respectively, but we didn&amp;rsquo;t tell python to print them so we never saw them. on our 4th line we joined our strings and numbers together by using what&amp;rsquo;s called a format string. The &lt;code&gt;%s&lt;/code&gt; is replaced with what follows the &lt;code&gt;%&lt;/code&gt; after the string. We could put multiple values in the string also, but we would need to group the values that we want to put in the string together using parenthesis and commas.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s adjust this since I really don&amp;rsquo;t know what Pluto is at the moment.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;planets.py&lt;/em&gt;&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;k&#34;&gt;print&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;There are &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt; planets, plus &lt;/span&gt;&lt;span class=&#34;si&#34;&gt;%s&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;%&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;pluto&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id=&#34;recap&#34;&gt;Recap&lt;/h2&gt;

&lt;p&gt;Today we learned how to use the Python REPL, wrote our first Python script, and learned about strings and numbers. This is a good first step in our Coder Journey. In the next episode we&amp;rsquo;ll look at how we can store information in variables, group pieces of data together in lists, and package up our code to run it again and again using functions.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Learn to Use Docker for Development</title>
      <link>https://coderjourney.com/docker-for-development/</link>
      <pubDate>Fri, 12 Aug 2016 11:36:40 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/docker-for-development/</guid>
      <description>

&lt;p&gt;In this tutorial, we&amp;rsquo;re going to dig into how we can use Docker for development. Our example will show the development of a Rails application without ever installing Rails on our machine. The process we&amp;rsquo;re going through today will make you more familiar with how you can use containers in creative ways. In the second part of the tutorial, we will take a look at layering another tool, docker-compose, into the mix to make our development environment even more enjoyable to work with.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/NEdDa3Zqu7s&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;



&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/vPuhdkx-jUY&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;p&gt;Creating our setup using Docker wasn&amp;rsquo;t the simplest thing possible, but it is repeatable. In the next tutorial, we&amp;rsquo;ll go through how to use docker-compose to take the hassle out of creating, starting, and connecting our containers for development.&lt;/p&gt;

&lt;h2 id=&#34;resources-for-using-docker-for-development&#34;&gt;Resources for Using Docker for Development&lt;/h2&gt;

&lt;p&gt;You should continue looking into the topics mentioned in this tutorial by reading further. Here are the links that I suggest you check out to dig digger into what we did today.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/_/ruby/&#34;&gt;Official Ruby Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/_/postgres/&#34;&gt;Official Postgres Image&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/tutorials/dockervolumes/&#34;&gt;Docker Volumes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://docs.docker.com/engine/userguide/networking/dockernetworks/&#34;&gt;Docker Networking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://guides.rubyonrails.org/getting_started.html&#34;&gt;Rails Getting Started Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>What is Docker?</title>
      <link>https://coderjourney.com/what-is-docker/</link>
      <pubDate>Mon, 08 Aug 2016 17:12:50 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/what-is-docker/</guid>
      <description>&lt;p&gt;Docker is a tool for working with Linux containers, but knowing that doesn&amp;rsquo;t make it obvious why that makes it useful. Let&amp;rsquo;s look at what it is, what it isn&amp;rsquo;t, and why it might be useful for you.&lt;/p&gt;


&lt;div style=&#34;position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;&#34;&gt;
  &lt;iframe src=&#34;//www.youtube-nocookie.com/embed/RyxXe5mbzlU&#34; style=&#34;position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;&#34; allowfullscreen title=&#34;YouTube Video&#34;&gt;&lt;/iframe&gt;
&lt;/div&gt;


&lt;p&gt;We&amp;rsquo;ll be digging into using Docker for development, deployment, testing, and orchestration in the future. The first video utilizing Docker has already been released, &lt;a href=&#34;https://coderjourney.com/learning-docker-15-minutes/&#34;&gt;learn how to get started&lt;/a&gt;.&lt;/p&gt;
</description>
    </item>
    
    <item>
      <title>Begin Learning Docker in 15 Minutes</title>
      <link>https://coderjourney.com/learning-docker-15-minutes/</link>
      <pubDate>Sat, 30 Jul 2016 20:00:37 +0000</pubDate>
      <author>keith@coderjourney.com (Keith Thompson)</author>
      <guid>https://coderjourney.com/learning-docker-15-minutes/</guid>
      <description>

&lt;p&gt;Learning Docker is going to be important in the next few years, so that&amp;rsquo;s what we&amp;rsquo;re going to do. In this first episode, we&amp;rsquo;re going to get up and running with Docker so that we have a little exposure to images &amp;amp; containers. This is a pretty weird place to start, but it will save a lot of time down the road by not needing to cover initial set up for different languages/environments over and over again.&lt;/p&gt;

&lt;div class=&#34;g-ytsubscribe&#34; data-channelid=&#34;UCwgYv9lmioF0uR7dnsINFKw&#34; data-layout=&#34;default&#34; data-count=&#34;default&#34;&gt;
&lt;/div&gt;

&lt;h2 id=&#34;resources-for-learning-docker&#34;&gt;Resources for Learning Docker&lt;/h2&gt;

&lt;p&gt;Here&amp;rsquo;s a list of the tools that we interacted with during this tutorial. Docker is very well documented, so feel free to poke around in some of the associated articles when you go to download Docker.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.docker.com/products/docker&#34;&gt;Docker for Mac/Windows&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://hub.docker.com/_/ubuntu/&#34;&gt;The official Ubuntu Image&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this short introduction into using Docker, we now have a stepping off point so that we can start using Docker for development and also for packaging and deploying code.&lt;/p&gt;
</description>
    </item>
    
  </channel>
</rss>
