<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>articles on luis angel ortega</title><link>https://luisangel.me/categories/articles/</link><description>Recent Articles on luis angel ortega</description><generator>Hugo</generator><language>en-US</language><managingEditor>hey@luisangel.me (Luis Angel Ortega)</managingEditor><webMaster>hey@luisangel.me (Luis Angel Ortega)</webMaster><copyright>2025 Luis Angel Ortega Holguin All rights reserved</copyright><lastBuildDate>Thu, 26 Jun 2025 17:00:00 +0000</lastBuildDate><atom:link href="https://luisangel.me/categories/articles/index.xml" rel="self" type="application/rss+xml"/><item><title>Who are we digitalizing education for? An urgent call for accessibility</title><link>https://luisangel.me/post/2025/06/26/digitalizing-education/</link><pubDate>Thu, 26 Jun 2025 17:00:00 +0000</pubDate><author>hey@luisangel.me (Luis Angel Ortega)</author><guid>https://luisangel.me/post/2025/06/26/digitalizing-education/</guid><description>&lt;p>For more than two decades, talking about digital transformation in education has become almost mandatory. Investments are made in platforms, new methodologies are promoted, and technological advances in classrooms are celebrated. But there&amp;rsquo;s a question that is rarely asked clearly: &lt;strong>Who are we digitalizing for?&lt;/strong>&lt;/p>
&lt;p>The enthusiasm for innovation has left out an essential element: accessibility. It&amp;rsquo;s not just about whether a person has internet, but whether they can use, understand, and benefit from the available educational tools from their context. And in Mexico, that context is usually a mid-range cell phone, an intermittent mobile connection, and the absence of a computer at home.&lt;/p>
&lt;p>According to INEGI data (2024), &lt;strong>more than 97% of internet users in the country connect from their cell phone&lt;/strong>, while &lt;strong>less than 44% of households have a computer&lt;/strong>. Additionally, the average mobile connection speed —25 Mbps— is barely sufficient for basic browsing, not for heavy platforms full of animations, embedded videos, and unnecessary visual load.&lt;/p>
&lt;p>Despite this reality, we continue to promote platforms that are not designed for that majority. Tools like Genially, Canva, or even Moodle with heavy themes become an obstacle for many students. Not due to lack of interest, but because they simply &lt;strong>don&amp;rsquo;t load&lt;/strong> or overwhelm the device. The message is clear: if you don&amp;rsquo;t have the right hardware or connection, you&amp;rsquo;re out.&lt;/p>
&lt;p>This isn&amp;rsquo;t about rejecting technology. It&amp;rsquo;s about demanding that it be designed from the perspective of the real user and not from the desktop of the designer or decision-maker. An educational platform that doesn&amp;rsquo;t work offline, that doesn&amp;rsquo;t adapt to small screens, or that requires expensive equipment &lt;strong>is not designed to include, but to exclude&lt;/strong>.&lt;/p>
&lt;p>Teachers, administrators, and developers must understand that digital transformation is not synonymous with sophistication or aesthetics. It&amp;rsquo;s an opportunity to do things better, to close gaps, not to open new ones. Betting on lightweight sites, responsive design, open standards, and free software is not just a technical decision: &lt;strong>it&amp;rsquo;s an ethical and pedagogical stance&lt;/strong>.&lt;/p>
&lt;p>In a country with such social and technological diversity, it&amp;rsquo;s not enough to offer access. We must think about real, daily, situated use. As long as we don&amp;rsquo;t take digital accessibility seriously, any attempt at inclusion will be just an empty promise. And the gap, far from closing, will continue to grow&amp;hellip; loading slowly.&lt;/p>
&lt;hr>
&lt;h3 id="references">References&lt;/h3>
&lt;ul>
&lt;li>
&lt;p>Covarrubias Hernández, L. Y. (2021). &lt;em>Distance education: transformation of learning&lt;/em>. &lt;em>Telos: Journal of Interdisciplinary Studies in Social Sciences&lt;/em>. Retrieved from Gale database: Academic Report &lt;a href="https://doi.org/10.36390/telos231.12">https://doi.org/10.36390/telos231.12&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Fernández-Enguita, M. (2023). &lt;em>The fifth wave: the digital transformation of learning, education and school&lt;/em>. Ediciones Morata, S. L. Retrieved from eLibro Cátedra database &lt;a href="https://elibro.net/es/lc/bibliotecauveg/titulos/232678">https://elibro.net/es/lc/bibliotecauveg/titulos/232678&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>National Institute of Statistics and Geography. (2025, May 6). &lt;em>National Survey on Availability and Use of Information Technologies in Households (ENDUTIH) 2024: Main results&lt;/em>. &lt;a href="https://www.inegi.org.mx/programas/endutih/2024/">https://www.inegi.org.mx/programas/endutih/2024/&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>Speedtest by Ookla. (2024). &lt;em>Speedtest Global Index – Mexico&lt;/em>. &lt;a href="https://www.speedtest.net/global-index/mexico">https://www.speedtest.net/global-index/mexico&lt;/a>&lt;/p>
&lt;/li>
&lt;li>
&lt;p>The Competitive Intelligence Unit. (2024). &lt;em>Smartphone market in Mexico, Q1-2024&lt;/em>. &lt;a href="https://www.theciu.com/publicaciones-analisis/2024/03/smartphones-en-mexico-1T-2024">https://www.theciu.com/publicaciones-analisis/2024/03/smartphones-en-mexico-1T-2024&lt;/a>&lt;/p>
&lt;/li>
&lt;/ul>
&lt;blockquote>
&lt;p>Originally published on &lt;a href="https://eltelar.xyz/blog/para-quien-estamos-digitalizando-la-educacion/">El telar&lt;/a> blog&lt;/p>
&lt;/blockquote></description></item><item><title>Dropdowns and Toggles with Pure CSS</title><link>https://luisangel.me/post/2022/11/05/dropdowns-and-toggles-with-css/</link><pubDate>Sat, 05 Nov 2022 11:53:11 -0500</pubDate><author>hey@luisangel.me (Luis Angel Ortega)</author><guid>https://luisangel.me/post/2022/11/05/dropdowns-and-toggles-with-css/</guid><description>&lt;p>We could imagine the technologies of the platform on which I work, &lt;a href="https://www.joinbuildit.com/">Build It&lt;/a>, as a dish; where Ruby on Rails is our main dish but is accompanied by a good portion of JavaScript through &lt;a href="https://stimulus.hotwired.dev/">Stimulus JS&lt;/a>, and while this brings the functionality and that magical feeling of a single page application (SPA), there are things we want to keep simple instead of using a sledgehammer to kill an ant, as a university professor used to say. Therefore, we decided to take a page from &lt;a href="https://apple.com/mx">Apple&lt;/a> when handling dropdown menus or dropdowns and do it through pure CSS and HTML; without requiring a line of JavaScript.&lt;/p>
&lt;h2 id="the-pillars">The Pillars&lt;/h2>
&lt;p>Our two pillars in the view will be &lt;code>&amp;lt;input&amp;gt;&lt;/code> elements of checkbox type and &lt;code>&amp;lt;label&amp;gt;&lt;/code> tags. We will form our basic skeleton as follows:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#ca9ee6">input&lt;/span> &lt;span style="color:#8caaee">id&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>&lt;span style="color:#a6d189">&amp;#34;toggle&amp;#34;&lt;/span> &lt;span style="color:#8caaee">type&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>&lt;span style="color:#a6d189">&amp;#34;checkbox&amp;#34;&lt;/span>&amp;gt;&amp;lt;/&lt;span style="color:#ca9ee6">input&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#ca9ee6">label&lt;/span> &lt;span style="color:#8caaee">for&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>&lt;span style="color:#a6d189">&amp;#34;toggle&amp;#34;&lt;/span>&amp;gt;&amp;lt;/&lt;span style="color:#ca9ee6">label&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>We will be using the checked property of checkbox-type inputs to control the content we show and when we show it. For this, we will be relying on the &lt;code>&amp;lt;label&amp;gt;&lt;/code> element since by linking it through its &lt;code>for&lt;/code> property it will also be affected by the class change when the checked property of our checkbox is present.&lt;/p>
&lt;p>All our code will really be inside &lt;code>&amp;lt;label&amp;gt;&lt;/code> in two sections: container and toggle as shown below.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-html" data-lang="html">&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#ca9ee6">input&lt;/span> &lt;span style="color:#8caaee">id&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>&lt;span style="color:#a6d189">&amp;#34;toggle&amp;#34;&lt;/span> &lt;span style="color:#8caaee">type&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>&lt;span style="color:#a6d189">&amp;#34;checkbox&amp;#34;&lt;/span>&amp;gt;&amp;lt;/&lt;span style="color:#ca9ee6">input&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;&lt;span style="color:#ca9ee6">label&lt;/span> &lt;span style="color:#8caaee">for&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>&lt;span style="color:#a6d189">&amp;#34;toggle&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#ca9ee6">div&lt;/span> &lt;span style="color:#8caaee">class&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>&lt;span style="color:#a6d189">&amp;#34;toggle&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#737994;font-style:italic">&amp;lt;!-- The element with which the user will interact --&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#ca9ee6">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#ca9ee6">div&lt;/span> &lt;span style="color:#8caaee">class&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>&lt;span style="color:#a6d189">&amp;#34;container&amp;#34;&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#737994;font-style:italic">&amp;lt;!-- What we want to show--&amp;gt;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#ca9ee6">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&amp;lt;/&lt;span style="color:#ca9ee6">label&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;h2 id="the-magic">The Magic&lt;/h2>
&lt;p>Now that we have our HTML skeleton ready, it&amp;rsquo;s time to add the CSS that will give our component the magical touch:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-css" data-lang="css">&lt;span style="display:flex;">&lt;span>#&lt;span style="color:#ef9f76">toggle&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">display&lt;/span>: &lt;span style="color:#ef9f76">none&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>.&lt;span style="color:#e5c890">container&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">display&lt;/span>: &lt;span style="color:#ef9f76">none&lt;/span>;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>#&lt;span style="color:#ef9f76">toggle&lt;/span>:&lt;span style="color:#8caaee;font-weight:bold">checked&lt;/span> &lt;span style="color:#99d1db;font-weight:bold">+&lt;/span> &lt;span style="color:#ca9ee6">label&lt;/span> .&lt;span style="color:#e5c890">container&lt;/span> { 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">display&lt;/span>: &lt;span style="color:#ef9f76">inherit&lt;/span>; 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Our input with the toggle id will never be shown so that we do not have the checkbox present on our page, what we will show and with which the user interacts is what is inside our div with toggle class. Once they click on our toggle, the input will have the value of checked and with &lt;code>#toggle:checked+label&lt;/code> we affect the style of our &lt;code>&amp;lt;label&amp;gt;&lt;/code> to obtain a result like the following&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/dropdowns-toggle-css-1.gif" alt="Demo 1">&lt;/p>
&lt;p>And with a little more style (courtesy of Thulio Philipe) we can have results like this&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/dropdowns-toggle-css-2.gif" alt="Demo 2">&lt;/p>
&lt;p>Or as the examples we have inside Build It&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/dropdowns-toggle-css-3.gif" alt="Demo 3">&lt;/p>
&lt;p>A small popover that is always present, giving vital information to the user&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/dropdowns-toggle-css-4.gif" alt="Demo 4">&lt;/p>
&lt;p>Or a filter menu that can be shown easily.&lt;/p>
&lt;p>As we can see, modern CSS allows us to make interactive pages without the need for a script for it; giving us a new solution to a problem with endless ways to solve it, so it will be necessary to consider the needs of the project and what is most suitable.&lt;/p>
&lt;p>Finally, I leave you &lt;a href="https://github.com/LinkSake/toggle-dropdown-css">a repository&lt;/a> with a couple of examples seen in this article for future reference and I invite you to visit &lt;a href="https://www.joinbuildit.com/early_access/client">the platform&lt;/a> and especially &lt;a href="https://www.joinbuildit.com/u/luis-ortega-160">my profile&lt;/a>, where we can connect for future projects.&lt;/p></description></item><item><title>Thinking Outside the Box an Online Resume With Docz</title><link>https://luisangel.me/post/2021/10/21/thinking-outside-the-box-an-online-resume-with-docz/</link><pubDate>Thu, 21 Oct 2021 15:32:45 -0500</pubDate><author>hey@luisangel.me (Luis Angel Ortega)</author><guid>https://luisangel.me/post/2021/10/21/thinking-outside-the-box-an-online-resume-with-docz/</guid><description>&lt;p>One of the best traits of humankind is its curiosity. It is so human that in honor of it we named a Mars rover &amp;ldquo;Curiosity&amp;rdquo; in 2003.&lt;/p>
&lt;p>Talking about curiosity in the developer world, open source projects top the list, since by nature they invite us to experiment, modify and share what else we can do with them. This is why I propose to think a little outside the box with &lt;a href="https://www.docz.site/">Docz&lt;/a> - a software documentation tool that is completely open source.&lt;/p>
&lt;h2 id="what-is-docz">What is Docz?&lt;/h2>
&lt;p>Docz is a &lt;a href="https://www.gatsbyjs.com/">Gatsby-based&lt;/a> project that simplifies the process of documenting other projects without worrying about configuration, speed and support.&lt;/p>
&lt;p>It provides a library that allows you to write MDX pages instead of HTML or JSX files, handles the routing and provides plugins for all the other needs that you may have. All of this results on projects anyone can contribute to!&lt;/p>
&lt;p>Is this simplicity and friendliness that makes Docz a great option for more than just docs.&lt;/p>
&lt;h2 id="creating-our-docz-project">Creating our Docz project&lt;/h2>
&lt;p>Before we can jump into Docz, there are some prerequisites that you will need have in order to create the project:&lt;/p>
&lt;ul>
&lt;li>&lt;a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#overview">NodeJS&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://yarnpkg.com/getting-started/install">Yarn&lt;/a> or &lt;a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#overview">npm&lt;/a>&lt;/li>
&lt;/ul>
&lt;p>Now that you have the prerequisites, let’s start by creating a new React app with &lt;code>create-react-app&lt;/code> (CRA)&lt;/p>
&lt;p>Go to your terminal and run:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>npx create-react-app my-resume
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>If you don’t have CRA installed, npm will ask you if it’s okay to install &lt;code>create-react-app&lt;/code> type &lt;code>y&lt;/code> to continue and let CRA create the new project.&lt;/p>
&lt;blockquote>
&lt;p>We are using the command &lt;code>npx&lt;/code> instead of &lt;code>npm&lt;/code> since we want to execute a package, not install it to a project. You can read more about it &lt;a href="https://stackoverflow.com/questions/50605219/difference-between-npx-and-npm">here&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;p>Now lets move to the directory of our project and install Docz.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#99d1db">cd&lt;/span> my-resume
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>yarn add docz &lt;span style="color:#737994;font-style:italic"># or npm install docz&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Then let’s remove everything that CRA created for us inside the &lt;code>src&lt;/code> folder, since we don’t need it.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>rm src/*
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Also, it is a good idea to add to the .gitignore the .docz folder since we only needed for development.&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-.gitignore" data-lang=".gitignore"># .gitignore

# Docz generated files
.docz/
&lt;/code>&lt;/pre>&lt;p>Let’s go and create a file named &lt;code>index.mdx&lt;/code> and a &lt;em>hello world&lt;/em> header in the following way.&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-mdx" data-lang="mdx">&amp;lt;!-- src/index.mdx --&amp;gt;

---
name: Hello World
route: /
---

# Hello world from Docz!
&lt;/code>&lt;/pre>&lt;p>And it’s time to run our development server to see what we have just created.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>yarn docz dev &lt;span style="color:#737994;font-style:italic"># or npm run docz dev&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>If you get an error &lt;a href="https://github.com/gatsbyjs/gatsby/issues/19922">ERROR #98123&lt;/a> while trying to run the development server, just delete your &lt;code>yarn.lock&lt;/code> or &lt;code>package-json.lock&lt;/code> and the &lt;code>node_modules&lt;/code> folder and install the dependencies again.&lt;/p>
&lt;/blockquote>
&lt;p>&lt;em>Et voila!&lt;/em> We have successfully created our Docz project.&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-1.png" alt="Hello from Docz">&lt;/p>
&lt;blockquote>
&lt;p>Now is a good time to commit your files!&lt;/p>
&lt;/blockquote>
&lt;h2 id="your-time-to-shine">Your time to shine&lt;/h2>
&lt;p>Before we start adding more pages, let’s create a configuration file named &lt;code>doczrc.js&lt;/code> on the root of our project. This will help us to set some meta tags easily, but it manages &lt;a href="https://www.docz.site/docs/project-configuration">all the configuration&lt;/a> of our project.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#737994;font-style:italic">// doczrc.js
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#737994;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">export&lt;/span> &lt;span style="color:#ca9ee6">default&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> title&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#34;Luis Angel Ortega&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> description&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#34;Hello, I&amp;#39;m Luis Angel and this is my resume made with Docz!&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ignore&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> [&lt;span style="color:#a6d189">&amp;#34;README.md&amp;#34;&lt;/span>]
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The title key will set the suffix for our &lt;a href="https://www.w3schools.com/tags/tag_title.asp">title tag&lt;/a> and it will change the text on the top left corner of our project, since it’s an online resume I recommend using your name in this field.&lt;/p>
&lt;p>Then, the description key that we added will modify the &lt;a href="https://moz.com/learn/seo/meta-description">meta description tag&lt;/a> on our webpage to display it when it’s looked up or shared online.&lt;/p>
&lt;p>The last key will tell Docz to ignore some files and don’t display them on the webpage, as is in this case with the README file.&lt;/p>
&lt;p>Now let’s add more pages! I’ll add a contact page with my socials and resume one in the following way&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-mdx" data-lang="mdx">&amp;lt;!-- src/contact.mdx --&amp;gt;

---
name: Contact
route: /contact
---

# Contact me! 🗣

---

Let&amp;#39;s talk! You can find me on these platforms:

- ✉️ [Email](mailto:hey@luisangelme)
- 🤝 [LinkedIn](https://www.linkedin.com/in/luisangel-ortega)
- 🐙 [GitHub](https://github.com/LinkSake)
- 🐦 [Twitter](https://twitter.com/LinkSake)
- 🌐 [Website](https://luisangel.me)
&lt;/code>&lt;/pre>&lt;pre tabindex="0">&lt;code class="language-mdx" data-lang="mdx">&amp;lt;!-- src/resume.mdx --&amp;gt;

---
name: Resume
route: /resume
---

# Resume 💼

---

## Work Experience

&amp;lt;details&amp;gt;
 &amp;lt;summary&amp;gt;Software Developer. &amp;lt;a href=&amp;#39;growthconstant.co&amp;#39; target=&amp;#39;_blank&amp;#39;&amp;gt;Growth Constant&amp;lt;/a&amp;gt;, (Mar. 2021 - Currently)&amp;lt;/summary&amp;gt;
 &amp;lt;div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt; Full stack developer (Ruby on Rails) and copywriter for the first project of the start-up: &amp;lt;a href=&amp;#39;virtualdash.co&amp;#39; target=&amp;#39;_blank&amp;#39;&amp;gt;Virtual Dash &amp;lt;/a&amp;gt;.&amp;lt;/li&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/details&amp;gt;

&amp;lt;details&amp;gt;
 &amp;lt;summary&amp;gt;Backend Developer Intern. &amp;lt;a href=&amp;#39;facturasamurai.com&amp;#39; target=&amp;#39;_blank&amp;#39;&amp;gt;Factura Samurai&amp;lt;/a&amp;gt;, (Aug. - Dec. 2020)&amp;lt;/summary&amp;gt;
 &amp;lt;div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt; Implemented the user authentication on the Elixir API. &amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt; Learn and developed serverless services (Cloudflare Workers) with TypeScript. &amp;lt;/li&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/details&amp;gt;

&amp;lt;details&amp;gt;
 &amp;lt;summary&amp;gt;Full Stack Web Developer. &amp;lt;a href=&amp;#39;biobot.farm&amp;#39; target=&amp;#39;_blank&amp;#39;&amp;gt;biobot.farm&amp;lt;/a&amp;gt;, (Aug. 2019 - Jun. 2020)&amp;lt;/summary&amp;gt;
 &amp;lt;div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt; Successfully launched a new service (web application) that was developed form scratch while learning React. &amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt; Documented the web application and taught a colleague to mantener said application. &amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt; Improved speed, functionality and readability of a Python API and micro-services. &amp;lt;/li&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/details&amp;gt;

## Education

&amp;lt;details&amp;gt;
 &amp;lt;summary&amp;gt;Bachelor&amp;#39;s Degree in Information Technologies and Telecomunications. &amp;lt;a href=&amp;#39;ulsachihuahua.edu.mx/site&amp;#39; target=&amp;#39;_blank&amp;#39;&amp;gt;Universidad La Salle Chihuahua&amp;lt;/a&amp;gt;, (Aug. 2016 - Dic. 2020)&amp;lt;/summary&amp;gt;
 &amp;lt;div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt; Degree on engineering on information and telecommunication with specialization on mobile development. &amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt; Academic exchange semester at La Salle Ramon Llull University (Barcelona, Spain) from January to June 2019 with the Computer Engineering degree. &amp;lt;/li&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/details&amp;gt;

## Skills

&amp;lt;details&amp;gt;
 &amp;lt;summary&amp;gt; Languages &amp;lt;/summary&amp;gt;
 &amp;lt;div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt;Spanish: Native&amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt;English: Advanced (TOFEL ITP: 627)&amp;lt;/li&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/details&amp;gt;
&amp;lt;details&amp;gt;
&amp;lt;summary&amp;gt; Tech &amp;lt;/summary&amp;gt;
 &amp;lt;div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt; &amp;lt;b&amp;gt; Professional level &amp;lt;/b&amp;gt; &amp;lt;/li&amp;gt;
 &amp;lt;div div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt;JavaScript (Node, React, Next)&amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt;Ruby (Rails)&amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt;SQL (MySQL, PostgreSQL)&amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt;Version manager (Git)&amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt;HTML &amp;amp; CSS&amp;lt;/li&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt; &amp;lt;b&amp;gt; Novice Level &amp;lt;/b&amp;gt; &amp;lt;/li&amp;gt;
 &amp;lt;div style={{marginLeft: &amp;#39;1em&amp;#39;}}&amp;gt;
 &amp;lt;li&amp;gt;Python (Bottle)&amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt;Docker&amp;lt;/li&amp;gt;
 &amp;lt;li&amp;gt;UNIX&amp;lt;/li&amp;gt;
 &amp;lt;/div&amp;gt;
 &amp;lt;/div&amp;gt;
&amp;lt;/details&amp;gt;

## Achivements

- Essential part of the winning team of the following hackathons:
 - Ideacon (2018)
 - Reset (2018)
- Essential part of the 2nd place team of the Blockchain Mobility Hackathon 2019 in Barcelona, Spain.
&lt;/code>&lt;/pre>&lt;p>As you can see, using MDX means that we can use &lt;a href="https://www.markdownguide.org/">Markdown syntax&lt;/a> and &lt;a href="https://es.reactjs.org/docs/introducing-jsx.html">JSX&lt;/a> in the same document, giving a lot of flexibility and customization to our Docz projects.&lt;/p>
&lt;p>At the end they will look something like this:&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-2.png" alt="Contact page">&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-3.png" alt="Resume page">&lt;/p>
&lt;h2 id="spice-it-adding-a-custom-component">Spice it! Adding a custom component&lt;/h2>
&lt;p>Now let’s focus on our &lt;code>index.mdx&lt;/code> file. Let’s change it’s title to &amp;ldquo;About me&amp;rdquo;&lt;/p>
&lt;pre tabindex="0">&lt;code class="language-mdx" data-lang="mdx">&amp;lt;!-- src/index.mdx --&amp;gt;
---
name: About me
route: /
---

# Hello world from Docz!
&lt;/code>&lt;/pre>&lt;p>And then, create a &lt;code>components&lt;/code> folder inside of the &lt;code>src&lt;/code> directory. There create a &lt;code>welcome.jsx&lt;/code> component, this will replace our Markdown heading to make the root page more interesting.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-jsx" data-lang="jsx">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#737994;font-style:italic">// src/components/welcome.jsx
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#737994;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">import&lt;/span> React from &lt;span style="color:#a6d189">&amp;#39;react&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">const&lt;/span> Welcome &lt;span style="color:#99d1db;font-weight:bold">=&lt;/span> ( props ) =&amp;gt; {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">const&lt;/span> style &lt;span style="color:#99d1db;font-weight:bold">=&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> container&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> display&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#39;flex&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> flexDirection&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#39;column&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> textContainer&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> textAlign&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#39;center&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> imgContainer&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> paddingTop&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#39;1em&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> img&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> display&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#39;flex&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> margin&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#39;auto&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> maxWidth&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#39;40%&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> borderRadius&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#39;50%&amp;#39;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> },
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> }
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">return&lt;/span> (
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#ca9ee6">div&lt;/span> &lt;span style="color:#8caaee">style&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>{style.container}&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#ca9ee6">div&lt;/span> &lt;span style="color:#8caaee">style&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>{style.textContainer}&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#ca9ee6">h1&lt;/span>&amp;gt;{props.title}&amp;lt;/&lt;span style="color:#ca9ee6">h1&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#ca9ee6">span&lt;/span>&amp;gt;{props.children}&amp;lt;/&lt;span style="color:#ca9ee6">span&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#ca9ee6">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#ca9ee6">div&lt;/span> &lt;span style="color:#8caaee">style&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>{style.imgContainer}&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;&lt;span style="color:#ca9ee6">img&lt;/span> &lt;span style="color:#8caaee">style&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>{style.img} &lt;span style="color:#8caaee">src&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>{props.img} &lt;span style="color:#8caaee">alt&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">=&lt;/span>{props.title}/&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#ca9ee6">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &amp;lt;/&lt;span style="color:#ca9ee6">div&lt;/span>&amp;gt;
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> )
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">export&lt;/span> &lt;span style="color:#ca9ee6">default&lt;/span> Welcome
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Here I just made a quick component that takes a title, some text and displays it all centered and the image as a circle, but you can make your creativity go wild on this one!&lt;/p>
&lt;p>Next, let’s change index.mdx to import our component and use it to give a warm welcome to all the visitors on our webpage, here is how it looks:&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-4.png" alt="Welcome page">&lt;/p>
&lt;h2 id="its-alive-time-to-deploy">It&amp;rsquo;s alive! Time to deploy&lt;/h2>
&lt;p>ow that we have our Docz project it’s time to build it and deploy it to GitHub Pages (since we already have the repository there).&lt;/p>
&lt;p>First we need to configure some things, go to your doczrc.js file and add a dest key with the value “/docs” and a base key the name of your repo as it’s value.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-js" data-lang="js">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#737994;font-style:italic">// doczrc.js
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#737994;font-style:italic">&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">export&lt;/span> &lt;span style="color:#ca9ee6">default&lt;/span> {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> title&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#34;Luis Angel Ortega&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> description&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#34;Hello, I&amp;#39;m Luis Angel and this is my resume made with Docz!&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> ignore&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> [&lt;span style="color:#a6d189">&amp;#34;README.md&amp;#34;&lt;/span>],
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> dest&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#34;/docs&amp;#34;&lt;/span>,
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> base&lt;span style="color:#99d1db;font-weight:bold">:&lt;/span> &lt;span style="color:#a6d189">&amp;#34;docz-resume&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The first key is telling Docz to build the project into the docs directory, we’re doing this since GitHub Pages expects the static files to be on the root or docs directories.&lt;/p>
&lt;p>The base key is changing the base folder to match the name of the repo in order to make the public files and links to work in GitHub Pages.&lt;/p>
&lt;p>Once we have everything correctly configured, we need to build the project with the following command:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>yarn docz build &lt;span style="color:#737994;font-style:italic"># or npm run docz build&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>When it is done, you will see a docs folder on your project. Commit and push everything to your repo. After that, let’s go to the settings tab on your project and in the left menu go to the Pages section.&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-5.png" alt="Repo page">&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-6.png" alt="Settings page">&lt;/p>
&lt;p>Then select your main branch (or the branch on which you are working on) and select the docs folder.&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-7.png" alt="Pages page">&lt;/p>
&lt;p>And that is it! In a few minutes your website should be live on the link that GitHub has given you.&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-8.png" alt="Done!">&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/cv-docz-9.png" alt="Handsome you">&lt;/p>
&lt;h2 id="the-future-awaits">The future awaits&lt;/h2>
&lt;p>In this article we only scratched the surface of what Docz is capable of, so be sure to check their &lt;a href="https://www.docz.site/docs/getting-started">documentation&lt;/a> to learn more.&lt;/p>
&lt;p>I encourage you to read about them to make your resume stand out from the crowd and always remember to support the creators of this amazing project and contribute if you can.&lt;/p>
&lt;p>Find the repo of the project &lt;a href="https://github.com/LinkSake/docz-resume">here&lt;/a>. For end result, check out &lt;a href="https://linksake.github.io/docz-resume/">GitHub&lt;/a>.&lt;/p></description></item><item><title>Docker + Rails: A Solution for Your Headaches</title><link>https://luisangel.me/post/2021/09/02/docker-and-rails/</link><pubDate>Thu, 02 Sep 2021 15:15:49 -0500</pubDate><author>hey@luisangel.me (Luis Angel Ortega)</author><guid>https://luisangel.me/post/2021/09/02/docker-and-rails/</guid><description>&lt;p>Have you ever spent a week just trying to run the project you just joined? Or does your application not run in production as it did locally?
There are a multitude of factors that can contribute to this, which is why &lt;a href="https://www.docker.com/">Docker&lt;/a> offers us a solution with which we can have greater control over these variables across the necessary computers.&lt;/p>
&lt;p>With that said, in this article we will see how to make our lives easier by having our entire Ruby on Rails application running on Docker; including any necessary databases.&lt;/p>
&lt;h2 id="prerequisites">Prerequisites&lt;/h2>
&lt;p>To follow this guide, you will need to have &lt;a href="https://docs.docker.com/get-docker/">Docker installed&lt;/a> as well as a project you want to &lt;em>dockerize&lt;/em>. If you just want to practice, you can use &lt;a href="https://github.com/LinkSake/docker-rails">this example project&lt;/a> which requires a connection to &lt;a href="https://en.wikipedia.org/wiki/PostgreSQL">Postgres&lt;/a> and &lt;a href="https://en.wikipedia.org/wiki/Redis">Redis&lt;/a> to function.&lt;/p>
&lt;p>Are you impatient? You can clone &lt;a href="https://github.com/LinkSake/docker-rails/tree/docker">this branch&lt;/a> of the project where the necessary files to run the project inside Docker are already present!&lt;/p>
&lt;h2 id="first-comes-the-dockerfile">First Comes the Dockerfile&lt;/h2>
&lt;p>The first thing we will do is create a custom &lt;a href="https://docs.docker.com/get-started/overview/#docker-objects">image&lt;/a> for our project, so we will create a file at the root of it called &lt;code>Dockerfile&lt;/code>&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>touch Dockerfile
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The first line of our file will define the image we will base on, in this case, it will be the &lt;a href="https://hub.docker.com/_/ruby">official Ruby image&lt;/a>, but we will use the Alpine version to have a lighter image as a result.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">FROM&lt;/span>&lt;span style="color:#a6d189"> ruby:3.0.1-alpine&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>⚠️ Make sure the Ruby version (ruby:X.X.X-alpine) is the same as in your project, or you will have errors when trying to build the image. You can find the version used by your project in your Gemfile.&lt;/p>
&lt;/blockquote>
&lt;p>Next comes the most difficult part of this Dockerfile, installing the necessary dependencies for the project to function; those shown here are the ones that work for our &lt;a href="https://github.com/LinkSake/docker-rails">example project&lt;/a>, which include the necessary ones to make a connection with Postgres, but you will have to discover which ones are necessary for your project.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">FROM&lt;/span>&lt;span style="color:#a6d189"> ruby:3.0.1-alpine&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> apk add --update --no-cache --virtual run-dependencies &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>build-base &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-client &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-dev &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>yarn &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>git &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>tzdata &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>libpq &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/cache/apk/*&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>You can wait to build the image (&lt;code>docker build .&lt;/code>) to check the error printed by Docker, with that you can find out what dependencies are missing 😉&lt;/p>
&lt;/blockquote>
&lt;p>The last line (&lt;code>rm -rf /var/cache/apk/*&lt;/code>) deletes the packages of the dependencies we just installed, this will save space in the image.&lt;/p>
&lt;p>Next, we need to create a directory inside the container where we can copy the code of our application for its execution, we will do this with the following command inside our Dockerfile.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">FROM&lt;/span>&lt;span style="color:#a6d189"> ruby:3.0.1-alpine&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> apk add --update --no-cache --virtual run-dependencies &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>build-base &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-client &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-dev &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>yarn &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>git &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>tzdata &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>libpq &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/cache/apk/*&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">WORKDIR&lt;/span>&lt;span style="color:#a6d189"> /docker-rails&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Remember to change &lt;code>docker-rails&lt;/code> to your project name!&lt;/p>
&lt;/blockquote>
&lt;p>Just as we gave your project a home inside the container we will create, the gems of the same need a folder too. Therefore, we will inform &lt;a href="https://bundler.io/">bundler&lt;/a> where to place them through an environment variable.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">FROM&lt;/span>&lt;span style="color:#a6d189"> ruby:3.0.1-alpine&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> apk add --update --no-cache --virtual run-dependencies &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>build-base &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-client &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-dev &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>yarn &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>git &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>tzdata &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>libpq &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/cache/apk/*&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">WORKDIR&lt;/span>&lt;span style="color:#a6d189"> /docker-rails&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">ENV&lt;/span> BUNDLE_PATH /gems&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And although we have already installed the necessary dependencies to run Rails within the container, your project will need some gems and some JavaScript packages to function correctly, we will take care of that as follows.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">FROM&lt;/span>&lt;span style="color:#a6d189"> ruby:3.0.1-alpine&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> apk add --update --no-cache --virtual run-dependencies &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>build-base &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-client &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-dev &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>yarn &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>git &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>tzdata &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>libpq &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/cache/apk/*&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">WORKDIR&lt;/span>&lt;span style="color:#a6d189"> /docker-rails&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">ENV&lt;/span> BUNDLE_PATH /gems&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">COPY&lt;/span> package.json yarn.lock /docker-rails/&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> yarn install&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">COPY&lt;/span> Gemfile Gemfile.lock /docker-rails/&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> bundle install&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Now that we have everything necessary for your project to function, we will copy the code to the container inside the folder we created with the &lt;code>WORKDIR&lt;/code> command.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">FROM&lt;/span>&lt;span style="color:#a6d189"> ruby:3.0.1-alpine&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> apk add --update --no-cache --virtual run-dependencies &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>build-base &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-client &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-dev &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>yarn &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>git &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>tzdata &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>libpq &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/cache/apk/*&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">WORKDIR&lt;/span>&lt;span style="color:#a6d189"> /docker-rails&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">ENV&lt;/span> BUNDLE_PATH /gems&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">COPY&lt;/span> package.json yarn.lock /docker-rails/&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> yarn install&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">COPY&lt;/span> Gemfile Gemfile.lock /docker-rails/&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> bundle install&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">COPY&lt;/span> . /docker-rails/&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>Why do we first copy the manifests (package.json, Gemfile, etc.) and then the rest of the project? This avoids having to reinstall the dependencies (since they stay in the cache) after changing the base code and rebuilding the image; this way only when the manifests change will their installation commands be run again.&lt;/p>
&lt;/blockquote>
&lt;p>Finally, we will tell Docker what command to run when we start our container (&lt;code>rails&lt;/code>), as well as the arguments for it (&lt;code>s -b 0.0.0.0&lt;/code>) and which port to expose so that we can access our application.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-Dockerfile" data-lang="Dockerfile">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">FROM&lt;/span>&lt;span style="color:#a6d189"> ruby:3.0.1-alpine&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> apk add --update --no-cache --virtual run-dependencies &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>build-base &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-client &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>postgresql-dev &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>yarn &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>git &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>tzdata &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>libpq &lt;span style="color:#8caaee">\
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#8caaee">&lt;/span>&lt;span style="color:#99d1db;font-weight:bold">&amp;amp;&amp;amp;&lt;/span> rm -rf /var/cache/apk/*&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>WORKROOM /docker-rails&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">ENV&lt;/span> BUNDLE_PATH /gems&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">COPY&lt;/span> package.json yarn.lock /docker-rails/&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> yarn install&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">COPY&lt;/span> Gemfile Gemfile.lock /docker-rails/&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">RUN&lt;/span> bundle install&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">COPY&lt;/span> . /docker-rails/&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">ENTRYPOINT&lt;/span> [&lt;span style="color:#a6d189">&amp;#34;bin/rails&amp;#34;&lt;/span>]&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">CMD&lt;/span> [&lt;span style="color:#a6d189">&amp;#34;s&amp;#34;&lt;/span>, &lt;span style="color:#a6d189">&amp;#34;-b&amp;#34;&lt;/span>, &lt;span style="color:#a6d189">&amp;#34;0.0.0.0&amp;#34;&lt;/span>]&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#e78284">&lt;/span>&lt;span style="color:#ca9ee6">EXPOSE&lt;/span>&lt;span style="color:#a6d189"> 3000&lt;/span>&lt;span style="color:#e78284">
&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>The default port over which Rails runs is 3000, but if you have designated another port within your application make sure to expose it correctly.&lt;/p>
&lt;/blockquote>
&lt;p>And with this we have our Dockerfile ready, although we are far from having our application ready. If we build our image with &lt;code>docker build .&lt;/code> and try to run it with &lt;code>docker start docker-rails&lt;/code> we would encounter an error, since Rails does not find the databases it needs to start correctly; but we will soon take care of that.&lt;/p>
&lt;h2 id="then-the-docker-composeyml">Then the docker-compose.yml&lt;/h2>
&lt;p>To coordinate all the services we need for the correct functioning of our application (in this case 2 databases: Postgres and Redis) we will use &lt;a href="https://docs.docker.com/compose/">docker-compose&lt;/a>, this Docker utility will help us create multiple containers from different images, &lt;a href="https://docs.docker.com/compose/networking/">connect them&lt;/a>, give them &lt;a href="https://docs.docker.com/compose/environment-variables/">environment variables&lt;/a> and even &lt;a href="https://docs.docker.com/storage/volumes/">volumes&lt;/a>.&lt;/p>
&lt;p>We will start by creating a file called &lt;code>docker-compose.yml&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>touch docker-compose.yml
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And on its first line we will specify which &lt;a href="https://docs.docker.com/compose/compose-file/#compose-and-docker-compatibility-matrix">version&lt;/a> of the tool we want to use, in this case we will use the most recent at the time of writing this article.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">version&lt;/span>: &lt;span style="color:#a6d189">&amp;#39;3.8&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Next, we will indicate the services we want docker-compose to run, we will do this under the &lt;code>services&lt;/code> label. We will give each service a name, which will be important when we are configuring our image, so make sure to name it in a way that makes sense to you. Let&amp;rsquo;s start with the Postgres service, which we will call &lt;em>db&lt;/em>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">version&lt;/span>: &lt;span style="color:#a6d189">&amp;#39;3.8&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">db&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: postgres:latest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-db
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_DB=docker-rails-dev
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_PASSWORD=password
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">5432&lt;/span>:&lt;span style="color:#ef9f76">5432&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#a6d189">&amp;#39;dbdata:/var/lib/postgresql/data&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;blockquote>
&lt;p>YAML files are sensitive to indentation, so make sure everything is in order and indented correctly.&lt;/p>
&lt;/blockquote>
&lt;p>The &lt;code>db&lt;/code> tag is the name we gave to the service and within which we will specify all the configuration for it.&lt;/p>
&lt;p>The first thing we encounter is &lt;code>image&lt;/code>, which as its name indicates is the name of the image we want to use for that service, in this case it is the official Postgres image in its latest version (you can specify a version by replacing &lt;code>latest&lt;/code> with another valid version).&lt;/p>
&lt;p>Then we encounter &lt;code>container_name&lt;/code>, which is also self-explanatory and which will come in handy when checking our containers with &lt;code>docker ps&lt;/code>.&lt;/p>
&lt;p>&lt;code>environment&lt;/code> refers to the environment variables, and if we refer to the &lt;a href="https://hub.docker.com/_/postgres">Docker Postgres image documentation&lt;/a> we can see that the only mandatory variable is &lt;code>POSTGRES_PASSWORD&lt;/code> but we will also define &lt;code>POSTGRES_DB&lt;/code> to give a custom name to the database that the image creates by default.&lt;/p>
&lt;blockquote>
&lt;p>⚠️ Be sure to choose a secure password for the database!&lt;/p>
&lt;/blockquote>
&lt;p>&lt;code>ports&lt;/code> are the ports that we will need to pass from inside the container to our machine, the ones indicated in the file are the ones that Postgres uses by default.&lt;/p>
&lt;p>Finally, the &lt;code>volumes&lt;/code> are the persistent information we will need so as not to run the migrations every time we turn on the container, this is because Docker deletes all data once we shut down the information, if you want to learn more about this topic I recommend &lt;a href="https://docs.docker.com/storage/volumes/">this&lt;/a> section of the documentation.&lt;/p>
&lt;p>Now, the next service is Redis but we will not delve much into it as it only has a couple of labels which we have already reviewed, for more information you can visit &lt;a href="https://hub.docker.com/_/redis">the official image&lt;/a>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">version&lt;/span>: &lt;span style="color:#a6d189">&amp;#39;3.8&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">db&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: postgres:latest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-db
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_DB=docker-rails-dev
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_PASSWORD=password
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">5432&lt;/span>:&lt;span style="color:#ef9f76">5432&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#a6d189">&amp;#39;dbdata:/var/lib/postgresql/data&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">redis&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: redis:latest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-redis
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">6379&lt;/span>:&lt;span style="color:#ef9f76">6379&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>Our last service we will call &lt;code>web&lt;/code> and it will be the image we have built with our &lt;code>Dockerfile&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">version&lt;/span>: &lt;span style="color:#a6d189">&amp;#39;3.8&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">db&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: postgres:latest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-db
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_DB=docker-rails-dev
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_PASSWORD=password
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">5432&lt;/span>:&lt;span style="color:#ef9f76">5432&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#a6d189">&amp;#39;dbdata:/var/lib/postgresql/data&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">redis&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: redis:latest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-redis
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">6379&lt;/span>:&lt;span style="color:#ef9f76">6379&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">web&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">build&lt;/span>: .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: docker-rails
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-web
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">3000&lt;/span>:&lt;span style="color:#ef9f76">3000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">depends_on&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - db
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - redis
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_HOST=db
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_USER=postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_PASSWORD=password
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - REDIS_URL=redis://redis:6379
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>The first new tag we encounter is &lt;code>build&lt;/code>, which indicates the directory where our Dockerfile is located; since our Dockerfile is at the root we will only put &lt;code>.&lt;/code>; if your Dockerfile is not at the root or has another name it is advisable to read &lt;a href="https://docs.docker.com/compose/compose-file/compose-file-v3/#build">this&lt;/a> section of the documentation to make sure Compose finds it.&lt;/p>
&lt;p>The &lt;code>image&lt;/code> tag in this case will serve to name the image that Compose will build, since &lt;code>build&lt;/code> is present it will not go to the repository to look for a pre-built image.&lt;/p>
&lt;p>Finally, the &lt;code>depends_on&lt;/code> tag will inform Compose that it should not try to start the container until the &lt;code>db&lt;/code> and &lt;code>redis&lt;/code> services are created, as well as it will connect them internally so that we can access them through a URL (as can be seen in the Redis environment variable) or by their respective credentials (as is the case with Postgres), if you want to learn how Docker handles this you can read about &lt;a href="https://docs.docker.com/compose/networking/">Docker Network&lt;/a>.&lt;/p>
&lt;p>Now that we have finished with the services, the only thing we must do is list the volumes we will use and which we &lt;a href="https://docs.docker.com/compose/compose-file/compose-file-v3/#volumes">named&lt;/a> in the following way.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-yaml" data-lang="yaml">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">version&lt;/span>: &lt;span style="color:#a6d189">&amp;#39;3.8&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">services&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">db&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: postgres:latest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-db
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_DB=docker-rails-dev
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_PASSWORD=password
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">5432&lt;/span>:&lt;span style="color:#ef9f76">5432&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#a6d189">&amp;#39;dbdata:/var/lib/postgresql/data&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">redis&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: redis:latest
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-redis
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">6379&lt;/span>:&lt;span style="color:#ef9f76">6379&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">web&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">build&lt;/span>: .
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">image&lt;/span>: docker-rails
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">container_name&lt;/span>: docker-rails-web
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">ports&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - &lt;span style="color:#ef9f76">3000&lt;/span>:&lt;span style="color:#ef9f76">3000&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">depends_on&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - db
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - redis
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">environment&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_HOST=db
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_USER=postgres
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - POSTGRES_PASSWORD=password
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - REDIS_URL=redis://redis:6379
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> - .:/app
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>&lt;span style="color:#ca9ee6">volumes&lt;/span>:
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#ca9ee6">dbdata&lt;/span>:
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And that&amp;rsquo;s it! Our &lt;code>docker-compose.yml&lt;/code> is ready, now there&amp;rsquo;s only one step left to start creating our Docker-contained application.&lt;/p>
&lt;h2 id="out-of-sight-dockerignore-out-of-mind">Out of Sight, .dockerignore Out of Mind&lt;/h2>
&lt;p>Many times we do not want certain files to be in our Docker image because they are not necessary for its construction (or are generated in it) and only end up making the project larger than it needs to be, such as the &lt;code>node_modules&lt;/code> and &lt;code>.git&lt;/code> folder.
To save this space, we will create a file called &lt;code>.dockerignore&lt;/code> at the root of our project and add these two folders:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#99d1db">echo&lt;/span> &lt;span style="color:#a6d189">&amp;#34;.git \n node_modules&amp;#34;&lt;/span> &amp;gt;&amp;gt; .dockerignore
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>For more information on what a &lt;code>.dockerignore&lt;/code> file can contain, you can consult the &lt;a href="https://docs.docker.com/engine/reference/builder/#dockerignore-file">official Docker documentation&lt;/a>&lt;/p>
&lt;h2 id="databases-2-go">Databases 2 Go&lt;/h2>
&lt;p>Before running the project it will be necessary to create the database that Rails expects, and creating it is so simple that it can be done in a single command.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker-compose run web db:create
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>This command tells Docker to use the image (which it will build) to run a command, in this case &lt;code>db:create&lt;/code>. Docker, with what is specified in the &lt;code>docker-compose.yml&lt;/code>, knows that since &lt;em>web&lt;/em> depends on &lt;em>db&lt;/em> it will have to run the Postgres instance first, so the database will be created in this container.&lt;/p>
&lt;blockquote>
&lt;p>Why only &lt;code>db:create&lt;/code> and not &lt;code>rails db:create&lt;/code> or &lt;code>rake db:create&lt;/code>? In our &lt;code>Dockerfile&lt;/code> we gave &lt;code>rails&lt;/code> as the entry point, so only the parameters are necessary. If we wanted to perform another command inside the container this would have to be through &lt;a href="https://docs.docker.com/engine/reference/commandline/exec/">docker exec&lt;/a>.&lt;/p>
&lt;/blockquote>
&lt;h2 id="our-application-in-a-container">Our Application in a Container&lt;/h2>
&lt;p>With the database created, there&amp;rsquo;s only one command left that will run the containers in &lt;a href="https://docs.docker.com/compose/reference/up/">detached mode&lt;/a> and we will be able to see the fruit of our labor.&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#c6d0f5;background-color:#303446;-moz-tab-size:4;-o-tab-size:4;tab-size:4;">&lt;code class="language-bash" data-lang="bash">&lt;span style="display:flex;">&lt;span>docker-compose up -d
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>And that&amp;rsquo;s it! You can now access through your browser to &lt;a href="http://localhost:3000/">localhost:3000&lt;/a> and see the Rails welcome page.&lt;/p>
&lt;p>&lt;img src="https://luisangel.me/images/post/docker-rails-1.png" alt="Welcome to Rails!">&lt;/p>
&lt;h2 id="conclusion">Conclusion&lt;/h2>
&lt;p>This whole process may be a bit intimidating at first, especially if you are not familiar with Docker, but the result is a much simpler development environment for everyone involved in the project, as now just by having Docker installed they can start programming; not to mention the benefits that this technology can bring to your production environment when combined with Kubernetes or Docker Swarm.&lt;/p>
&lt;p>I hope you found this useful, anything you can &lt;a href="https://luisangel.me/es/about">contact me&lt;/a> and I will respond as soon as possible.&lt;/p>
&lt;h2 id="references">References&lt;/h2>
&lt;ul>
&lt;li>&lt;a href="https://docs.docker.com/samples/rails/">Docker Docs&lt;/a>&lt;/li>
&lt;li>&lt;a href="https://gorails.com/episodes/docker-basics-for-gorails">Go Rails&lt;/a>&lt;/li>
&lt;/ul></description></item><item><title>Home Office or No Home Office? That is the Question</title><link>https://luisangel.me/post/2021/04/20/the-issue-with-home-office/</link><pubDate>Tue, 20 Apr 2021 15:07:57 -0500</pubDate><author>hey@luisangel.me (Luis Angel Ortega)</author><guid>https://luisangel.me/post/2021/04/20/the-issue-with-home-office/</guid><description>&lt;p>During this past weekend, I found myself in the middle of a family conversation, where the topic of &lt;em>home office&lt;/em> came up. My father commented that it wasn&amp;rsquo;t a good practice. &amp;ldquo;It&amp;rsquo;s not healthy,&amp;rdquo; he repeated several times while shaking his head from side to side in denial.&lt;/p>
&lt;p>My cousin and I did not agree with him, as both of us (who, by the way, both work in the IT field) have seen huge benefits from working from home. We tried to explain, but he continued to shake his head and finally we left the conversation at that.&lt;/p>
&lt;p>But since then, I haven&amp;rsquo;t been able to stop thinking about it. Is &lt;em>home office&lt;/em> really healthy? Does it really have the benefits that I claim? After a couple of days of reflection, I found that this topic, like everything in life, is complicated.&lt;/p>
&lt;p>We have already passed the first year mark of the &lt;a href="https://en.wikipedia.org/wiki/COVID-19_pandemic">pandemic&lt;/a>, and from my experience and privilege, &lt;em>home office&lt;/em> has brought a lot of benefits to my life (although here I only list 3).&lt;/p>
&lt;hr>
&lt;h3 id="the-good">The Good&lt;/h3>
&lt;ul>
&lt;li>&lt;strong>Job opportunities&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>This situation has allowed me to have a remote job, something that while possible before, I&amp;rsquo;m not sure I would have been given the opportunity so easily as a &lt;em>junior&lt;/em> developer.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>More time for myself&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>I think this is the most obvious, as without having to travel (or even shower in the mornings) to go to an office I have been able to sleep more, spend more time with my family, and give myself time for me. I have been able to engage in more activities, which although are inside my house or with a limited number of people, I had not been able to try before; I didn&amp;rsquo;t know how much time of my life was only going in transport to other places.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Greater mental peace&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>This was the point I wanted to get to, because I believe not everyone has experienced this, but for me (after the initial shock of confinement) my mental health has improved considerably. See, I have &lt;a href="https://en.wikipedia.org/wiki/Generalized_anxiety_disorder">generalized anxiety disorder&lt;/a> and there are days that I am very, very bad. Those days, when I had to work in an office, were terrible. The workday seemed eternal, I&amp;rsquo;m sure I aged 4 years for each day that was like that; I couldn&amp;rsquo;t concentrate during those hours and I felt horrible about it, feeling that my work was not worth it and not sure what I was doing there. It was a time when neither my mind nor my body could escape from there, the most I could do was watch a couple of YouTube videos, talk to colleagues or go for a walk; but that was it, your colleagues can only talk so much with you before they have to return to their tasks and after a certain number of walks your boss starts to look at you weird (YouTube videos are infinite, for better or worse).&lt;/p>
&lt;p>But in the &lt;em>home office&lt;/em> I have the privilege of working from my room, where I have all the tools I need to deal with those bad days, which not only are no longer terrible, but have decreased in quantity and frequency! Although it took a couple of months to reach stability in my routine and have the discipline to work from home, now if I start having a particularly terrible day, I&amp;rsquo;ll take a quick shower, go out to the patio, and play with my pet; and that will work as a &lt;em>reset&lt;/em> to my body, where I didn&amp;rsquo;t lose the whole day trying to escape from my own mind, instead just 20 minutes in regaining composure. On less terrible but still difficult days, stopping each &lt;a href="https://en.wikipedia.org/wiki/Pomodoro_Technique">pomodoro&lt;/a> break to walk around the house or play a game as a reward for finishing a task serves as enough incentive to keep a good mood all day.&lt;/p>
&lt;hr>
&lt;h3 id="the-bad">The Bad&lt;/h3>
&lt;p>This is not to say that everything has been rosy, as I mentioned, it was a couple of months of work to get to this point. Also, I know I am speaking from a huge privilege, because not only was I lucky enough to have the equipment to work comfortably from home; but I had a place where to do it and a quiet environment, something that many people have not had.&lt;/p>
&lt;p>Even so, with all my privilege, there has been a big point and an important topic throughout the pandemic: socialization.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Socialization&lt;/strong>&lt;/li>
&lt;/ul>
&lt;p>As an &amp;ldquo;adult&amp;rdquo; that I am, I am starting to notice something that I had heard from older people: when you are an adult it is difficult to make friends. And in my first job in IT the best thing I took away were the friendships I made, because they are people that to this day I frequent and talk to daily; they went from being colleagues to close friends. Talking with them I like to tell them that really that office was not an office, but really we were in a &lt;em>reality show&lt;/em> style &lt;a href="https://en.wikipedia.org/wiki/The_Office">&lt;em>The Office&lt;/em>&lt;/a> where they recorded everything that happened.&lt;/p>
&lt;p>While, in the jobs/internships that I had during the pandemic I was able to meet incredible people, people I consider mentors, I can&amp;rsquo;t help but think that I would have a better relationship with them if I could have seen them in person more often. I also can&amp;rsquo;t deny that it is much easier to get help from someone if they are sitting next to you, even if it only serves as a &lt;a href="https://en.wikipedia.org/wiki/Rubber_duck_debugging">rubber duck&lt;/a>.&lt;/p>
&lt;p>In short, I miss very much the human warmth that working in an office brought and it would be a lie if I did not say that I worry about losing the ability to make friends if this model awaited me for the rest of my life.&lt;/p>
&lt;p>However, this is just one of the problems that working from home brings; I have not touched on things as important as that businesses save money if we are not physically in an office while we spend more by having to pay for the supplies we use to work without having a salary increase that reflects that saving on the part of the employer. This was not the point I wanted to touch on in this writing, but we should not take our finger off that topic.&lt;/p>
&lt;hr>
&lt;h2 id="what-i-propose">What I Propose&lt;/h2>
&lt;p>So what is the solution? What would be ideal? From my young and naive point of view, and considering that this is a solution to my specific problems; I believe that the solution would be a hybrid model, 2 days of face-to-face office and 3 days of work from home. It could work in reverse as well, but personally I prefer the first option.&lt;/p>
&lt;p>This would allow for an agile dynamic for situations such as meetings, planning or any other type of event that benefits from being physically in a room, leaving 3 days of space for the employee to work comfortably and in their own style from home. Also, if the office is already going to be open some days, why not allow employees who want to go work there? This could benefit, for example, someone who does not have good internet at home or someone who has children at home and does not have a suitable place to concentrate.&lt;/p>
&lt;p>In this last example it also works the other way around, it would allow (if things return to something that resembles the &lt;em>past&lt;/em>) for working parents to see their children more time after they get home from school, even allowing everyone to eat at the same time, at the same table.&lt;/p>
&lt;hr>
&lt;p>In the end, like many of the beautiful things in life, I think everything should be left to the free will of people; that they can choose the model that works best for them, because I believe that we as humans are much more than a piece of meat capable of making money for a company and &lt;em>home office&lt;/em> can be a support in our search for meaning and happiness.&lt;/p>
&lt;p>If you are interested in more about the topic of post-covid life, I recommend this &lt;a href="https://www.youtube.com/watch?v=6iILrpgbAMY">video&lt;/a> by Ophelia Pastrana.&lt;/p></description></item></channel></rss>