Jekyll2021-06-15T02:02:30+00:00https://michael.minton.io/feed.xmlmichael.minton.ioCopyright 2017
using bulma with phoenix2019-08-06T21:10:32+00:002019-08-06T21:10:32+00:00https://michael.minton.io/2019/08/using-bulma-with-phoenix<p>In this short post I’ll walk you through getting a new Phoenix 1.4 app up and running with <a href="https://bulma.io/">Bulma</a>, a responsive, modular, and modern css framework. It feels light and it is really easy to use.</p>
<h1 id="yarn">Yarn</h1>
<p>I prefer <a href="https://yarnpkg.com/">Yarn</a> so let’s make sure it’s installed.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew install yarn
</code></pre></div></div>
<h1 id="generate-a-new-phoenix-14-app">Generate a new Phoenix 1.4 app</h1>
<p><em>This assumes you have both Elixir and Phoenix installed already. If not checkout their <a href="https://hexdocs.pm/phoenix/installation.html#content">guides</a> which do a great job walking through the process.</em></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mix phx.new bulma
</code></pre></div></div>
<p>Be sure <strong>NOT</strong> to install any dependencies when prompted.</p>
<p>Manually install all dependencies and create the database:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">cd </span>bulma <span class="o">&&</span> mix deps.get <span class="o">&&</span> mix ecto.create <span class="o">&&</span> <span class="nb">cd </span>assets <span class="o">&&</span> yarn add node-sass sass-loader bulma <span class="nt">--dev</span> <span class="o">&&</span> yarn <span class="o">&&</span> node node_modules/webpack/bin/webpack.js <span class="nt">--mode</span> development <span class="o">&&</span> <span class="nb">cd</span> ..
</code></pre></div></div>
<h1 id="switching-to-sass">Switching to sass</h1>
<p>Change our file extensions to sass and remove default styles:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mv </span>assets/css/app.css assets/css/app.scss <span class="o">&&</span> <span class="nb">sed</span> <span class="nt">-i</span> <span class="s1">''</span> <span class="s1">'s/app.css/app.scss/g'</span> assets/js/app.js <span class="o">&&</span> <span class="nb">rm </span>assets/css/phoenix.css
</code></pre></div></div>
<p>Open <code class="highlighter-rouge">/assets/webpack.config.js</code> and find the place that tests for <code class="highlighter-rouge">css</code> files, it should look like this:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
<span class="nl">test</span><span class="p">:</span> <span class="sr">/</span><span class="se">\.</span><span class="sr">css$/</span><span class="p">,</span>
<span class="nx">use</span><span class="p">:</span> <span class="p">[</span><span class="nx">MiniCssExtractPlugin</span><span class="p">.</span><span class="nx">loader</span><span class="p">,</span> <span class="dl">'</span><span class="s1">css-loader</span><span class="dl">'</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Now replace it with this:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span>
<span class="nl">test</span><span class="p">:</span> <span class="sr">/</span><span class="se">\.</span><span class="sr">s</span><span class="se">?</span><span class="sr">css$/</span><span class="p">,</span>
<span class="nx">use</span><span class="p">:</span> <span class="p">[</span><span class="nx">MiniCssExtractPlugin</span><span class="p">.</span><span class="nx">loader</span><span class="p">,</span> <span class="dl">'</span><span class="s1">css-loader</span><span class="dl">'</span><span class="p">,</span> <span class="dl">'</span><span class="s1">sass-loader</span><span class="dl">'</span><span class="p">]</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Open <code class="highlighter-rouge">/assets/css/app.scss</code> and replace it with the following (mostly copied from the Bulma docs):</p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@charset</span> <span class="s2">"utf-8"</span><span class="p">;</span>
<span class="c1">// Import a Google Font</span>
<span class="k">@import</span> <span class="sx">url('https://fonts.googleapis.com/css?family=Nunito:400,700')</span><span class="p">;</span>
<span class="c1">// Set your brand colors</span>
<span class="nv">$purple</span><span class="p">:</span> <span class="mh">#8A4D76</span><span class="p">;</span>
<span class="nv">$pink</span><span class="p">:</span> <span class="mh">#FA7C91</span><span class="p">;</span>
<span class="nv">$brown</span><span class="p">:</span> <span class="mh">#757763</span><span class="p">;</span>
<span class="nv">$beige-light</span><span class="p">:</span> <span class="mh">#D0D1CD</span><span class="p">;</span>
<span class="nv">$beige-lighter</span><span class="p">:</span> <span class="mh">#EFF0EB</span><span class="p">;</span>
<span class="c1">// Update Bulma's global variables</span>
<span class="nv">$family-sans-serif</span><span class="p">:</span> <span class="s2">"Nunito"</span><span class="o">,</span> <span class="nb">sans-serif</span><span class="p">;</span>
<span class="nv">$grey-dark</span><span class="p">:</span> <span class="nv">$brown</span><span class="p">;</span>
<span class="nv">$grey-light</span><span class="p">:</span> <span class="nv">$beige-light</span><span class="p">;</span>
<span class="nv">$primary</span><span class="p">:</span> <span class="nv">$purple</span><span class="p">;</span>
<span class="nv">$link</span><span class="p">:</span> <span class="nv">$pink</span><span class="p">;</span>
<span class="nv">$widescreen-enabled</span><span class="p">:</span> <span class="bp">false</span><span class="p">;</span>
<span class="nv">$fullhd-enabled</span><span class="p">:</span> <span class="bp">false</span><span class="p">;</span>
<span class="c1">// Update some of Bulma's component variables</span>
<span class="nv">$body-background-color</span><span class="p">:</span> <span class="nv">$beige-lighter</span><span class="p">;</span>
<span class="nv">$control-border-width</span><span class="p">:</span> <span class="m">2px</span><span class="p">;</span>
<span class="nv">$input-border-color</span><span class="p">:</span> <span class="nb">transparent</span><span class="p">;</span>
<span class="nv">$input-shadow</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="c1">//Import Bulma</span>
<span class="k">@import</span> <span class="s1">'bulma'</span><span class="p">;</span>
</code></pre></div></div>
<p>Open <code class="highlighter-rouge">/lib/bulma_web/templates/page/index.html.eex</code> and replace it with the following (again mostly copied from Bulma docs):</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><section</span> <span class="na">class=</span><span class="s">"section"</span><span class="nt">></span>
<span class="nt"><h1</span> <span class="na">class=</span><span class="s">"title"</span><span class="nt">></span>
Bulma
<span class="nt"></h1></span>
<span class="nt"><p</span> <span class="na">class=</span><span class="s">"subtitle"</span><span class="nt">></span>
Modern CSS framework based on <span class="nt"><a</span> <span class="na">href=</span><span class="s">"https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Flexible_Box_Layout/Basic_Concepts_of_Flexbox"</span><span class="nt">></span>Flexbox<span class="nt"></a></span>
<span class="nt"></p></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"field"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"control"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">class=</span><span class="s">"input"</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">placeholder=</span><span class="s">"Input"</span><span class="nt">></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"field"</span><span class="nt">></span>
<span class="nt"><p</span> <span class="na">class=</span><span class="s">"control"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"select"</span><span class="nt">></span>
<span class="nt"><select></span>
<span class="nt"><option></span>Select dropdown<span class="nt"></option></span>
<span class="nt"></select></span>
<span class="nt"></span></span>
<span class="nt"></p></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"buttons"</span><span class="nt">></span>
<span class="nt"><a</span> <span class="na">class=</span><span class="s">"button is-primary"</span><span class="nt">></span>Primary<span class="nt"></a></span>
<span class="nt"><a</span> <span class="na">class=</span><span class="s">"button is-link"</span><span class="nt">></span>Link<span class="nt"></a></span>
<span class="nt"></div></span>
<span class="nt"></section></span>
</code></pre></div></div>
<h1 id="test-it-out">Test it out</h1>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>mix phx.server
</code></pre></div></div>
<p><img src="https://michael.minton.io/assets/20190814-phoenix-bulma.png" alt="package contents" /></p>Michael MintonIn this short post I’ll walk you through getting a new Phoenix 1.4 app up and running with Bulma, a responsive, modular, and modern css framework. It feels light and it is really easy to use.cool basecamp tricks2019-05-31T18:55:54+00:002019-05-31T18:55:54+00:00https://michael.minton.io/2019/05/cool-basecamp-tricks%20copy<p>I have used Basecamp for years and yet the other day a coworker taught me something new about it. I was a bit surprised and also excited because the new feature was actually very useful. So to share that excitement I give you some cool Basecamp tricks.</p>
<h1 id="code-formatting">Code formatting</h1>
<p>When you have a snippet of code you’d like to share via Campfire or Ping you can have Basecamp format it for you using the following command:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/code <lang> | [paste]
</code></pre></div></div>
<p>where <code class="highlighter-rouge"><lang></code> is some programming language.</p>
<p>For example, imagine I have this snippet of <em>ruby</em> code on my clipboard:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">sum_eq_n?</span><span class="p">(</span><span class="n">arr</span><span class="p">,</span> <span class="n">n</span><span class="p">)</span>
<span class="k">return</span> <span class="kp">true</span> <span class="k">if</span> <span class="n">arr</span><span class="p">.</span><span class="nf">empty?</span> <span class="o">&&</span> <span class="n">n</span> <span class="o">==</span> <span class="mi">0</span>
<span class="n">arr</span><span class="p">.</span><span class="nf">product</span><span class="p">(</span><span class="n">arr</span><span class="p">).</span><span class="nf">reject</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="o">|</span> <span class="n">a</span> <span class="o">==</span> <span class="n">b</span> <span class="p">}.</span><span class="nf">any?</span> <span class="p">{</span> <span class="o">|</span><span class="n">a</span><span class="p">,</span><span class="n">b</span><span class="o">|</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span> <span class="o">==</span> <span class="n">n</span> <span class="p">}</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Type <code class="highlighter-rouge">/code ruby | </code> then <kbd>⌘</kbd> + <kbd>v</kbd> to paste and <kbd>⏎</kbd> to send the message.</p>
<p>Basecamp will output the following nicely formatted code:</p>
<p><img src="https://michael.minton.io/assets/basecamp-code-formatting.png" alt="basecamp-code-formatting" /></p>
<h1 id="playing-sounds">Playing Sounds</h1>
<p>Dating all the way back to the original version of Campfire there has been a “hidden” ability to play various sound bites. These have been updated over the years and recently include sounds from Game of Thrones, Frozen, and more.</p>
<p>To play a sound just type <code class="highlighter-rouge">/play <sound></code> where <code class="highlighter-rouge"><sound></code> is one of the available sounds. For example, to play the 🎉 <em>Tada</em> sound type <code class="highlighter-rouge">/play tada</code> and enjoy!</p>
<p><img src="https://michael.minton.io/assets/basecamp-tada.png" alt="basecamp-tada" /></p>
<h1 id="help">Help</h1>
<p>Both of these useful commands are hidden and remembering all the sounds can be a pain. To help with this they’ve included a <code class="highlighter-rouge">help</code> command.</p>
<p>Type <code class="highlighter-rouge">/help</code> and Basecamp will spit out documentation along with a list of all the available sounds:</p>
<p><img src="https://michael.minton.io/assets/basecamp-help.png" alt="basecamp-help" /></p>Michael MintonI have used Basecamp for years and yet the other day a coworker taught me something new about it. I was a bit surprised and also excited because the new feature was actually very useful. So to share that excitement I give you some cool Basecamp tricks.creating a form for a non-persisted ecto schema in phoenix 1.42018-12-22T12:55:54+00:002018-12-22T12:55:54+00:00https://michael.minton.io/2018/12/creating-a-form-for-a-non-persisted-ecto-schema-in-phoenix<p>I kind of wanted to title this post, “how to create a form that doesn’t use a model” but Ecto decided to drop “Model” in favor of “Schema”; same thing, different mindset.</p>
<p>Sometimes you just want to collect some data from a user but have no plans of persisting it to the database. You can use <code class="highlighter-rouge">embedded_schema</code> to accomplish this. You’ll get to mostly work with Phoenix/Ecto as usual except without the migration, tables, and saving.</p>
<p>In this post we’ll be creating a <a href="https://phoenixframework.org">Phoenix</a> 1.4 app with a contact form.</p>
<h1 id="create-the-phoenix-14-app">Create the Phoenix 1.4 app</h1>
<p>The following command will</p>
<ul>
<li>create a new Phoenix app called <code class="highlighter-rouge">Contact</code></li>
<li>install its dependencies</li>
<li>create the database</li>
<li>open your browser to http://localhost:4000</li>
<li>start the webserver</li>
</ul>
<p>A couple things to note:</p>
<ol>
<li>You will told the directory already exists and asked if you want to continue: Type <code class="highlighter-rouge">y</code> and press <kbd>Enter</kbd></li>
<li>You will be asked if you want to “Fetch and install dependencies?”: Type <code class="highlighter-rouge">y</code> and press <kbd>Enter</kbd></li>
<li>The browser will likely tell you the page isn’t found since it tried to load the site before the webserver finished starting. Simply wait a second or two and then reload the page.</li>
</ol>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">mkdir </span>contact <span class="p">;</span> <span class="nb">cd </span>contact <span class="p">;</span> mix phx.new <span class="nb">.</span> <span class="nt">--app</span> contact <span class="p">;</span> mix ecto.create <span class="p">;</span> open http://localhost:4000 <span class="p">;</span> mix phx.server
</code></pre></div></div>
<p>You should be greeted with the Phoenix welcome screen.</p>
<p><img src="https://michael.minton.io/assets/20181222-welcome-to-phoenix.png" alt="Phoenix Welcome" /></p>
<h1 id="create-the-ectoschema">Create the Ecto.Schema</h1>
<p>Create a new file <code class="highlighter-rouge">\lib\contact\message.ex</code> with the following contents:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">Contact</span><span class="o">.</span><span class="no">Message</span> <span class="k">do</span>
<span class="kn">use</span> <span class="no">Ecto</span><span class="o">.</span><span class="no">Schema</span>
<span class="kn">import</span> <span class="no">Ecto</span><span class="o">.</span><span class="no">Changeset</span>
<span class="n">embedded_schema</span> <span class="k">do</span>
<span class="n">field</span> <span class="ss">:name</span>
<span class="n">field</span> <span class="ss">:email</span>
<span class="k">end</span>
<span class="k">def</span> <span class="n">changeset</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">attrs</span><span class="p">)</span> <span class="k">do</span>
<span class="n">message</span>
<span class="o">|></span> <span class="n">cast</span><span class="p">(</span><span class="n">attrs</span><span class="p">,</span> <span class="p">[</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:email</span><span class="p">])</span>
<span class="o">|></span> <span class="n">validate_required</span><span class="p">([</span><span class="ss">:name</span><span class="p">,</span> <span class="ss">:email</span><span class="p">])</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Notice we used <a href="https://hexdocs.pm/ecto/Ecto.Schema.html#embedded_schema/1">embedded_schema</a> here. This let’s <a href="https://hexdocs.pm/ecto/Ecto.html">Ecto</a> know that we don’t plan on saving this schema to the database.</p>
<h1 id="creating-the-form">Creating the form</h1>
<p>Open <code class="highlighter-rouge">\lib\contact_web\templates\page\index.html.eex</code> and replace with the following:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">"section"</span><span class="o">></span>
<span class="o"><</span><span class="n">p</span> <span class="n">class</span><span class="o">=</span><span class="s2">"alert alert-info"</span> <span class="n">role</span><span class="o">=</span><span class="s2">"alert"</span><span class="err">></span><span class="o"><%=</span> <span class="n">get_flash</span><span class="p">(</span><span class="nv">@conn</span><span class="p">,</span> <span class="ss">:info</span><span class="p">)</span> <span class="p">%</span><span class="err">></span><span class="o"></</span><span class="n">p</span><span class="o">></span>
<span class="o"><%=</span> <span class="n">form_for</span> <span class="nv">@changeset</span><span class="p">,</span> <span class="no">Routes</span><span class="o">.</span><span class="n">page_path</span><span class="p">(</span><span class="nv">@conn</span><span class="p">,</span> <span class="ss">:contact</span><span class="p">),</span> <span class="p">[</span><span class="ss">method:</span> <span class="s2">"post"</span><span class="p">],</span> <span class="k">fn</span> <span class="n">f</span> <span class="o">-></span> <span class="p">%</span><span class="o">></span>
<span class="o"><%=</span> <span class="k">if</span> <span class="nv">@changeset</span><span class="o">.</span><span class="n">action</span> <span class="k">do</span> <span class="p">%</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">"alert alert-danger"</span><span class="o">></span>
<span class="o"><</span><span class="n">p</span><span class="o">></span><span class="no">Oops</span><span class="p">,</span> <span class="n">you</span> <span class="n">might</span> <span class="n">have</span> <span class="n">missed</span> <span class="n">a</span> <span class="n">field!</span> <span class="no">Please</span> <span class="n">check</span> <span class="n">the</span> <span class="n">errors</span> <span class="n">below</span><span class="o">.</</span><span class="n">p</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"><</span><span class="p">%</span> <span class="k">end</span> <span class="p">%</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">"field"</span><span class="o">></span>
<span class="o"><%=</span> <span class="n">label</span> <span class="n">f</span><span class="p">,</span> <span class="ss">:name</span> <span class="p">%</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">"control"</span><span class="o">></span>
<span class="o"><%=</span> <span class="n">text_input</span> <span class="n">f</span><span class="p">,</span> <span class="ss">:name</span><span class="p">,</span> <span class="p">[</span><span class="ss">class:</span> <span class="s2">"input is-large"</span><span class="p">,</span> <span class="ss">placeholder:</span> <span class="s2">"Your name"</span><span class="p">]</span> <span class="p">%</span><span class="o">></span>
<span class="o"><%=</span> <span class="n">error_tag</span> <span class="n">f</span><span class="p">,</span> <span class="ss">:name</span> <span class="p">%</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">"field"</span><span class="o">></span>
<span class="o"><%=</span> <span class="n">label</span> <span class="n">f</span><span class="p">,</span> <span class="ss">:email</span><span class="p">,</span> <span class="ss">class:</span> <span class="s2">"label is-large"</span> <span class="p">%</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">"control"</span><span class="o">></span>
<span class="o"><%=</span> <span class="n">text_input</span> <span class="n">f</span><span class="p">,</span> <span class="ss">:email</span><span class="p">,</span> <span class="p">[</span><span class="ss">class:</span> <span class="s2">"input is-large"</span><span class="p">,</span> <span class="ss">type:</span> <span class="s2">"email"</span><span class="p">,</span> <span class="ss">placeholder:</span> <span class="s2">"Your email"</span><span class="p">]</span> <span class="p">%</span><span class="o">></span>
<span class="o"><%=</span> <span class="n">error_tag</span> <span class="n">f</span><span class="p">,</span> <span class="ss">:email</span> <span class="p">%</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"><</span><span class="n">div</span> <span class="n">class</span><span class="o">=</span><span class="s2">"control"</span><span class="o">></span>
<span class="o"><%=</span> <span class="n">submit</span> <span class="s2">"Send"</span><span class="p">,</span> <span class="ss">class:</span> <span class="s2">"button is-primary is-large"</span> <span class="p">%</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
<span class="o"><</span><span class="p">%</span> <span class="k">end</span> <span class="p">%</span><span class="o">></span>
<span class="o"></</span><span class="n">div</span><span class="o">></span>
</code></pre></div></div>
<h1 id="hooking-up-the-controller">Hooking up the controller</h1>
<p>Open <code class="highlighter-rouge">lib\contact_web\controllers\page_controller.ex</code> and replace with the following:</p>
<div class="language-elixir highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">defmodule</span> <span class="no">ContactWeb</span><span class="o">.</span><span class="no">PageController</span> <span class="k">do</span>
<span class="kn">use</span> <span class="no">ContactWeb</span><span class="p">,</span> <span class="ss">:controller</span>
<span class="n">alias</span> <span class="no">Contact</span><span class="o">.</span><span class="no">Message</span>
<span class="k">def</span> <span class="n">index</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="n">_params</span><span class="p">)</span> <span class="k">do</span>
<span class="n">changeset</span> <span class="o">=</span> <span class="no">Message</span><span class="o">.</span><span class="n">changeset</span><span class="p">(%</span><span class="no">Message</span><span class="p">{},</span> <span class="p">%{})</span>
<span class="n">render</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="s2">"index.html"</span><span class="p">,</span> <span class="ss">changeset:</span> <span class="n">changeset</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="n">contact</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="p">%{</span><span class="s2">"message"</span> <span class="o">=></span> <span class="n">message_params</span><span class="p">})</span> <span class="k">do</span>
<span class="n">changeset</span> <span class="o">=</span>
<span class="p">%</span><span class="no">Message</span><span class="p">{}</span>
<span class="o">|></span> <span class="no">Message</span><span class="o">.</span><span class="n">changeset</span><span class="p">(</span><span class="n">message_params</span><span class="p">)</span>
<span class="k">if</span> <span class="n">changeset</span><span class="o">.</span><span class="n">valid?</span> <span class="k">do</span>
<span class="c1"># Do something with message_params</span>
<span class="n">conn</span>
<span class="o">|></span> <span class="n">put_flash</span><span class="p">(</span><span class="ss">:info</span><span class="p">,</span> <span class="s2">"Message sent!"</span><span class="p">)</span>
<span class="o">|></span> <span class="n">redirect</span><span class="p">(</span><span class="ss">to:</span> <span class="no">Routes</span><span class="o">.</span><span class="n">page_path</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="ss">:index</span><span class="p">))</span>
<span class="k">else</span>
<span class="n">changeset</span> <span class="o">=</span> <span class="p">%{</span><span class="n">changeset</span> <span class="o">|</span> <span class="ss">action:</span> <span class="ss">:index</span><span class="p">}</span>
<span class="n">render</span><span class="p">(</span><span class="n">conn</span><span class="p">,</span> <span class="s2">"index.html"</span><span class="p">,</span> <span class="ss">changeset:</span> <span class="n">changeset</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>Michael MintonI kind of wanted to title this post, “how to create a form that doesn’t use a model” but Ecto decided to drop “Model” in favor of “Schema”; same thing, different mindset.modern rails with webpacker and stimulus2018-06-10T18:55:54+00:002018-06-10T18:55:54+00:00https://michael.minton.io/2018/06/modern-rails-with-webpacker-and-stimulus<p>I recently had the opportunity to start fresh with a new Rails app. Instead of building another traditional Rails app I took this chance to investigate using some modern tools like Webpacker and a modern CSS framework Bulma. In this post I’ll explain how I got everything wired together.</p>
<p>Here’s an outline of what we’ll cover in this post:</p>
<ul>
<li>creating a new Rails 5.2 app using <a href="https://github.com/rails/webpacker/">Webpacker</a> and <a href="https://stimulusjs.org/">Stimulus</a></li>
<li>installing <a href="https://bulma.io/">Bulma</a>, my preference over Bootstrap</li>
<li>installing <a href="https://fontawesome.com/">Font Awesome 5</a>, for icons</li>
<li>creating a basic site layout with navigation</li>
<li>wiring up the burger menu with stimulus</li>
</ul>
<h1 id="create-the-rails-app">Create the Rails app</h1>
<p><strong>Yarn</strong></p>
<p><a href="https://yarnpkg.com/">Yarn</a> claims to be “Fast, reliable, and secure dependency management” and it really is.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>yarn
</code></pre></div></div>
<p><strong>Webpacker</strong></p>
<p>This is Rail’s gateway to the land of JavaScript apps and npm packages. Webpacker can live side-by-side with the asset pipeline, although once you fully embrace it, you’ll find little need for the asset pipeline. You can use webpacker to manage all your assets.</p>
<p><strong>Stimulus</strong></p>
<p>A JavaScript framework from <a href="https://basecamp.com/">Basecamp</a> that integrates nicely with <a href="https://github.com/turbolinks/turbolinks/">Turbolinks</a>. We’ll use this to “sprinkle” in some behavior to our views.</p>
<p><strong>Rails new</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails new myapp <span class="nt">--webpack</span><span class="o">=</span>stimulus
<span class="nb">cd </span>myapp
</code></pre></div></div>
<p><strong>An initial controller</strong></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>bin/rails generate controller Home index about
</code></pre></div></div>
<p><strong>A default route</strong></p>
<p>Change your <code class="highlighter-rouge">config/routes.rb</code> file to look like this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span>
<span class="n">get</span> <span class="s1">'home/index'</span>
<span class="n">get</span> <span class="s1">'home/about'</span>
<span class="n">root</span> <span class="ss">to: </span><span class="s1">'home#index'</span>
<span class="k">end</span>
</code></pre></div></div>
<p><strong>Switching from the Asset Pipeline</strong></p>
<p>Open <code class="highlighter-rouge">app/views/layouts/application.html.erb</code> and replace <code class="highlighter-rouge">stylesheet_link_tag</code> with <code class="highlighter-rouge">stylesheet_pack_tag</code>. Next replace <code class="highlighter-rouge">javascript_include_tag</code> with <code class="highlighter-rouge">javascript_pack_tag</code>.</p>
<h1 id="bulma">Bulma</h1>
<p><a href="https://bulma.io/">Bulma</a> is a relatively new CSS framework. It feels like a light, streamlined alternative to Bootstrap. Bulma doesn’t include any JavaScript at all. This means some stuff just won’t work out of the box. For example, the burger menu won’t toggle without a little JavaScript help. We’ll get to that later.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn add bulma
</code></pre></div></div>
<p>Open <code class="highlighter-rouge">app/javascript/packs/application.js</code> and add the following to the top:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="dl">'</span><span class="s1">../styles</span><span class="dl">'</span>
</code></pre></div></div>
<p>Create <code class="highlighter-rouge">app/javascript/styles.scss</code>:</p>
<div class="language-scss highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">@import</span> <span class="s1">'~bulma/bulma'</span><span class="p">;</span>
</code></pre></div></div>
<h1 id="font-awesome-5">Font Awesome 5</h1>
<p>To use icons in Bulma you need to include <a href="https://fontawesome.com/">Font Awesome</a>.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn add @fortawesome/fontawesome
yarn add @fortawesome/fontawesome-free-regular
yarn add @fortawesome/fontawesome-free-brands
</code></pre></div></div>
<h1 id="the-view">The View</h1>
<p><strong>The navbar</strong></p>
<p>Open <code class="highlighter-rouge">app/views/layouts/application.html.erb</code> and add the following just above the <code class="highlighter-rouge">yield</code> line:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp"><%=</span> <span class="n">render</span> <span class="s1">'layouts/navbar'</span> <span class="cp">%></span>
</code></pre></div></div>
<p>Create <code class="highlighter-rouge">app/views/layouts/_navbar.html.erb</code>:</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"container"</span><span class="nt">></span>
<span class="nt"><nav</span> <span class="na">class=</span><span class="s">"navbar"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"navbar-brand"</span><span class="nt">></span>
<span class="nt"><a</span> <span class="na">class=</span><span class="s">"navbar-item"</span> <span class="na">href=</span><span class="s">"#"</span><span class="nt">></span>
<span class="nt"><img</span> <span class="na">src=</span><span class="s">"https://bulma.io/images/bulma-logo.png"</span> <span class="na">width=</span><span class="s">"112"</span> <span class="na">height=</span><span class="s">"28"</span><span class="nt">></span>
<span class="nt"></a></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"navbar-burger burger"</span> <span class="na">data-target=</span><span class="s">"main-nav"</span><span class="nt">></span>
<span class="nt"><span></span></span>
<span class="nt"><span></span></span>
<span class="nt"><span></span></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"><div</span> <span class="na">id=</span><span class="s">"main-nav"</span> <span class="na">class=</span><span class="s">"navbar-menu"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"navbar-start"</span><span class="nt">></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="n">root_url</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'navbar-item'</span> <span class="k">do</span> <span class="cp">%></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"icon"</span><span class="nt">></span>
<span class="nt"><i</span> <span class="na">class=</span><span class="s">"far fa-gem"</span><span class="nt">></i></span>
<span class="nt"></span></span>
<span class="nt"><span></span>Home<span class="nt"></span></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
<span class="cp"><%=</span> <span class="n">link_to</span> <span class="n">home_about_url</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'navbar-item'</span> <span class="k">do</span> <span class="cp">%></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"icon"</span><span class="nt">></span>
<span class="nt"><i</span> <span class="na">class=</span><span class="s">"far fa-star"</span><span class="nt">></i></span>
<span class="nt"></span></span>
<span class="nt"><span></span>About<span class="nt"></span></span>
<span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
<span class="nt"></nav></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>This is basically copied from the Bulma examples. It is a basic nav bar with two menu items; Home and About.</p>
<p>We now have all the pieces in place and can start wiring up our Stimulus controllers.</p>
<h1 id="create-a-stimulus-controller">Create a Stimulus controller</h1>
<p>To keep this example simple, we’re going to create a single controller which we’ll attach to the <code class="highlighter-rouge">body</code> tag in the main layout. This controller will be responsible for rendering the Font Awesome icons (as described in a <a href="/2018/01/using-font-awesome-5-with-rails-5-turbolinks.html">previous post</a>) as well as handling our Bulma burger menu.</p>
<p>Create <code class="highlighter-rouge">app/javascript/Controllers/main_controller.js</code>:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">fontawesome</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@fortawesome/fontawesome</span><span class="dl">'</span>
<span class="k">import</span> <span class="nx">icons</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@fortawesome/fontawesome-free-regular</span><span class="dl">'</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">Controller</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">stimulus</span><span class="dl">'</span>
<span class="k">export</span> <span class="k">default</span> <span class="kd">class</span> <span class="kd">extends</span> <span class="nx">Controller</span> <span class="p">{</span>
<span class="nx">initialize</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">fontawesome</span><span class="p">.</span><span class="nx">library</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">icons</span><span class="p">)</span>
<span class="p">}</span>
<span class="nx">connect</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">fontawesome</span><span class="p">.</span><span class="nx">dom</span><span class="p">.</span><span class="nx">i2svg</span><span class="p">()</span>
<span class="c1">// Get all "navbar-burger" elements</span>
<span class="kd">var</span> <span class="nx">$navbarBurgers</span> <span class="o">=</span> <span class="nb">Array</span><span class="p">.</span><span class="nx">prototype</span><span class="p">.</span><span class="nx">slice</span><span class="p">.</span><span class="nx">call</span><span class="p">(</span><span class="nb">document</span><span class="p">.</span><span class="nx">querySelectorAll</span><span class="p">(</span><span class="dl">'</span><span class="s1">.navbar-burger</span><span class="dl">'</span><span class="p">),</span> <span class="mi">0</span><span class="p">);</span>
<span class="c1">// Check if there are any navbar burgers</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">$navbarBurgers</span><span class="p">.</span><span class="nx">length</span> <span class="o">></span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// Add a click event on each of them</span>
<span class="nx">$navbarBurgers</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">$el</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">$el</span><span class="p">.</span><span class="nx">addEventListener</span><span class="p">(</span><span class="dl">'</span><span class="s1">click</span><span class="dl">'</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="c1">// Get the target from the "data-target" attribute</span>
<span class="kd">var</span> <span class="nx">target</span> <span class="o">=</span> <span class="nx">$el</span><span class="p">.</span><span class="nx">dataset</span><span class="p">.</span><span class="nx">target</span><span class="p">;</span>
<span class="kd">var</span> <span class="nx">$target</span> <span class="o">=</span> <span class="nb">document</span><span class="p">.</span><span class="nx">getElementById</span><span class="p">(</span><span class="nx">target</span><span class="p">);</span>
<span class="c1">// Toggle the class on both the "navbar-burger" and the "navbar-menu"</span>
<span class="nx">$el</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">toggle</span><span class="p">(</span><span class="dl">'</span><span class="s1">is-active</span><span class="dl">'</span><span class="p">);</span>
<span class="nx">$target</span><span class="p">.</span><span class="nx">classList</span><span class="p">.</span><span class="nx">toggle</span><span class="p">(</span><span class="dl">'</span><span class="s1">is-active</span><span class="dl">'</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This controller imports the icons from Font Awesome when <code class="highlighter-rouge">initialize</code> is called. Everytime connect is called it renders the icons and then searches for navbar burgers to attach the appropriate click events on.</p>
<h1 id="connect-the-controller">Connect the controller</h1>
<p>Now we want to connect the body tag to our controller using an HTML5 data attribute.</p>
<p>Open <code class="highlighter-rouge">app/views/layouts/application.html.erb</code> and add the following attribute to the <code class="highlighter-rouge"><body></code> tag.</p>
<div class="language-erb highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><body</span> <span class="na">data-controller=</span><span class="s">"main"</span><span class="nt">></span>
</code></pre></div></div>
<h1 id="testing">Testing</h1>
<p>Run your rails app and you should see the simple site with a navbar across the top:</p>
<p><img src="https://michael.minton.io/assets/Screen Shot 2018-06-10 at 4.33.28 PM.png" alt="" /></p>
<p>Now try shrinking the window until the menus are hidden and replaced with the burger menu. Notice when you click it, the menus reappear:</p>
<p><img src="https://michael.minton.io/assets/Screen Shot 2018-06-10 at 4.33.46 PM.png" alt="" /></p>
<h3 id="you-now-have-a-rails-5-app-with-turbolinks-stimulus-and-font-awesome-5-">You now have a Rails 5 app with Turbolinks, Stimulus, and Font Awesome 5. 🥑🍞</h3>Michael MintonI recently had the opportunity to start fresh with a new Rails app. Instead of building another traditional Rails app I took this chance to investigate using some modern tools like Webpacker and a modern CSS framework Bulma. In this post I’ll explain how I got everything wired together.font awesome 5 with turbolinks and stimulus2018-06-08T01:55:54+00:002018-06-08T01:55:54+00:00https://michael.minton.io/2018/06/font-awesome-5-with-turbolinks-and-stimulus<p>In a <a href="/2018/01/using-font-awesome-5-with-rails-5-turbolinks.html">previous post</a> I wrote about how to use <a href="https://fontawesome.com">Font Awesome 5</a>’s with <a href="https://github.com/turbolinks/turbolinks">Turbolinks</a>. Some of you have asked how you might do something similar but using <a href="https://stimulusjs.org">Stimulus</a> instead of coffeescript. Recently I started a new Rails app using webpacker and stimulus. Here are the steps I used to get this setup working with Font Awesome 5.</p>
<h1 id="the-rails-app">The Rails app</h1>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rails new myapp --webpack=stimulus
</code></pre></div></div>
<h1 id="setting-up-font-awesome-5">Setting up Font Awesome 5</h1>
<p>One of the great things about using FA5 via JS is the ability to only import the icons you’ll actually be using. In this case I only needed the twitter icon.</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>yarn add @fortawesome/fontawesome
yarn add @fortawesome/fontawesome-free-brands
</code></pre></div></div>
<h1 id="create-a-stimulus-controller">Create a Stimulus controller</h1>
<p>We’re going to create a controller which we’ll attach the <code class="highlighter-rouge">body</code> tag in the main layout. This controller will be responsible for importing the needed icons and for telling Font Awesome when they need to be rendered.</p>
<p><em>Create <code class="highlighter-rouge">app/Javascript/Controllers/fa_controller.js</code></em></p>
<div class="language-js highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">import</span> <span class="nx">fontawesome</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@fortawesome/fontawesome</span><span class="dl">'</span>
<span class="k">import</span> <span class="nx">faTwitter</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">@fortawesome/fontawesome-free-brands/faTwitter</span><span class="dl">'</span>
<span class="k">import</span> <span class="p">{</span> <span class="nx">Controller</span> <span class="p">}</span> <span class="k">from</span> <span class="dl">'</span><span class="s1">stimulus</span><span class="dl">'</span>
<span class="k">export</span> <span class="k">default</span> <span class="kd">class</span> <span class="kd">extends</span> <span class="nx">Controller</span> <span class="p">{</span>
<span class="nx">initialize</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">fontawesome</span><span class="p">.</span><span class="nx">library</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">faTwitter</span><span class="p">)</span>
<span class="p">}</span>
<span class="nx">connect</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">fontawesome</span><span class="p">.</span><span class="nx">dom</span><span class="p">.</span><span class="nx">i2svg</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="connect-the-controller">Connect the controller</h1>
<p>Now we want to connect the body tag to our controller using an HTML5 data attribute (i.e., <code class="highlighter-rouge"><body data-controller='fa'></code>) like so:</p>
<p><em><code class="highlighter-rouge">app/views/layouts/application.html.haml</code></em></p>
<div class="language-haml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt">%body</span><span class="p">{</span> <span class="ss">data: </span><span class="p">{</span><span class="ss">controller: </span><span class="s1">'fa'</span> <span class="p">}}</span>
</code></pre></div></div>
<p><em>I’m a big fan of <a href="http://haml.info">Haml</a> so this is my layout but yours may be <code class="highlighter-rouge">application.html.erb</code>.</em></p>
<h1 id="done">Done</h1>
<p>You now have a Rails 5 app with Turbolinks, Stimulus, and Font Awesome 5. 🥑🍞</p>Michael MintonIn a previous post I wrote about how to use Font Awesome 5’s with Turbolinks. Some of you have asked how you might do something similar but using Stimulus instead of coffeescript. Recently I started a new Rails app using webpacker and stimulus. Here are the steps I used to get this setup working with Font Awesome 5.using font awesome 5 with turbolinks2018-01-28T01:03:54+00:002018-01-28T01:03:54+00:00https://michael.minton.io/2018/01/using-font-awesome-5-with-rails-5-turbolinks<p><a href="https://fontawesome.com">Font Awesome 5</a>’s SVG with JS is slick and modern. It uses javascript to find all the <code class="highlighter-rouge"><i></code> tags with icons (e.g., <code class="highlighter-rouge">fas fa-camera</code>) and replaces them with an <code class="highlighter-rouge"><svg></code> tag. The best part is the SVG icons will respect all your CSS styles like <code class="highlighter-rouge">size</code> and <code class="highlighter-rouge">color</code>. Truly <em>awesome</em> stuff. However, there is a problem. Out of the box this won’t play nice with Rails 5 and <a href="https://github.com/turbolinks/turbolinks">Turbolinks</a>. What will happen is the initial page load will correctly show the icons but after clicking a link Turbolinks will reload the page but not your icons. In this article I’ll walk you through a few steps to fix this.</p>
<h1 id="setting-up-font-awesome-5">Setting up Font Awesome 5</h1>
<p><em>These instructions are current as of v5.0.6. Check <a href="https://fontawesome.com">https://fontawesome.com/get-started</a> for the latest instructions.</em></p>
<p>In your <code class="highlighter-rouge">application.html.erb</code> inside the <code class="highlighter-rouge"><head></code> tag include a link to Font Awesome from their free CDN.</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><head></span>
...
<span class="nt"><</span><span class="err">%=</span> <span class="na">javascript_include_tag</span> <span class="err">'</span><span class="na">application</span><span class="err">',</span> <span class="err">'</span><span class="na">data-turbolinks-track</span><span class="err">'</span><span class="na">:</span> <span class="err">'</span><span class="na">reload</span><span class="err">'</span> <span class="err">%</span><span class="nt">></span>
<span class="nt"><script </span><span class="na">defer</span> <span class="na">src=</span><span class="s">"https://use.fontawesome.com/releases/v5.0.6/js/all.js"</span><span class="nt">></script></span>
<span class="nt"></head></span>
</code></pre></div></div>
<h1 id="create-an-init-script">Create an init script</h1>
<p>We’re going to create a small script to call into Font Awesome’s API and force it to re-render the icons everytime the <code class="highlighter-rouge">turbolinks:load</code> event fires.</p>
<p>Create a new file called <code class="highlighter-rouge">fontawesome-init.coffee</code> in <code class="highlighter-rouge">app/assets/javascripts/</code> with the following:</p>
<div class="language-coffeescript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">$</span><span class="p">(</span><span class="nb">document</span><span class="p">).</span><span class="na">on</span> <span class="s">"turbolinks:load"</span><span class="p">,</span> <span class="o">-></span>
<span class="nx">FontAwesome</span><span class="p">.</span><span class="na">dom</span><span class="p">.</span><span class="na">i2svg</span><span class="p">()</span>
</code></pre></div></div>
<p><strong>Important!</strong></p>
<p>If your <code class="highlighter-rouge">application.js</code> doesn’t have <code class="highlighter-rouge">//= require_tree .</code> then you’ll need to add <code class="highlighter-rouge">//= require fontawesome-init</code>.</p>
<h1 id="prevent-layout-shifting">Prevent layout shifting</h1>
<p>While optional, this next step will prevent your layout from constantly resizing as the intial view is loaded and the icons are being rendered. Font Awesome 5 adds the <code class="highlighter-rouge">fontawesome-i2svg-pending</code> class to the <code class="highlighter-rouge"><span class="nt"><html></span></code> tag while it’s rendering icons. Using a variant of the instructions <a href="https://fontawesome.com/how-to-use/performance-and-security#async-loading-indicators">here</a>, we can take advantage of this and hide the <code class="highlighter-rouge"><body></code> tag until the icons are rendered and that class is removed.</p>
<p>Add the following to your <code class="highlighter-rouge">application.scss</code>:</p>
<div class="language-css highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nc">.fontawesome-i2svg-pending</span> <span class="nt">body</span> <span class="p">{</span>
<span class="nl">display</span><span class="p">:</span> <span class="nb">none</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>You now have Rails 5 with Turbolinks working with Font Awesome 5’s SVG with JS approach. 🍰</p>Michael MintonFont Awesome 5’s SVG with JS is slick and modern. It uses javascript to find all the <i> tags with icons (e.g., fas fa-camera) and replaces them with an <svg> tag. The best part is the SVG icons will respect all your CSS styles like size and color. Truly awesome stuff. However, there is a problem. Out of the box this won’t play nice with Rails 5 and Turbolinks. What will happen is the initial page load will correctly show the icons but after clicking a link Turbolinks will reload the page but not your icons. In this article I’ll walk you through a few steps to fix this.how to tmux2017-12-04T21:03:54+00:002017-12-04T21:03:54+00:00https://michael.minton.io/2017/12/how-to-tmux<p><a href="http://https://github.com/tmux/tmux">tmux</a> is a terminal multiplexer which is a fancy way to say it allows multiple
“windows” in a single terminal. It’s essential to my workflow. This post will
only touch on the basics to get you up and running.</p>
<h1 id="install">Install</h1>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ brew install tmux
</code></pre></div></div>
<p><em>Using Windows?</em> See <a href="https://leanpub.com/the-tao-of-tmux/read#appendix-windows-bash">here</a>.</p>
<h1 id="the-basics">The Basics</h1>
<p><strong>Start it up</strong></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>$ tmux
</code></pre></div></div>
<p><strong>The leader</strong></p>
<p>To use any of the commands you have to type the leader prefix followed by your
specific command. The default is <kbd>CTRL + B</kbd>. To save space I’ll show
the prefix as <kbd>PX</kbd>.</p>
<p><strong>Creating windows</strong></p>
<p><kbd>PX</kbd> + <kbd>c</kbd></p>
<p>tmux starts with a window created by default but we can open multiple within
the same session. The windows are numbers starting at zero.</p>
<p><strong>Switching windows</strong></p>
<p><kbd>PX</kbd> + <kbd>0</kbd></p>
<p>The above would switch to window zero. At the bottom in the status bar you’ll
see each window listed. The active window is indicated with an asterisk.</p>
<p><strong>Creating panes</strong></p>
<p><kbd>PX</kbd> + <kbd>%</kbd> Vertical split<br />
<kbd>PX</kbd> + <kbd>""</kbd> Horizontal split</p>
<p>Windows a kind of useless to me. I much prefer to just split a single window
into multiple panes and keep everything in sight.</p>
<p><strong>Switching panes</strong></p>
<p><kbd>PX</kbd> + <kbd>;</kbd></p>
<p>This will cycle from one pane to the next within the same window. Instead of <code class="highlighter-rouge">;</code>
you can also use the arrow keys.</p>
<p><strong>Resizing panes</strong></p>
<p>Resizing is so awkward I usually go into command mode for this.</p>
<p><kbd>PX</kbd> + <kbd>:</kbd></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>: resize-windows -L
</code></pre></div></div>
<p><code class="highlighter-rouge">L</code> indicates the direction: left. You can also specify <code class="highlighter-rouge">U</code>, <code class="highlighter-rouge">D</code>, and <code class="highlighter-rouge">R</code> for
the other four directions. Repeat this command as needed.</p>
<p><strong>Detach</strong></p>
<p><kbd>PX</kbd> + <kbd>d</kbd></p>
<p>This will detach the session, close tmux, <em>but leave your session running in
the background</em>.</p>
<h1 id="customize">Customize</h1>
<p><strong>vim copy and paste</strong></p>
<p>You can get lost for weeks configuring this stuff but here is a basic setup
that’ll let you copy and paste like you do in <a href="http://www.vim.org/">vim</a>. The config is
here: <code class="highlighter-rouge">~/.tmux.conf</code></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>set-window-option -g mode-keys vi
bind-key -t vi-copy 'v' begin-selection
bind-key -t vi-copy 'y' copy-selection
</code></pre></div></div>
<p><strong>Disable the mouse</strong></p>
<p>The prevent accidental scrolling and trashing your tmux session I recommend you
immediately disable the mouse.</p>
<p><kbd>PX</kbd> + <kbd>:</kbd></p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>: setw -g mode-mouse off
</code></pre></div></div>
<h1 id="advanced">Advanced</h1>
<p>I haven’t really even scratch the surface. After you’ve been using tmux
for a while you’ll want to customze your status bar and start messing with
powerlines glyphs. To learn how to do that and get a cooler setup I recommend
you read <a href="https://pragprog.com/book/bhtmux2/tmux-2"><strong>tmux 2</strong> <em>Productive Mouse-Free Development</em></a>.</p>Michael Mintontmux is a terminal multiplexer which is a fancy way to say it allows multiple “windows” in a single terminal. It’s essential to my workflow. This post will only touch on the basics to get you up and running.cleaning house2017-11-27T20:03:54+00:002017-11-27T20:03:54+00:00https://michael.minton.io/2017/11/cleaning-house<p>I’m re-purposing this blog toward the pragmatic. To that end I’ve deleted a ton
of posts that didn’t meet the new criteria. I want my posts to be useful. They
should impart some knowledge, practical advice, or hard-learned lessons. There
is already too much junk on the internet and this blog wasn’t helping. I want
this to be a useful resource for my future self and hopefully anyone else who
accidentally stumbles across it.</p>
<p>I will still write about things I find interesting but my aim will always be to
keep things useful. I do expect to be posting less rants and more tutorials,
guides, and stories I think are worth sharing. I will do my best to avoid any
politics or drifting into heated narratives.</p>Michael MintonI’m re-purposing this blog toward the pragmatic. To that end I’ve deleted a ton of posts that didn’t meet the new criteria. I want my posts to be useful. They should impart some knowledge, practical advice, or hard-learned lessons. There is already too much junk on the internet and this blog wasn’t helping. I want this to be a useful resource for my future self and hopefully anyone else who accidentally stumbles across it.rails on high sierra2017-11-21T10:03:54+00:002017-11-21T10:03:54+00:00https://michael.minton.io/2017/11/rails-on-high-sierra<p>This post will walk you through the process I used to get my machine setup for
rails development on macOS High Sierra. We’ll start by performing a clean
install of High Sierra to avoid any upgrade rust. Afterward we’ll install the
development tools and some useful utilities. Enjoy!</p>
<h1 id="install-high-sierra">Install High Sierra</h1>
<h3 id="️-backup-your-data-before-following-these-steps">⚠️ Backup your data BEFORE following these steps!</h3>
<p><strong>In order to complete this section you’ll need access to a 16+GB thumb drive.
You’ll also want to print this or open it on another device before you start.</strong></p>
<h3 id="get-the-installer">Get the installer</h3>
<p>Download <a href="https://itunes.apple.com/us/app/macos-high-sierra/id1246284741">High Sierra</a> from the AppStore. Quit the installer when it launches.</p>
<h3 id="create-a-bootable-image">Create a bootable image</h3>
<p><strong>In the command below I’ve used the name of my USB drive which is <code class="highlighter-rouge">TINY</code>. It is
likely that your drive has a different name so update the command accordingly.</strong></p>
<p>Open terminal and run the following command</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo</span> /Applications/Install<span class="se">\ </span>macOS<span class="se">\ </span>High<span class="se">\ </span>Sierra.app/Contents/Resources/createinstallmedia <span class="nt">--volume</span> /Volumes/TINY
</code></pre></div></div>
<p>This command took about 14 minutes to complete on my machine.</p>
<h3 id="erase-and-install">Erase and Install</h3>
<p><strong>⚠️ Last Warning! Be sure you have a backup before erasing your data!</strong></p>
<p>Reboot your Mac and when it’s turning back on hold down <kbd>⌘ + R</kbd> until
you see the Apple logo. Eventually <strong>macOS Utilities</strong> will open. Select <strong>Disk
Utility</strong>. On the left you’ll see a list of drives. Select your hard drive (e.g.,
<strong>Macintosh HD</strong>) and from the top toolbar select <strong>Erase</strong>. Once the erase has
finished, quit <strong>Disk Utility</strong>.</p>
<p>You should be taken back to the <strong>macOS Utilities</strong> screen. Select <strong>Install
macOS</strong>, selected your hard drive and follow the wizard.</p>
<h1 id="install-useful-utilities">Install Useful utilities</h1>
<h3 id="homebrew">Homebrew</h3>
<p><em>https://brew.sh/</em></p>
<p>This is the “<em>missing package manager for macOS</em>” and we’ll use it to install
most of the other stuff.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>/usr/bin/ruby <span class="nt">-e</span> <span class="s2">"</span><span class="si">$(</span>curl <span class="nt">-fsSL</span> https://raw.githubusercontent.com/Homebrew/install/master/install<span class="si">)</span><span class="s2">"</span>
</code></pre></div></div>
<p>Install some dev packages:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>coreutils automake autoconf openssl libyaml readline libxslt libtool unixodbc
</code></pre></div></div>
<h3 id="cask">Cask</h3>
<p><em>https://caskroom.github.io</em></p>
<p>This allows us to lean on Homebrew to install applications for us.</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew tap caskroom/cask
</code></pre></div></div>
<p>Install the following:</p>
<ul>
<li>Google Chrome <code class="highlighter-rouge">brew cask install google-chrome</code></li>
<li>iterm2 <code class="highlighter-rouge">brew cask install iterm2</code></li>
<li>atom - <code class="highlighter-rouge">brew cask install atom</code></li>
</ul>
<h3 id="asdf">asdf</h3>
<p><em>https://github.com/asdf-vm/asdf</em></p>
<p>This is a version manager much like <a href="https://github.com/rbenv/rbenv">rbenv</a> but not limited to ruby.</p>
<p><em>v0.4.0 was the latest as of this writing. This also assumes your just using
Bash.</em></p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>git clone https://github.com/asdf-vm/asdf.git ~/.asdf <span class="nt">--branch</span> v0.4.0
<span class="nb">echo</span> <span class="nt">-e</span> <span class="s1">'\n. $HOME/.asdf/asdf.sh'</span> <span class="o">>></span> ~/.bash_profile
<span class="nb">echo</span> <span class="nt">-e</span> <span class="s1">'\n. $HOME/.asdf/completions/asdf.bash'</span> <span class="o">>></span> ~/.bash_profile
</code></pre></div></div>
<p>You may have to restart your shell before proceeding.</p>
<p>Install the ruby plugin:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>asdf plugin-add ruby
</code></pre></div></div>
<h1 id="install-ruby">Install Ruby</h1>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>asdf <span class="nb">install </span>ruby 2.4.2
asdf global ruby 2.4.2
</code></pre></div></div>
<h1 id="install-rails">Install Rails</h1>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>gem <span class="nb">install </span>rails <span class="nt">-v</span> 5.1.4
</code></pre></div></div>
<h1 id="install-postgres">Install Postgres</h1>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>brew <span class="nb">install </span>postgresql
brew services start postgresql
</code></pre></div></div>Michael MintonThis post will walk you through the process I used to get my machine setup for rails development on macOS High Sierra. We’ll start by performing a clean install of High Sierra to avoid any upgrade rust. Afterward we’ll install the development tools and some useful utilities. Enjoy!backing up a fusion vm2017-06-19T16:43:45+00:002017-06-19T16:43:45+00:00https://michael.minton.io/2017/06/backing-up-a-fusion-vm<p>Often I want to store a VMware Fusion Virtual Machine on Dropbox, either for backup purposes or to share with others. Since the VM itself, despite macOS treating it as a single file, is actually a folder with a ton of files burried inside. Trying to upload or download all these tiny files to Dropbox takes forever. The answer is to first convert the VM into a <a href="https://www.dmtf.org/standards/ovf">OVA</a>.</p>
<h1 id="what-is-an-ova">What is an OVA?</h1>
<p>An OVA is an Open Virtual Appliance, which is really just a OVF (Open Virtualization Format) stored in a <a href="https://en.wikipedia.org/wiki/Tar_(computing)">TAR</a> file. The benefit of this is a single, compressed file that can be transferred around a bit easier.</p>
<h1 id="creating-the-ova">Creating the OVA</h1>
<h3 id="1-locate-your-vmdk-file">1. Locate your .vmdk file</h3>
<p>In the Virtual Machine Library, right-click your VM and select Show in Finder. Right-click your <code class="highlighter-rouge">.vmwarevm</code> file and select Show Package Contents.
<img src="https://michael.minton.io/assets/20170619-vmwarevm.png" alt="package contents" /></p>
<p>Now find <code class="highlighter-rouge">Virtual Disk.vmdk</code>, there will be lots of <code class="highlighter-rouge">.vmdk</code> files but you want the “entry” one without a number.</p>
<h3 id="2-use-the-vmware-ovf-tool">2. Use the VMware OVF Tool</h3>
<p><em>If you have VMware Fusion Pro, you can simply choose to Export your VM using the GUI.</em></p>
<p>Open a terminal and navigate to <code class="highlighter-rouge">/Applications/VMware Fusion.app/Contents/Library/VMware OVF Tool</code>. <strong>Note</strong> <em>This path may change on different versions of Fusion. This is valid for 10.</em></p>
<p>Type the following into your terminal:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./ovftool --compress
</code></pre></div></div>
<p>Note the space after <code class="highlighter-rouge">--compress</code>.</p>
<p>Now drag the <code class="highlighter-rouge">Virtual Disk.vmdk</code> from Finder into your Terminal window. It should drop in the full path.</p>
<p>Add another space and then type the path where you’d like your <code class="highlighter-rouge">ova</code> file saved.</p>
<p>The final output should look similar like this:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>./ovftool --compress /Users/minton/Virtual\ Machines/Win10ProWS.vmwarevm/Virtual\ Disk.vmdk ~/backup.ova
</code></pre></div></div>
<p>This is going to save my OVA file into my Home folder as <code class="highlighter-rouge">backup.ova</code>. <strong>This may take a long time</strong> but the end result is a single file you can upload to Dropbox.</p>
<h1 id="importing-the-ova">Importing the OVA</h1>
<p>To import your OVA file, open the Virtual Machine Library and select File -> Import. Navigate to your OVA file and you’re done.</p>Michael MintonOften I want to store a VMware Fusion Virtual Machine on Dropbox, either for backup purposes or to share with others. Since the VM itself, despite macOS treating it as a single file, is actually a folder with a ton of files burried inside. Trying to upload or download all these tiny files to Dropbox takes forever. The answer is to first convert the VM into a OVA.