Jekyll2024-01-24T21:28:38-06:00http://blog.edruder.com/feed.xmledruder.commy stuffToday I Learned How to Keep Christmas Tree Lights Working Forever2024-01-24T00:00:00-06:002024-01-24T00:00:00-06:00http://blog.edruder.com/2024/01/24/christmas-lights<p>I have been decorating Christmas trees with <strong>incandescent</strong> mini-lights almost
every year for many years. (<a href="https://www.youtube.com/watch?v=OSOxeP-GF4Q">LED lights are different.</a>)
Over that time, I’ve bought, maintained, and thrown away dozens of strands of
lights. I’m cheap, so I always try to repair a strand when some lights go out,
and I generally keep strands working for years. Eventually though, each strand
gets to a point where I can’t get it working in a reasonable time, and I throw
it away and buy a new one.</p>
<p>That is, until this year, when I learned how to keep Christmas tree lights going
virtually forever!</p>
<h3 id="get-a-lightkeeper-pro">Get a LightKeeper Pro</h3>
<p>A while ago, I discovered a great tool to keep tree lights working when a light
bulb or two goes out–the <a href="https://lightkeeperpro.com/home/">LightKeeper Pro</a> (LKP)! It’s a
super-useful tool–I think that everyone who lights a Christmas tree every year
should have one. It has several functions, but the one I use the most is the
<em>quick fix</em>–you plug your lights into the gun-shaped tool, pull the trigger
a few
times, and the section of your strand that was dark magically lights up!</p>
<p>It’s worth mentioning that most Christmas tree strands are composed of several
sections of lights that are connected together to make a longer string of
lights. For example, a 150-light string is actually made up of three 50-light
sections connected end-to-end. (There are strings of lights that are composed of
35-light sections, but I don’t have any of those. These suggestions still
apply.) When a bulb in one of the sections blows out, it will only affect its
own section of lights. That’s why most of a long string of lights will remain
working when one section goes dark. When I say “strand”, I mean one of these
50-(or 35-)light sections of a longer string of lights.</p>
<h3 id="the-lightkeeper-pro-isnt-enough">The LightKeeper Pro Isn’t Enough</h3>
<p>Using the LKP quick-fix alone doesn’t keep your lights going forever though. I
had some tree lights that had a bulb or two burn out every year or two and I’d
use the LKP to get them working again. But then the entire strand of light bulbs
blew out–every single bulb was blackened on the inside!</p>
<p>This year, as usual, the LKP fixed some of my lights before I put them up. After
I fixed them and put them up, we finished decorating the tree. The very next
day, a strand went out and the LKP didn’t help–all the bulbs were blown. Another
strand completely burned out the next day! While I’d seen this happen before
once or twice, this was the first time it happened to me after the tree was
completely decorated. We decided to live with the burned-out strands for the
duration of the season–removing the lights and ornaments, fixing the lights,
then putting up the lights and ornaments <em>again</em> would have been too much work.</p>
<p>As I chewed on this frustration, I decided to figure out what caused this, and
it didn’t take long to find out.</p>
<h3 id="replace-all-burned-out-bulbs">Replace All Burned Out Bulbs</h3>
<p>The short answer is that every season, before you put up your lights, <strong>replace
all the burned out bulbs</strong>. It turns out that as long as you start each season
with all of your mini light bulbs working, the LKP quick fix will keep you going
for the season.</p>
<p>You usually get a few replacement bulbs with each new strand. When you run
through those, you can buy mini light bulbs in bulk online or at many hardware
stores. (The number of bulbs in a strand determines the voltage of the bulbs you
need to buy–2.5V for 50-bulb, 3.5V for 35-bulb strands–make sure to get the
right ones.)</p>
<h3 id="how-this-works">How This Works</h3>
<p>If you just want to keep your lights working, you can stop reading. If you’re
curious <em>why</em> these suggestions work, here are the details.</p>
<h4 id="how-does-the-lightkeeper-pro-work">How Does The LightKeeper Pro Work?</h4>
<p>It’s not magic, of course. I learned that each bulb in a strand has a little
<em>shunt</em> built into it. The shunt’s job is to keep the rest of the bulbs in the
strand lit even when its bulb burns out. Usually the shunt just works–when a
bulb burns out, the shunt kicks in and the rest of the bulbs continue to work.
Fairly frequently though, a bulb’s shunt doesn’t work right away, and the entire
strand goes dark. That’s where the LKP comes in–plugging the strand into the
tool and pulling the trigger generates a jolt of electricity that causes the
reluctant shunts to start working, and the strand lights up!</p>
<h4 id="why-replace-all-the-dead-bulbs">Why Replace All The Dead Bulbs?</h4>
<p>If you just keep clicking the LKP to get your strands working every year, more
and more bulbs in each strand will be burnt out. Not very noticeable, but each
strand is getting closer and closer to catastrophe. Here’s what’s happening.</p>
<p>When a strand is new and every bulb is lit, there’s a certain amount of electric
current running through the strand. When one bulb burns out and its shunt kicks
in, the same amount of current is going through the strand, but it’s lighting
one fewer bulb. This causes each of the remaining bulbs to burn a <em>little</em>
brighter. When another bulb burns out, the remaining bulbs burn a little <em>more</em>
brightly. When a few more bulbs (5? or 6? <em>maybe</em> more?) have blown out, the
remaining bulbs are running as hot as they can. The next bulb to die sets off a
cascade of blown bulbs until every one is burned out.</p>
<p>A strand of lights can withstand a few dead bulbs, so just start the season off
with no dead bulbs and your season will be merry!</p>
<h3 id="the-lightkeeper-pro-is-even-better">The LightKeeper Pro Is Even Better!</h3>
<p>There are a few more ways that your strands can go dark and the LKP can help you
figure out the problem:</p>
<ul>
<li>Every string of lights has a little fuse in the plug which can blow–the LKP
has a fuse tester.</li>
<li>Sometimes, the wires at the base of a bulb can break. The LKP has a voltage
detector that can tell you where the bad bulb is.</li>
<li>The LKP has a bulb tester, too.</li>
</ul>
<h3 id="references">References</h3>
<ul>
<li><a href="https://lightkeeperpro.com/home/">LightKeeper Pro home page</a></li>
<li><a href="https://www.youtube.com/watch?v=EzbQCRkZKck">How to fix Christmas lights video</a></li>
<li><a href="https://www.youtube.com/watch?v=OSOxeP-GF4Q">How to fix LED Christmas lights video</a></li>
</ul>I have been decorating Christmas trees with incandescent mini-lights almost every year for many years. (LED lights are different.) Over that time, I’ve bought, maintained, and thrown away dozens of strands of lights. I’m cheap, so I always try to repair a strand when some lights go out, and I generally keep strands working for years. Eventually though, each strand gets to a point where I can’t get it working in a reasonable time, and I throw it away and buy a new one.Easy Property files for Bash scripts2020-09-13T00:00:00-05:002020-09-13T00:00:00-05:00http://blog.edruder.com/2020/09/13/easy-preferences-for-bash-scripts<p>Recently, I wanted to have a setting/preference to control an aspect of a Bash script. I considered
using an environment variable, but I wanted the preference to be able to be different based on the
directory that the script is run from—the “local” directory’s setting would override the
“global” setting.</p>
<p>I’ve used a hierarchy of YAML files from Java—but YAML is overkill and I just needed two
levels of hierarchy. A simple “properties file”, with settings in the local file overriding the
settings in the global file in the home directory, works. A properties file is a text file,
usually with a <code class="language-plaintext highlighter-rouge">.properties</code> extension, with one property per line, and each line looking like
this: <code class="language-plaintext highlighter-rouge">property=value</code>.</p>
<p>Searching online, I found <a href="https://fabianlee.org/2019/10/05/bash-setting-and-replacing-values-in-a-properties-file-use-sed/">a simple <code class="language-plaintext highlighter-rouge">sed</code> command</a> that nicely plucks specific properties from
a file. With that, I wrote a simple Bash function that returns the value of a property from a
properties file, looking first in the properties file in the directory where the script was
invoked, then in the properties file in the home directory.</p>
<p>Here’s the function:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>prop<span class="o">()</span> <span class="o">{</span>
<span class="nv">name</span><span class="o">=</span><span class="nv">$1</span>
<span class="nv">local_properties</span><span class="o">=</span><span class="s2">"</span><span class="si">$(</span><span class="nb">pwd</span><span class="si">)</span><span class="s2">"</span>/<span class="s2">"</span><span class="nv">$properties_filename</span><span class="s2">"</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nt">-f</span> <span class="s2">"</span><span class="nv">$local_properties</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">value</span><span class="o">=</span><span class="si">$(</span><span class="nb">sed</span> <span class="nt">-En</span> <span class="s2">"s/^</span><span class="nv">$name</span><span class="s2">=([^</span><span class="se">\n</span><span class="s2">]+)</span><span class="nv">$/</span><span class="se">\1</span><span class="s2">/p"</span> <span class="s2">"</span><span class="nv">$local_properties</span><span class="s2">"</span><span class="si">)</span>
<span class="k">fi
if</span> <span class="o">[[</span> <span class="nt">-z</span> <span class="s2">"</span><span class="nv">$value</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">global_properties</span><span class="o">=</span>~/<span class="s2">"</span><span class="nv">$properties_filename</span><span class="s2">"</span>
<span class="k">if</span> <span class="o">[[</span> <span class="nt">-f</span> <span class="s2">"</span><span class="nv">$global_properties</span><span class="s2">"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then
</span><span class="nv">value</span><span class="o">=</span><span class="si">$(</span><span class="nb">sed</span> <span class="nt">-En</span> <span class="s2">"s/^</span><span class="nv">$name</span><span class="s2">=([^</span><span class="se">\n</span><span class="s2">]+)</span><span class="nv">$/</span><span class="se">\1</span><span class="s2">/p"</span> <span class="s2">"</span><span class="nv">$global_properties</span><span class="s2">"</span><span class="si">)</span>
<span class="k">fi
fi
</span><span class="nb">echo</span> <span class="s2">"</span><span class="nv">$value</span><span class="s2">"</span>
<span class="o">}</span>
</code></pre></div></div>
<p>The function expects the variable <code class="language-plaintext highlighter-rouge">properties_filename</code> to be defined.</p>
<p>It’s invoked like this:</p>
<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="o">[[</span> <span class="s2">"</span><span class="si">$(</span>prop <span class="s1">'allow_something'</span><span class="si">)</span><span class="s2">"</span> <span class="o">==</span> <span class="s2">"true"</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
<span class="c"># do something</span>
<span class="k">fi</span>
</code></pre></div></div>
<p>Note:</p>
<ul>
<li>This is on macOS, which has slightly different syntax for the <code class="language-plaintext highlighter-rouge">sed</code> options than is described in
the original article (macOS: <code class="language-plaintext highlighter-rouge">-En</code> vs. Linux: <code class="language-plaintext highlighter-rouge">-rn</code>).</li>
<li>The function interprets an “empty” value as “no property is defined”, so you probably don’t want
to define a property without a value (i.e., <code class="language-plaintext highlighter-rouge">property=</code>).</li>
<li>I usually make my preferences files invisible.</li>
<li>I usually don’t commit my preferences files to source control.</li>
</ul>Recently, I wanted to have a setting/preference to control an aspect of a Bash script. I considered using an environment variable, but I wanted the preference to be able to be different based on the directory that the script is run from—the “local” directory’s setting would override the “global” setting.Using a Bootstrap DateTime Picker in Simple Form and Rails 5.12018-01-27T00:00:00-06:002018-01-27T00:00:00-06:00http://blog.edruder.com/2018/01/27/bootstrap-date-time-picker-in-simple-form<p>I’m using <a href="https://getbootstrap.com/">Bootstrap</a> to make the pages of my Rails app look halfway
decent–I’m a programmer who’s creatively challenged. (I can already feel the
scorn from my designer friends, but hey–I actually like how Bootstrap looks!)
I’m also using <a href="https://github.com/plataformatec/simple_form">Simple Form</a> to clean up the HTML forms in my app.</p>
<p>In one of my forms, the user needs to choose a date & time, and the default way
to enter a date & time in Rails is horrendously ugly, even to my soulless, dead
eyes. A little Googling for ‘bootstrap datetime picker rails’ landed me on the
<a href="https://github.com/TrevorS/bootstrap3-datetimepicker-rails">bootstrap3-datetimepicker-rails</a> gem page. This gem
just wraps the <a href="https://eonasdan.github.io/bootstrap-datetimepicker/">bootstrap-datetime-picker</a>, whose minimal
setup looked perfectly suitable to me. Piece of cake, I thought!</p>
<p>It was straightforward to install and configure the gem using the instructions
on <a href="https://github.com/TrevorS/bootstrap3-datetimepicker-rails">its home page</a>. The hard part was trying to figure
out how to use the picker in my Simple Form form.</p>
<p>The <code class="language-plaintext highlighter-rouge">bootstrap-datetime-picker</code> <a href="https://eonasdan.github.io/bootstrap-datetimepicker/">home page</a> describes the
markup that renders the picker. From the top of that page, this is what I
wanted Simple Form to output:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"form-group"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"input-group date"</span> <span class="na">id=</span><span class="s">"datetimepicker1"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">type=</span><span class="s">"text"</span> <span class="na">class=</span><span class="s">"form-control"</span> <span class="nt">/></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"glyphicon glyphicon-calendar"</span><span class="nt">></span></span>
<span class="nt"></span></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>(There is some markup wrapping this, but this is the part that is important.)</p>
<p>I read the (very complete!) <a href="https://github.com/plataformatec/simple_form">Simple Form documentation</a>, but I
didn’t see how to specify a stock Simple Form field that would result in
something resembling the markup above. I read several of the <a href="https://github.com/plataformatec/simple_form/wiki/Adding-custom-components">Simple
Form</a> <a href="https://github.com/plataformatec/simple_form/wiki/Adding-custom-input-components">wiki</a> <a href="https://github.com/plataformatec/simple_form/wiki/Bootstrap-component-helpers">pages</a> about
building custom input components, and I decided that that’s what I needed to
create to get the markup that would render the datetime picker properly.</p>
<p>Unfortunately, that documentation didn’t get me to the point where I knew how
to write the custom component, but with that and <a href="http://arjanvandergaag.nl/blog/simpleform-custom-inputs.html">several</a>
<a href="https://jeremysmith.co/posts/2015-12-09-custom-currency-input-for-simple-form/">other</a> <a href="https://www.foraker.com/blog/create-reusable-custom-simple-form-inputs">examples</a> I found online, my mental
picture of what I needed to do became clearer. I didn’t find a good
soup-to-nuts description of how to build a custom input component, starting
with the markup you want, but I figured I could dive in and figure it out.</p>
<h3 id="a-solution">A Solution</h3>
<h4 id="first-the-markup">First, the Markup</h4>
<p>I have the markup I’m aiming for (above). Here’s the Simple Form field that I
think should create it (<code class="language-plaintext highlighter-rouge">published_at</code> is the Active Record datetime field
to be created/edited):</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="o"><</span><span class="sx">%= f.input :published_at, as: :date_time_picker %>
</span></code></pre></div></div>
<p>I started with a shell of a custom input component, from the <a href="https://github.com/plataformatec/simple_form#custom-inputs">Custom inputs
section</a> of the Simple Form documentation. If you put
the file in the <code class="language-plaintext highlighter-rouge">app/inputs</code> directory (which is Simple Form-specific–you’ll
probably need to create it) and restart your server, Simple Form will pick it
up:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/inputs/date_time_picker_input.rb</span>
<span class="k">class</span> <span class="nc">DateTimePickerInput</span> <span class="o"><</span> <span class="no">SimpleForm</span><span class="o">::</span><span class="no">Inputs</span><span class="o">::</span><span class="no">Base</span>
<span class="k">def</span> <span class="nf">input</span><span class="p">(</span><span class="n">wrapper_options</span><span class="p">)</span>
<span class="n">merged_input_options</span> <span class="o">=</span> <span class="n">merge_wrapper_options</span><span class="p">(</span><span class="n">input_html_options</span><span class="p">,</span> <span class="n">wrapper_options</span><span class="p">)</span>
<span class="vi">@builder</span><span class="p">.</span><span class="nf">text_field</span><span class="p">(</span><span class="n">attribute_name</span><span class="p">,</span> <span class="n">merged_input_options</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Looking at the markup I’m shooting for, I’m going to need a <code class="language-plaintext highlighter-rouge">text</code> input, and
I’m guessing that’s what <code class="language-plaintext highlighter-rouge">@builder.text_field</code> is going to create, so let’s
just try it out! When I restart my server and render a form using a this custom
input component (using exactly the <code class="language-plaintext highlighter-rouge">f.input</code> line, above), this is the HTML
that’s rendered:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"form-group date_time_picker required content_published_at"</span><span class="nt">></span>
<span class="nt"><label</span> <span class="na">class=</span><span class="s">"control-label date_time_picker required"</span> <span class="na">for=</span><span class="s">"content_published_at"</span><span class="nt">></span>
Published at
<span class="nt"></label></span>
<span class="nt"><input</span> <span class="na">class=</span><span class="s">"form-control date_time_picker required"</span>
<span class="na">type=</span><span class="s">"text"</span>
<span class="na">value=</span><span class="s">"2018-01-01 23:38:00 UTC"</span>
<span class="na">name=</span><span class="s">"content[published_at]"</span>
<span class="na">id=</span><span class="s">"content_published_at"</span> <span class="nt">/></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>Not a bad start! It looks like Simple Form will generate a <code class="language-plaintext highlighter-rouge">label</code> by default,
and I don’t want one. Poking around in the documentation and examples, I see
that there is a <code class="language-plaintext highlighter-rouge">label</code> method that I can define to customize the <code class="language-plaintext highlighter-rouge">label</code> tag
of this component. What if I define one that returns nothing?</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/inputs/date_time_picker_input.rb</span>
<span class="k">class</span> <span class="nc">DateTimePickerInput</span> <span class="o"><</span> <span class="no">SimpleForm</span><span class="o">::</span><span class="no">Inputs</span><span class="o">::</span><span class="no">Base</span>
<span class="k">def</span> <span class="nf">input</span><span class="p">(</span><span class="n">wrapper_options</span><span class="p">)</span>
<span class="n">merged_input_options</span> <span class="o">=</span> <span class="n">merge_wrapper_options</span><span class="p">(</span><span class="n">input_html_options</span><span class="p">,</span> <span class="n">wrapper_options</span><span class="p">)</span>
<span class="vi">@builder</span><span class="p">.</span><span class="nf">text_field</span><span class="p">(</span><span class="n">attribute_name</span><span class="p">,</span> <span class="n">merged_input_options</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">label</span><span class="p">(</span><span class="n">_</span><span class="p">);</span> <span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>And its output:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"form-group date_time_picker required content_published_at"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">class=</span><span class="s">"form-control date_time_picker required"</span>
<span class="na">type=</span><span class="s">"text"</span>
<span class="na">value=</span><span class="s">"2018-01-01 23:38:00 UTC"</span>
<span class="na">name=</span><span class="s">"content[published_at]"</span>
<span class="na">id=</span><span class="s">"content_published_at"</span> <span class="nt">/></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>Bingo! (The <code class="language-plaintext highlighter-rouge">_</code> parameter is there because the <code class="language-plaintext highlighter-rouge">label</code> method requires one
parameter, but we aren’t using it and don’t care about it. This is a Ruby
convention that’s pretty handy.) Moving on…</p>
<p>I see that the outer <code class="language-plaintext highlighter-rouge">div</code> with a class of <code class="language-plaintext highlighter-rouge">form-group</code> is already there
without me having to do anything. We can ignore the other classes on that outer
<code class="language-plaintext highlighter-rouge">div</code>, but you can see the name of our component there, the model name/field
name (<code class="language-plaintext highlighter-rouge">content_published_at</code>) that Rails wants, etc.</p>
<p>Comparing the HTML to the exemplar, the <code class="language-plaintext highlighter-rouge">input</code> needs to be wrapped in a <code class="language-plaintext highlighter-rouge">div</code>.
From some of the examples I saw in the documentation and elsewhere, I can wrap
a div around the input using <code class="language-plaintext highlighter-rouge">template.content_tag(:div)</code>. Let’s give that a
shot in the <code class="language-plaintext highlighter-rouge">input</code> method:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/inputs/date_time_picker_input.rb</span>
<span class="k">def</span> <span class="nf">input</span><span class="p">(</span><span class="n">wrapper_options</span><span class="p">)</span>
<span class="n">merged_input_options</span> <span class="o">=</span> <span class="n">merge_wrapper_options</span><span class="p">(</span><span class="n">input_html_options</span><span class="p">,</span> <span class="n">wrapper_options</span><span class="p">)</span>
<span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:div</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'input-group date'</span><span class="p">,</span> <span class="ss">id: </span><span class="s1">'datetimepicker1'</span><span class="p">)</span> <span class="k">do</span>
<span class="vi">@builder</span><span class="p">.</span><span class="nf">text_field</span><span class="p">(</span><span class="n">attribute_name</span><span class="p">,</span> <span class="n">merged_input_options</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Here’s the HTML that’s generated:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"form-group date_time_picker required content_published_at"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"input-group date"</span> <span class="na">id=</span><span class="s">"datetimepicker1"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">class=</span><span class="s">"form-control date_time_picker required"</span>
<span class="na">type=</span><span class="s">"text"</span>
<span class="na">value=</span><span class="s">"2018-01-01 23:38:00 UTC"</span>
<span class="na">name=</span><span class="s">"content[published_at]"</span>
<span class="na">id=</span><span class="s">"content_published_at"</span> <span class="nt">/></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>Closer!</p>
<p>Thinking about this for a second, the custom component should not be assigning
an <code class="language-plaintext highlighter-rouge">id</code> to that <code class="language-plaintext highlighter-rouge">div</code>–this is a general purpose component. We’ll figure out
how to set the <code class="language-plaintext highlighter-rouge">id</code> later, if we need it–for now, I’m going to delete the
<code class="language-plaintext highlighter-rouge">id</code>.</p>
<p>Now I need to create the <code class="language-plaintext highlighter-rouge">span</code> that follows the <code class="language-plaintext highlighter-rouge">input</code>. And that <code class="language-plaintext highlighter-rouge">span</code> needs
to contain a nested <code class="language-plaintext highlighter-rouge">span</code> inside of it. Hmm–that’s a pattern we’ve seen
before. The nested <code class="language-plaintext highlighter-rouge">span</code> can be created like this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:span</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'input-group-addon'</span><span class="p">)</span> <span class="k">do</span>
<span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:span</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'glyphicon glyphicon-calendar'</span><span class="p">)</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Adding that into the <code class="language-plaintext highlighter-rouge">input</code> method, we have:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/inputs/date_time_picker_input.rb</span>
<span class="k">def</span> <span class="nf">input</span><span class="p">(</span><span class="n">wrapper_options</span><span class="p">)</span>
<span class="n">merged_input_options</span> <span class="o">=</span> <span class="n">merge_wrapper_options</span><span class="p">(</span><span class="n">input_html_options</span><span class="p">,</span> <span class="n">wrapper_options</span><span class="p">)</span>
<span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:div</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'input-group date'</span><span class="p">)</span> <span class="k">do</span>
<span class="vi">@builder</span><span class="p">.</span><span class="nf">text_field</span><span class="p">(</span><span class="n">attribute_name</span><span class="p">,</span> <span class="n">merged_input_options</span><span class="p">)</span>
<span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:span</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'input-group-addon'</span><span class="p">)</span> <span class="k">do</span>
<span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:span</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'glyphicon glyphicon-calendar'</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>When we run this, we get this HTML:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"form-group date_time_picker required content_published_at"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"input-group date"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"glyphicon glyphicon-calendar"</span><span class="nt">></span></span>
<span class="nt"></span></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>Wait! What happened to the <code class="language-plaintext highlighter-rouge">input</code>?</p>
<p>Well, the way these tag builder blocks work is that the “return value” of the
block is what’s wrapped by the tag. In this case, the return value of the block
is whatever the <code class="language-plaintext highlighter-rouge">template.content_tag(:span)</code> builder returns, which is the
nested spans that we see. The output of the <code class="language-plaintext highlighter-rouge">@builder.text_field()</code> call fell
on the floor and wasn’t used at all.</p>
<p>The return value of the <code class="language-plaintext highlighter-rouge">template.content_tag(:div, class: 'input-group date')</code>
builder block needs to be contain both the <code class="language-plaintext highlighter-rouge">input</code> and the <code class="language-plaintext highlighter-rouge">span</code>, in that order.
The <code class="language-plaintext highlighter-rouge">input</code> and the <code class="language-plaintext highlighter-rouge">span</code> builders just return strings, so we can simply
concatenate them! Here’s a simple way to do that:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># app/inputs/date_time_picker_input.rb</span>
<span class="k">def</span> <span class="nf">input</span><span class="p">(</span><span class="n">wrapper_options</span><span class="p">)</span>
<span class="n">merged_input_options</span> <span class="o">=</span> <span class="n">merge_wrapper_options</span><span class="p">(</span><span class="n">input_html_options</span><span class="p">,</span> <span class="n">wrapper_options</span><span class="p">)</span>
<span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:div</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'input-group date'</span><span class="p">)</span> <span class="k">do</span>
<span class="n">input</span> <span class="o">=</span> <span class="vi">@builder</span><span class="p">.</span><span class="nf">text_field</span><span class="p">(</span><span class="n">attribute_name</span><span class="p">,</span> <span class="n">merged_input_options</span><span class="p">)</span>
<span class="n">span</span> <span class="o">=</span> <span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:span</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'input-group-addon'</span><span class="p">)</span> <span class="k">do</span>
<span class="n">template</span><span class="p">.</span><span class="nf">content_tag</span><span class="p">(</span><span class="ss">:span</span><span class="p">,</span> <span class="s1">''</span><span class="p">,</span> <span class="ss">class: </span><span class="s1">'glyphicon glyphicon-calendar'</span><span class="p">)</span>
<span class="k">end</span>
<span class="s2">"</span><span class="si">#{</span><span class="n">input</span><span class="si">}</span><span class="s2"> </span><span class="si">#{</span><span class="n">span</span><span class="si">}</span><span class="s2">"</span><span class="p">.</span><span class="nf">html_safe</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>And the HTML:</p>
<div class="language-html highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nt"><div</span> <span class="na">class=</span><span class="s">"form-group date_time_picker required content_published_at"</span><span class="nt">></span>
<span class="nt"><div</span> <span class="na">class=</span><span class="s">"input-group date"</span><span class="nt">></span>
<span class="nt"><input</span> <span class="na">class=</span><span class="s">"form-control date_time_picker required"</span>
<span class="na">type=</span><span class="s">"text"</span>
<span class="na">value=</span><span class="s">"2018-01-01 23:38:00 UTC"</span>
<span class="na">name=</span><span class="s">"content[published_at]"</span>
<span class="na">id=</span><span class="s">"content_published_at"</span> <span class="nt">/></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"input-group-addon"</span><span class="nt">></span>
<span class="nt"><span</span> <span class="na">class=</span><span class="s">"glyphicon glyphicon-calendar"</span><span class="nt">></span></span>
<span class="nt"></span></span>
<span class="nt"></div></span>
<span class="nt"></div></span>
</code></pre></div></div>
<p>Awesome!</p>
<p>Because we haven’t hooked up the JavaScript part of this component, it doesn’t
do anything, yet. Let’s do that now.</p>
<h4 id="the-javascript">The JavaScript</h4>
<p>The <code class="language-plaintext highlighter-rouge">bootstrap-datetime-picker</code> <a href="https://eonasdan.github.io/bootstrap-datetimepicker/">home page</a> describes the
simple JavaScript that hooks up and gives life to the picker. From near the top
of that page, this is all that it takes:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">$</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">#datetimepicker1</span><span class="dl">'</span><span class="p">).</span><span class="nx">datetimepicker</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div></div>
<p>This JavaScript uses <a href="https://jquery.com/">jQuery</a> to call the <code class="language-plaintext highlighter-rouge">datetimepicker</code> function
(provided by <code class="language-plaintext highlighter-rouge">bootstrap-datetime-picker</code>, which is already installed) on the
DOM element whose <code class="language-plaintext highlighter-rouge">id</code> is <code class="language-plaintext highlighter-rouge">datetimepicker1</code>. Whoops–I deleted that!</p>
<p>Our component doesn’t have an <code class="language-plaintext highlighter-rouge">id</code>, but does it need one? Let’s say we had a
form that had two or more of these pickers in it–we’d want all of them to be
turned on. The HTML of our component has plenty of identifying classes attached
to various elements of it–we can find all of the picker components in the DOM
using those classes.</p>
<p>A slight change to the JavaScript will enable all of the pickers in the DOM:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">$</span><span class="p">(</span><span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">.date_time_picker > .input-group.date</span><span class="dl">'</span><span class="p">).</span><span class="nx">datetimepicker</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div></div>
<p>This generic JavaScript is written this way so that the code inside of the
anonymous function gets called when the page has finished loading. (Exactly how
that works is beyond the scope of this post, but a little Googling around
should find tons of articles about it.) Rails 5.1 has a different way to run
JavaScript when the page is loaded (the details of which are also beyond the
scope of this post):</p>
<div class="language-javascript 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="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">turbolinks:load</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">.date_time_picker > .input-group.date</span><span class="dl">'</span><span class="p">).</span><span class="nx">datetimepicker</span><span class="p">();</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Here’s the equivalent CoffeeScript (which is the default flavor of JavaScript
as of Rails 5.1):</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">$</span><span class="p">(</span><span class="s">'.date_time_picker > .input-group.date'</span><span class="p">).</span><span class="na">datetimepicker</span><span class="p">()</span>
</code></pre></div></div>
<p>With that code added to your page’s JavaScript (I’m not going to explain how to
do that, but there’s lots of Rails documentation and tutorials online), the
picker component works! If you’ve been following along, hopefully you see something
like this:</p>
<p><img src="http://blog.edruder.com/assets/images/picker.png" alt="picker" /></p>
<p>When I started using this picker, it kind of worked, but had some problems.</p>
<p>The first was that when it was used to edit an existing value, the picker would
start out blank, instead of populated with the value. When I watched closely, I
saw that the right value flickered quickly in the picker, but was erased almost
immediately. For some reason, the value <strong>does</strong> populate the picker initially,
but when the <code class="language-plaintext highlighter-rouge">datetimepicker()</code> function is called, it gets erased.</p>
<p>My quick fix to that problem is to modify the JavaScript to grab the value of
the picker, call the initializer, then restore the value. Seems to work.
(There’s probably a better way to do this. Let me know!)</p>
<p>The next problem I saw was that the date that was saved in the Active Record
datetime field was a little funky–sometimes it was just a little wrong,
sometimes it wasn’t stored at all. Turns out that the format of the date/time
string has to match the format that the Rails database expects it. It will try
to parse the string using its format, and sometimes it will be just a little
wrong, and other times it would be an illegal date, and nothing gets stored!</p>
<p>The way I chose to fix this was to change the format of the string that’s
returned by the <code class="language-plaintext highlighter-rouge">bootstrap-datetime-picker</code> to match the format that my
database (MySQL) expects. (I think the format that MySQL expects–<code class="language-plaintext highlighter-rouge">YYYY-MM-DD
HH:mm:ss</code>–is fairly common, if not ubiquitous, among databases.)</p>
<p>Here’s the final JavaScript that works well for me:</p>
<div class="language-javascript 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="nx">on</span><span class="p">(</span><span class="dl">"</span><span class="s2">turbolinks:load</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">$pickerInput</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">.date_time_picker input.date_time_picker</span><span class="dl">'</span><span class="p">);</span>
<span class="kd">const</span> <span class="nx">initialValue</span> <span class="o">=</span> <span class="nx">$pickerInput</span><span class="p">.</span><span class="nx">val</span><span class="p">();</span>
<span class="nx">$</span><span class="p">(</span><span class="dl">'</span><span class="s1">.date_time_picker > .input-group.date</span><span class="dl">'</span><span class="p">).</span><span class="nx">datetimepicker</span><span class="p">({</span> <span class="na">format</span><span class="p">:</span> <span class="dl">'</span><span class="s1">YYYY-MM-DD HH:mm:ss</span><span class="dl">'</span> <span class="p">});</span>
<span class="k">return</span> <span class="nx">$pickerInput</span><span class="p">.</span><span class="nx">val</span><span class="p">(</span><span class="nx">initialValue</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div></div>
<p>Here’s the equivalent CoffeeScript:</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">$pickerInput</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s">'.date_time_picker input.date_time_picker'</span><span class="p">)</span>
<span class="nx">initialValue</span> <span class="o">=</span> <span class="nx">$pickerInput</span><span class="p">.</span><span class="na">val</span><span class="p">()</span>
<span class="nx">$</span><span class="p">(</span><span class="s">'.date_time_picker > .input-group.date'</span><span class="p">).</span><span class="na">datetimepicker</span><span class="p">({</span> <span class="na">format</span><span class="o">:</span> <span class="s">'YYYY-MM-DD HH:mm:ss'</span> <span class="p">})</span>
<span class="nx">$pickerInput</span><span class="p">.</span><span class="na">val</span><span class="p">(</span><span class="nx">initialValue</span><span class="p">)</span>
</code></pre></div></div>
<p>Please leave a note if you have questions, answers, suggestions, or a better
solution!</p>I’m using Bootstrap to make the pages of my Rails app look halfway decent–I’m a programmer who’s creatively challenged. (I can already feel the scorn from my designer friends, but hey–I actually like how Bootstrap looks!) I’m also using Simple Form to clean up the HTML forms in my app.Rendering Dynamic Markdown in Rails2018-01-27T00:00:00-06:002018-01-27T00:00:00-06:00http://blog.edruder.com/2018/01/27/rendering-dynamic-markdown<p>I wrote about how I enabled Markdown views in my Rails 5 app
<a href="/2017/12/19/add-markdown-to-rails-5.html">previously</a>. I wanted to add the ability to create and edit
Markdown-formatted articles, posts, etc. in this app, and it turned out to be
pretty easy.</p>
<p>The Markdown that I want to render will be created dynamically by the users of
my app and stored in the Rails database, as opposed to being in static <code class="language-plaintext highlighter-rouge">.md</code>
files somewhere in my <code class="language-plaintext highlighter-rouge">views</code> directory. I already had the
<a href="https://github.com/vmg/redcarpet">redcarpet</a> gem installed and configured in my app–I just needed to
figure out how to use it to render arbitrary Markdown in a view.</p>
<p>My Markdown handler had changed slightly from its initial incarnation–I had
tweaked the <code class="language-plaintext highlighter-rouge">Redcarpet</code> settings a little and done a tiny bit of refactoring.
Here’s what I started with:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># config/initializers/markdown.rb</span>
<span class="nb">require</span> <span class="s1">'redcarpet'</span>
<span class="k">module</span> <span class="nn">ActionView</span>
<span class="k">module</span> <span class="nn">Template::Handlers</span>
<span class="k">class</span> <span class="nc">Markdown</span>
<span class="n">class_attribute</span> <span class="ss">:default_format</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">default_format</span> <span class="o">=</span> <span class="no">Mime</span><span class="p">[</span><span class="ss">:html</span><span class="p">]</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
<span class="n">compiled_source</span> <span class="o">=</span> <span class="n">erb</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
<span class="s2">"</span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">.render(begin;</span><span class="si">#{</span><span class="n">compiled_source</span><span class="si">}</span><span class="s2">;end)"</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
<span class="n">markdown</span><span class="p">.</span><span class="nf">render</span><span class="p">(</span><span class="n">template</span><span class="p">).</span><span class="nf">html_safe</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">extensions</span>
<span class="vi">@md_options</span> <span class="o">||=</span> <span class="p">{</span>
<span class="ss">autolink: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">fenced_code_blocks: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">highlight: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">quotes: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">strikethrough: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">tables: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">underline: </span><span class="kp">true</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">markdown</span>
<span class="vi">@markdown</span> <span class="o">||=</span> <span class="no">Redcarpet</span><span class="o">::</span><span class="no">Markdown</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">renderer</span><span class="p">,</span> <span class="n">extensions</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">renderer_options</span>
<span class="vi">@renderer_options</span> <span class="o">||=</span> <span class="p">{</span>
<span class="ss">filter_html: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">hard_wrap: </span><span class="kp">true</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">renderer</span>
<span class="vi">@renderer</span> <span class="o">||=</span> <span class="no">HTMLWithPants</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">renderer_options</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">erb</span>
<span class="vi">@erb</span> <span class="o">||=</span> <span class="no">ActionView</span><span class="o">::</span><span class="no">Template</span><span class="p">.</span><span class="nf">registered_template_handler</span><span class="p">(</span><span class="ss">:erb</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">HTMLWithPants</span> <span class="o"><</span> <span class="no">Redcarpet</span><span class="o">::</span><span class="no">Render</span><span class="o">::</span><span class="no">HTML</span>
<span class="kp">include</span> <span class="no">Redcarpet</span><span class="o">::</span><span class="no">Render</span><span class="o">::</span><span class="no">SmartyPants</span>
<span class="k">end</span>
<span class="no">ActionView</span><span class="o">::</span><span class="no">Template</span><span class="p">.</span><span class="nf">register_template_handler</span><span class="p">(</span><span class="ss">:md</span><span class="p">,</span> <span class="no">ActionView</span><span class="o">::</span><span class="no">Template</span><span class="o">::</span><span class="no">Handlers</span><span class="o">::</span><span class="no">Markdown</span><span class="p">)</span>
</code></pre></div></div>
<p>Notice that all of the Markdown stuff is <code class="language-plaintext highlighter-rouge">private</code>–a Rails template handler
just needs to respond to <code class="language-plaintext highlighter-rouge">:call</code>–it doesn’t need to expose its implementation
details (and shouldn’t). Because of what <code class="language-plaintext highlighter-rouge">call</code> returns in this particular
handler–a <code class="language-plaintext highlighter-rouge">String</code> that gets <code class="language-plaintext highlighter-rouge">eval</code>ed somewhere in <code class="language-plaintext highlighter-rouge">ActionView</code>, and the
<code class="language-plaintext highlighter-rouge">eval</code>ed code calls the <code class="language-plaintext highlighter-rouge">render</code> method–the <code class="language-plaintext highlighter-rouge">render</code> method needs to be
<code class="language-plaintext highlighter-rouge">public</code>, too.</p>
<p>What I want to end up with is an application-wide <code class="language-plaintext highlighter-rouge">markdown(text)</code> method that
accepts Markdown-formatted text and returns HTML that can be displayed by any
view. The <code class="language-plaintext highlighter-rouge">Redcarpet::Markdown</code> object has a <code class="language-plaintext highlighter-rouge">render(text)</code> method that’s just
what we need–I just need to make that <code class="language-plaintext highlighter-rouge">markdown</code> method in my handler <code class="language-plaintext highlighter-rouge">public</code>
and use it in the helper! The result:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># config/initializers/markdown.rb</span>
<span class="c1"># moved into the public section</span>
<span class="k">def</span> <span class="nf">markdown</span>
<span class="vi">@markdown</span> <span class="o">||=</span> <span class="no">Redcarpet</span><span class="o">::</span><span class="no">Markdown</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="n">renderer</span><span class="p">,</span> <span class="n">extensions</span><span class="p">)</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="c1"># app/helpers/application_helper.rb</span>
<span class="k">def</span> <span class="nf">markdown</span><span class="p">(</span><span class="n">text</span><span class="p">)</span>
<span class="no">ActionView</span><span class="o">::</span><span class="no">Template</span><span class="o">::</span><span class="no">Handlers</span><span class="o">::</span><span class="no">Markdown</span><span class="p">.</span><span class="nf">markdown</span><span class="p">.</span><span class="nf">render</span><span class="p">(</span><span class="n">text</span><span class="p">).</span><span class="nf">html_safe</span>
<span class="k">end</span>
</code></pre></div></div>
<p>Not the prettiest line of Ruby code (and it violates the <a href="https://en.wikipedia.org/wiki/Law_of_Demeter">Law of
Demeter</a>), but it works–<strong>and</strong> it uses the
already-instantiated <code class="language-plaintext highlighter-rouge">Redcarpet::Markdown</code> object. I can pretty it up, later.</p>
<p>If you want to render the Markdown from your users differently than the
Markdown in your own views, you might want to instantiate (and cache) a
<code class="language-plaintext highlighter-rouge">Redcarpet::Markdown</code> object with different settings. E.g., you might want to
be more strict about what is allowed in the Markdown that your users can enter,
compared to what you allow in your own views.</p>
<p>That <code class="language-plaintext highlighter-rouge">.html_safe</code> is important–without it, the HTML generated from the
Markdown will be “escaped” by Rails, displaying a bunch of ugly, raw HTML in
your view.</p>
<p>With this helper, you’re able to put a call to <code class="language-plaintext highlighter-rouge">markdown</code> in any views that you
like! For example, I have a <code class="language-plaintext highlighter-rouge">ContentsController</code> whose <code class="language-plaintext highlighter-rouge">show</code> method reads a
<code class="language-plaintext highlighter-rouge">Content</code> record from the database into a <code class="language-plaintext highlighter-rouge">@content</code> variable. The <code class="language-plaintext highlighter-rouge">Content</code>
model has a <code class="language-plaintext highlighter-rouge">body</code> field containing Markdown formatted text, so in the
<code class="language-plaintext highlighter-rouge">views/contents/show.html.erb</code> file, there’s a <code class="language-plaintext highlighter-rouge">markdown(@content.body)</code> call
that inserts beautiful HTML from the Markdown text that the user entered!</p>
<p>Please leave a note if you have questions or suggestions.</p>I wrote about how I enabled Markdown views in my Rails 5 app previously. I wanted to add the ability to create and edit Markdown-formatted articles, posts, etc. in this app, and it turned out to be pretty easy.Adding support for Markdown views to Rails 52017-12-19T00:00:00-06:002017-12-19T00:00:00-06:00http://blog.edruder.com/2017/12/19/add-markdown-to-rails-5<p>I thought that adding <a href="https://daringfireball.net/projects/markdown/syntax">Markdown</a> support to a Ruby on Rails 5 project
would be a straightforward thing. I’ve read a bunch of blogs over the years
that described various ways to use Markdown in Rails apps. There are many
Markdown gems–<a href="https://github.com/vmg/redcarpet">redcarpet</a>, <a href="https://github.com/gettalong/kramdown">kramdown</a>,
<a href="https://github.com/davidfstr/rdiscount">rdiscount</a>, to name a few. And there are several ways to use
Markdown–from allowing a content management system to author new posts in
Markdown to supporting Markdown-formatted views in a Rails app itself. I was
interested in the latter, and expected it to be pretty easy.</p>
<p>Wrong.</p>
<p>My first road block was conceptual. I’ve been using Rails for a long time, off
and on, but haven’t used it consistently since pre-Rails 3. My recollection,
which may be just wrong, is that at some point, Rails’ view rendering allowed
chaining of several template renderers–if you named your view something like,
<code class="language-plaintext highlighter-rouge">posts.html.md.erb</code>, and you had the handlers installed, the view source would
first be handled by the <a href="http://www.stuartellis.name/articles/erb/">ERB</a> handler, then the Markdown handler, then
Rails’ standard HTML view processing. Turns out, this is not the way that
Rails’ template handlers work (and they may never have worked that way).</p>
<p>As far as I can figure out, <code class="language-plaintext highlighter-rouge">ActionView</code> template handlers aren’t chainable–
they are intended to convert from one type of template (<code class="language-plaintext highlighter-rouge">ERB</code> or <code class="language-plaintext highlighter-rouge">Markdown</code> or
<code class="language-plaintext highlighter-rouge">Haml</code>, say) into the final <code class="language-plaintext highlighter-rouge">MIME</code> type that your template is targeting (<code class="language-plaintext highlighter-rouge">HTML</code>
or <code class="language-plaintext highlighter-rouge">JSON</code> or <code class="language-plaintext highlighter-rouge">XML</code>, for example), and no more. If you want to create views in
Markdown that can have ERB inside of them, then your Markdown handler needs to
know how to handle ERB itself.</p>
<p>I searched all over the Web and found several helpful blog posts, but none that
did <strong>exactly</strong> what I wanted (<a href="https://gist.github.com/davidjrice/3014948">a</a> <a href="http://lugolabs.com/articles/18-render-markdown-views-with-redcarpet-and-pygment-in-rails">few</a> came pretty
close, though). The Rails Guides don’t discuss how to create your own template
handlers, and even the Rails source wasn’t much help to me. I wanted a clean
initializer and I wanted to enable ERB in the Markdown templates.</p>
<h3 id="a-solution">A Solution</h3>
<p>I chose to use the <code class="language-plaintext highlighter-rouge">redcarpet</code> Markdown gem because it’s fast, feature-rich,
and well-maintained. <code class="language-plaintext highlighter-rouge">redcarpet</code> needs to be available in all of the Rails
app’s environments, so don’t put it into a <code class="language-plaintext highlighter-rouge">development</code>-only stanza of your
<code class="language-plaintext highlighter-rouge">Gemfile</code>! (Been there, done that.)</p>
<p>I like to use TDD (though I’m not super-consistent about it), and it’s easy to
create a test for this–just create a view in Markdown and verify that the
HTML that’s rendered contains the right tag(s)! I’m using RSpec, and my test
looks like this:</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># spec/views/welcome/about.html.md_spec.rb</span>
<span class="nb">require</span> <span class="s1">'rails_helper'</span>
<span class="no">RSpec</span><span class="p">.</span><span class="nf">describe</span> <span class="s1">'welcome/about.html.md'</span> <span class="k">do</span>
<span class="n">it</span> <span class="s1">'renders Markdown'</span> <span class="k">do</span>
<span class="n">render</span>
<span class="n">expect</span><span class="p">(</span><span class="n">rendered</span><span class="p">).</span><span class="nf">to</span> <span class="n">match</span> <span class="sr">%r{<h3>About My Website</h3>}</span>
<span class="k">end</span>
<span class="k">end</span>
</code></pre></div></div>
<p>It will fail, of course, because there is no such view.</p>
<p>Then, create the Markdown view:</p>
<div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c"><!-- app/views/welcome/about.html.md --></span>
<span class="gu">### About My Website</span>
It's really cool!
</code></pre></div></div>
<p>The spec will still fail, but in a different way, since now the template is
asking for a handler that doesn’t exist.</p>
<p>Finally, the Markdown handler!</p>
<div class="language-ruby highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># config/initializers/redcarpet.rb</span>
<span class="nb">require</span> <span class="s1">'redcarpet'</span>
<span class="k">module</span> <span class="nn">ActionView</span>
<span class="k">module</span> <span class="nn">Template::Handlers</span>
<span class="k">class</span> <span class="nc">Markdown</span>
<span class="n">class_attribute</span> <span class="ss">:default_format</span>
<span class="nb">self</span><span class="p">.</span><span class="nf">default_format</span> <span class="o">=</span> <span class="no">Mime</span><span class="p">[</span><span class="ss">:html</span><span class="p">]</span>
<span class="k">class</span> <span class="o"><<</span> <span class="nb">self</span>
<span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
<span class="n">compiled_source</span> <span class="o">=</span> <span class="n">erb</span><span class="p">.</span><span class="nf">call</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
<span class="s2">"</span><span class="si">#{</span><span class="nb">name</span><span class="si">}</span><span class="s2">.render(begin;</span><span class="si">#{</span><span class="n">compiled_source</span><span class="si">}</span><span class="s2">;end)"</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">render</span><span class="p">(</span><span class="n">template</span><span class="p">)</span>
<span class="n">markdown</span><span class="p">.</span><span class="nf">render</span><span class="p">(</span><span class="n">template</span><span class="p">).</span><span class="nf">html_safe</span>
<span class="k">end</span>
<span class="kp">private</span>
<span class="k">def</span> <span class="nf">md_options</span>
<span class="vi">@md_options</span> <span class="o">||=</span> <span class="p">{</span>
<span class="ss">autolink: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">fenced_code_blocks: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">strikethrough: </span><span class="kp">true</span><span class="p">,</span>
<span class="ss">tables: </span><span class="kp">true</span><span class="p">,</span>
<span class="p">}</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">markdown</span>
<span class="vi">@markdown</span> <span class="o">||=</span> <span class="no">Redcarpet</span><span class="o">::</span><span class="no">Markdown</span><span class="p">.</span><span class="nf">new</span><span class="p">(</span><span class="no">HTMLWithPants</span><span class="p">,</span> <span class="n">md_options</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">def</span> <span class="nf">erb</span>
<span class="vi">@erb</span> <span class="o">||=</span> <span class="no">ActionView</span><span class="o">::</span><span class="no">Template</span><span class="p">.</span><span class="nf">registered_template_handler</span><span class="p">(</span><span class="ss">:erb</span><span class="p">)</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">HTMLWithPants</span> <span class="o"><</span> <span class="no">Redcarpet</span><span class="o">::</span><span class="no">Render</span><span class="o">::</span><span class="no">HTML</span>
<span class="kp">include</span> <span class="no">Redcarpet</span><span class="o">::</span><span class="no">Render</span><span class="o">::</span><span class="no">SmartyPants</span>
<span class="k">end</span>
<span class="no">ActionView</span><span class="o">::</span><span class="no">Template</span><span class="p">.</span><span class="nf">register_template_handler</span><span class="p">(</span><span class="ss">:md</span><span class="p">,</span> <span class="no">ActionView</span><span class="o">::</span><span class="no">Template</span><span class="o">::</span><span class="no">Handlers</span><span class="o">::</span><span class="no">Markdown</span><span class="p">)</span>
</code></pre></div></div>
<p>A little explanation, starting from the bottom.
<code class="language-plaintext highlighter-rouge">ActionView::Template.register_template_handler</code> is the method that registers a
new template handler. It expects the filename extension that the handler
applies to (<code class="language-plaintext highlighter-rouge">:md</code>, for files that end in <code class="language-plaintext highlighter-rouge">.md</code>), and an object that implements
a <code class="language-plaintext highlighter-rouge">call</code> method–in our case, the class that we defined,
<code class="language-plaintext highlighter-rouge">ActionView::Template::Handlers::Markdown</code>.</p>
<p>The <code class="language-plaintext highlighter-rouge">class << self</code> block wraps the class methods, of which only two are
<code class="language-plaintext highlighter-rouge">public</code>–<code class="language-plaintext highlighter-rouge">call</code> and <code class="language-plaintext highlighter-rouge">render</code>. (<code class="language-plaintext highlighter-rouge">render</code> only needs to be public because it’s
going to be called by Rails, which we’ll see in a second.) The magic happens in
the <code class="language-plaintext highlighter-rouge">call</code> class method–the class itself implements the <code class="language-plaintext highlighter-rouge">call</code> method that
<code class="language-plaintext highlighter-rouge">register_template_handler</code> requires.</p>
<p>The <code class="language-plaintext highlighter-rouge">call</code> method needs to return a <strong>string</strong> containing the <em>code</em> that needs
to be executed by Rails to generate HTML (in this template handler, because of
the <code class="language-plaintext highlighter-rouge">self.default_format = Mime[:html]</code> line). (There isn’t much, if any,
documentation on this–I got this from the articles I found online.)</p>
<p>The <code class="language-plaintext highlighter-rouge">compiled_source = erb.call(template)</code> line is what handles ERB in the
Markdown template. The string it returns is then handled by the Markdown
renderer that’s in our code.</p>
<p><code class="language-plaintext highlighter-rouge">"#{name}.render(begin;#{compiled_source};end)"</code> is the return value of the
<code class="language-plaintext highlighter-rouge">call</code> method–that’s the string of code that Rails will eventually evaluate
and run. Because the code will be run in a Rails context, it needs to
fully-qualify the method to be run. The <code class="language-plaintext highlighter-rouge">name</code> method returns the full name of
<code class="language-plaintext highlighter-rouge">self</code>, which is the class, so it returns
<code class="language-plaintext highlighter-rouge">ActionView::Template::Handlers::Markdown</code>. <code class="language-plaintext highlighter-rouge">#{name}.render</code>, then,
fully-qualifies our <code class="language-plaintext highlighter-rouge">render</code> method.</p>
<p>The parameter to <code class="language-plaintext highlighter-rouge">render</code>–<code class="language-plaintext highlighter-rouge">begin;#{compiled_source};end</code>–is also mysterious.
It wraps a Ruby block around the string that the ERB handler returned (that is
also Ruby code), which makes it digestible to the Markdown <code class="language-plaintext highlighter-rouge">render</code> method.</p>
<p>I’m still a little fuzzy on why the code that invokes the handler needs to be
passed around as a Ruby string, but this solution works nicely for me!</p>
<p>Please leave a note if you have questions, suggestions, or a better
explanation.</p>I thought that adding Markdown support to a Ruby on Rails 5 project would be a straightforward thing. I’ve read a bunch of blogs over the years that described various ways to use Markdown in Rails apps. There are many Markdown gems–redcarpet, kramdown, rdiscount, to name a few. And there are several ways to use Markdown–from allowing a content management system to author new posts in Markdown to supporting Markdown-formatted views in a Rails app itself. I was interested in the latter, and expected it to be pretty easy.Why can’t Smart Routers be Really Smart?2017-01-01T00:00:00-06:002017-01-01T00:00:00-06:00http://blog.edruder.com/2017/01/01/why-cant-smart-routers-be-smart<p>In 2016 the media reported on <a href="https://www.tripwire.com/state-of-security/security-data-protection/cyber-security/5-significant-ddos-attacks-2016/">a number of Distributed Denial of Service (DDoS)
attacks</a> that significantly disrupted aspects of the
Internet, wreaking havoc that ranged from minor inconveniences for many, to
serious financial losses for some. The DDoS attacks were caused by
<a href="https://www.eset.com/us/about/newsroom/corporate-blog/ddos-attacks-explained/">botnets</a>, which are composed of large numbers of unsecured,
hacked devices that are connected to the Internet. Attackers take advantage of
numerous well-known and lesser-known vulnerabilities in a multitude of
connected computers, routers, surveillance cameras, and other devices. When
they find a device they can hack into, they take control of the device for
their own, often destructive, purposes.</p>
<p>Sales of Internet-connected devices (a.k.a., the <a href="https://en.wikipedia.org/wiki/Internet_of_things">Internet of Things</a> or
IoT) are exploding, and there are no signs that the trend is slowing. On the
contrary, more and more connected devices are being introduced and sold into
homes and businesses because they are so useful and/or cool–they are here to
stay. Unfortunately, we haven’t yet figured out how to protect these devices
from attackers, or how to protect ourselves from hacked devices.</p>
<p>There are thousands of vulnerable products in millions of homes and businesses,
and each of them need to be fixed by its manufacturer. That will be a big,
distributed effort that will take a long time. Until that happens, how can we
prevent attackers from finding and hacking vulnerable Internet-connected
devices?</p>
<p>All of the vulnerable devices have one thing in common–they connect to the
Internet via a relatively inexpensive, sophisticated, commercial
<a href="https://en.wikipedia.org/wiki/Router_(computing)">router</a>. Every household and most businesses have one router through
which 100% of their Internet traffic flows–you can think of it as an Internet
gatekeeper. Sometimes that router is built into the modem that is provided by
their <a href="https://en.wikipedia.org/wiki/Internet_service_provider">Internet Service Provider</a> (ISP), sometimes it’s a separate box
connected to the ISP’s modem. Routers are quite complicated–they often have
built-in <a href="https://en.wikipedia.org/wiki/Firewall_(computing)">firewalls</a> and <a href="https://en.wikipedia.org/wiki/Virtual_private_network">VPNs</a> for security, logic to
intelligently route traffic to the devices “behind” them and much more.</p>
<p>My question is, why hasn’t one or more of the very sophisticated companies that
make and sell routers–Cisco, D-Link, Netgear, <strike>Apple</strike>, Google,
etc.–made an inexpensive commercial router that’s <strong>really</strong> smart? A Really
Smart Router (RSR) would have at least these characteristics:</p>
<ul>
<li>An RSR makes sure that it has a strong password.</li>
<li>An RSR itself is very well protected.</li>
<li>An RSR checks the devices connected to it for known vulnerabilities.</li>
<li>An RSR automatically and securely keeps its software up-to-date.</li>
</ul>
<p>Each of these features probably needs to be able to be overridden by their
owner, for reasons they think are strong enough to reduce the security of their
network, but they should be turned on by default.</p>
<h3 id="strong-password">Strong Password</h3>
<p>Almost all routers have a simple/weak password assigned when they are brand
new–it’s printed in the router’s manual so that new owners can easily set up
their new router. The manual usually advises the new owner IN ALL CAPS to
change the password to something stronger, but leaves it at that. People being
people, many new router owners never change their router’s password, making it
an easy target for attackers.</p>
<p>An RSR would refuse to work until its password was set to something hard for an
attacker to figure out. “Hard to figure out” can be satisfied a number of ways.
Maybe the password can’t be too short, so that it can’t be guessed quickly.
Maybe the password can’t be in a dictionary of common words or have any form of
the initial simple password in it. Maybe an RSR doesn’t allow login attempts to
happen quickly, so that attackers can’t “brute force” guess thousands or
millions of passwords in a very short time.</p>
<h3 id="well-protected">Well Protected</h3>
<p>Once protected by a strong password, I think that most routers are pretty
resistant to exploitation by attackers. However, I’m sure that more than a few
have known vulnerabilities that haven’t been fixed, or even have “back
doors”–ways into the router that bypass the password check that are
intentionally built into the router.</p>
<p>An RSR would be a fortress–it would have no back doors, its software would be
aggressively tested for vulnerabilities, and any found would be fixed quickly.</p>
<h3 id="checks-connected-devices">Checks Connected Devices</h3>
<p>This is a biggie. Many security experts and companies are well aware of almost
all of the vulnerabilities that attackers use to create botnets. The experts
know what the devices “look like”; they know how to exploit their
vulnerabilities.</p>
<p>On some frequency–once a day, once a week, when it detects a new device–a
Really Smart Router checks <strong>every</strong> device connected to it against a
comprehensive list of known vulnerabilities. If it finds a vulnerable device,
it informs the owner and disconnects the device from the Internet completely.
The owner would receive enough information to know what to do next–which
device is the problem, what the problem is, and how to fix it. (Some devices
are not easily updatable–they may need to be recycled.)</p>
<p>The devil is in the details, but this doesn’t seem like a terribly difficult
feature to implement.</p>
<p>An RSR wouldn’t store every known vulnerability inside of itself (even if it
had unlimited space, the list of vulnerabilities is always growing)–it would
“phone home” to its manufacturer with the “signature” of the devices connected
to it, and its manufacturer would send it the list of vulnerabilities to check
for on each of them.</p>
<p>I’m frankly surprised that no router manufacturer that I know of does this
already.</p>
<h3 id="automatically-updated">Automatically Updated</h3>
<p>Even a Really Smart Router that did all of these things could not be perfect.
New Internet-connected devices are created all the time, maybe with types of
vulnerabilities that the RSR doesn’t initially know how to check for. The RSR’s
software itself may have vulnerabilities that don’t get discovered until after
many of them are installed in customers’ homes and businesses.</p>
<p>Most if not all routers already have a way to update their software. However,
not many routers make updating their software easy or convenient, or have an
option to automatically update it. People being people, I think RSRs must have
an option to automatically check for and install new software without requiring
the user to press a button or visit a web page–it needs to be 100% automatic.</p>
<p>The updating process itself needs to be secure, too–it must be impossible for
an attacker to pretend that it’s the RSR’s manufacturer, and fool it into
downloading and installing the attacker’s software!</p>
<p>Our phones and computers can do this–heck, even smart thermostats update
themselves to the latest software automatically! There’s no good reason our
routers don’t.</p>
<h3 id="we-need-really-smart-routers">We need Really Smart Routers!</h3>
<p>Every year, millions of new connected devices are installed into people’s
houses and businesses. DDoS attacks will continue to happen more and more
often, causing more and more disruption, unless vulnerable devices are removed
from the Internet when they’re discovered.</p>
<p>I think that we need Really Smart Routers, and badly!</p>
<p>What do you think?</p>In 2016 the media reported on a number of Distributed Denial of Service (DDoS) attacks that significantly disrupted aspects of the Internet, wreaking havoc that ranged from minor inconveniences for many, to serious financial losses for some. The DDoS attacks were caused by botnets, which are composed of large numbers of unsecured, hacked devices that are connected to the Internet. Attackers take advantage of numerous well-known and lesser-known vulnerabilities in a multitude of connected computers, routers, surveillance cameras, and other devices. When they find a device they can hack into, they take control of the device for their own, often destructive, purposes.