<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <id>tag:iprog.com,2007:postingsatom</id>
  <link rel="alternate" type="text/html" href="https://iprog.com"/>
  <link rel="self" type="application/atom+xml" href="https://iprog.com/postings/atom"/>
  <title>interprogramming articles</title>
  <updated>2020-08-26T04:12:00Z</updated>
  <entry>
    <id>tag:iprog.com,2007:Posting58</id>
    <published>2020-08-26T04:12:00Z</published>
    <updated>2024-11-20T22:20:09Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2020/08/list-of-activejob-queue-backends"/>
    <title>List of ActiveJob queue backends</title>
    <content type="html">&lt;p&gt;During some recent research, I made a list of all the Rails/ActiveJob compatible queue backends I could find.&lt;/p&gt;

&lt;p&gt;I started with the &lt;a href="https://edgeapi.rubyonrails.org/classes/ActiveJob/QueueAdapters.html"&gt;list from Rails&lt;/a&gt;, which is just the queues with adapters built-in to Rails, then added anything else I could find that wasn&amp;rsquo;t obviously dead (mostly determined by lack of commits for an extended time).&lt;/p&gt;

&lt;p&gt;Additions and corrections are welcomed.&lt;/p&gt;
&lt;a id="more"&gt;&lt;/a&gt;
        &lt;table class="table"&gt;
          &lt;thead&gt;
            &lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Async&lt;/th&gt;
&lt;th&gt;Queues&lt;/th&gt;
&lt;th&gt;Delayed&lt;/th&gt;
&lt;th&gt;Priorities&lt;/th&gt;
&lt;th&gt;Timeout&lt;/th&gt;
&lt;th&gt;Retries&lt;/th&gt;
&lt;th&gt;Job storage&lt;/th&gt;
&lt;th&gt;Exec mode&lt;/th&gt;
&lt;/tr&gt;

          &lt;/thead&gt;
          &lt;tbody&gt;
            &lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/nesquena/backburner"&gt;Backburner&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;td&gt;beanstalkd&lt;/td&gt;
&lt;td&gt;inprocess, fork, thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/collectiveidea/delayed_job"&gt;Delayed Job&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;td&gt;activerecord, mongoid&lt;/td&gt;
&lt;td&gt;fork&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/contribsys/faktory"&gt;Faktory Worker&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;faktory (embedded redis)&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/bsm/fleiss"&gt;Fliess&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;activerecord&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/johnewart/gearman-ruby"&gt;Gearman Ruby&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;gearman&lt;/td&gt;
&lt;td&gt;single worker&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/bensheldon/good_job"&gt;GoodJob&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;postgres&lt;/td&gt;
&lt;td&gt;inprocess, thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/ursm/activejob-google_cloud_pubsub"&gt;Google Cloud Pub/Sub&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;gcp&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/yuemori/kube_queue"&gt;KubeQueue&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;kubernetes (etcd)&lt;/td&gt;
&lt;td&gt;k8s job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/que-rb/que"&gt;Que&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;postgres&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/QueueClassic/queue_classic"&gt;queue_classic&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;postgres&lt;/td&gt;
&lt;td&gt;fork, thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/resque/resque"&gt;Resque&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes (Gem)&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;redis&lt;/td&gt;
&lt;td&gt;fork&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/phstc/shoryuken"&gt;Shoryuken&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;aws sqs&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/mperham/sidekiq/"&gt;Sidekiq&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;redis&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/jondot/sneakers"&gt;Sneakers&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;rabbitmq&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/veeqo/advanced-sneakers-activejob"&gt;Advanced Sneakers&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;Queue&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;rabbitmq&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/rails/solid_queue"&gt;Solid Queue&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;activerecord&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/WeTransfer/sqewer"&gt;Sqewer&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;td&gt;aws sqs&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/brandonhilkert/sucker_punch"&gt;Sucker Punch&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;memory&lt;/td&gt;
&lt;td&gt;inprocess&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://github.com/sitrox/workhorse"&gt;Workhorse&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Global&lt;/td&gt;
&lt;td&gt;activerecord&lt;/td&gt;
&lt;td&gt;thread&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/AsyncAdapter.html"&gt;Active Job Async&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;memory&lt;/td&gt;
&lt;td&gt;inprocess&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;a href="https://api.rubyonrails.org/classes/ActiveJob/QueueAdapters/InlineAdapter.html"&gt;Active Job Inline&lt;/a&gt;&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;memory&lt;/td&gt;
&lt;td&gt;inline&lt;/td&gt;
&lt;/tr&gt;

          &lt;/tbody&gt;
        &lt;/table&gt;

&lt;p&gt;There are also gems for running background jobs that are not ActiveJob compatible. Those are not listed above.&lt;/p&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting57</id>
    <published>2019-09-01T00:55:00Z</published>
    <updated>2019-09-01T00:55:39Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2019/08/tls-certificate-verify-failed-on-aws-rds"/>
    <title>TLS certificate verification error on AWS RDS</title>
    <content type="html">&lt;p&gt;Recently, when upgrading the Docker base image for a Ruby on Rails app, the app suddenly started raising &lt;code&gt;SSL error: certificate verify failed&lt;/code&gt; exceptions when attempting to connect to Postgres. Unfortunately, the error message doesn&amp;rsquo;t describe &lt;em&gt;why&lt;/em&gt; verification failed.&lt;/p&gt;

&lt;p&gt;The base image was being upgraded from Debian 9 (Stretch) to Debian 10 (Buster). The Postgres 11 instance (which started life on 9.x, so it&amp;rsquo;s older) is hosted by AWS RDS and configured to require TLS connections.&lt;/p&gt;

&lt;p&gt;It turns out that AWS RDS only supports TLS 1.0. However, Debian 10&amp;rsquo;s openssl config defaults to requiring TLS 1.2+. The result is the certificate verification error above.&lt;/p&gt;

&lt;p&gt;The quick fix is to modify &lt;code&gt;/etc/ssl/openssl.cnf&lt;/code&gt; (as this is what changed between Debian 9 and 10) to allow TLS 1.0. Near the bottom of the file, change&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;MinProtocol = TLSv1.2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;to&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;MinProtocol = TLSv1.0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Or, run this simple one liner:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;sed -i -e 's/TLSv1.2/TLSv1.0/' /etc/ssl/openssl.cnf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The better fix is to upgrade/replace the Postgres server to support TLS 1.2+ since TLS 1.0 and 1.1 are being deprecated.&lt;/p&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting56</id>
    <published>2019-05-12T22:26:00Z</published>
    <updated>2019-05-13T00:23:06Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2019/05/rails-6-multi-environment-credentials"/>
    <title>Rails 6: How to use multi-environment credentials</title>
    <content type="html">&lt;p&gt;Rails 6.0 adds support for multi-environment credentials. Here&amp;rsquo;s a quick summary of how it works:&lt;/p&gt;

&lt;p&gt;By default, behavior is the same as Rails 5.2. To configure credentials for another enviornment, just add &lt;code&gt;--environment &amp;lt;env&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;Available commands&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;rails credentials:show [--environment &amp;lt;env&amp;gt;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rails credentials:edit [--environment &amp;lt;env&amp;gt;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rails credentials:help&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example: &lt;code&gt;rails credentials:edit --environment production&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;(Hint: &lt;code&gt;RAILS_ENV=&amp;lt;env&amp;gt; rails credentials:show&lt;/code&gt; won&amp;rsquo;t work. &lt;code&gt;--environment&lt;/code&gt; must be used instead.)&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;How Rails behaves&lt;/h4&gt;

&lt;p&gt;Rails continues to use the 5.2-compatible files (&lt;code&gt;config/master.key&lt;/code&gt; &amp;amp; &lt;code&gt;config/credentials.yml.enc&lt;/code&gt;) in the absence of an environment-specific file.&lt;/p&gt;

&lt;p&gt;If an environment-specific file is available, then that is used instead (and the default file is &lt;em&gt;ignored&lt;/em&gt; &amp;ndash; they are not merged). This is convenient when you want multiple environments, eg: development and test, to both use the same file. In this example, use the default file for those two environments, and then provide an environment-specific file for production only.&lt;/p&gt;

&lt;p&gt;For reference, Rails will look in the following places for the master key for decryption:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ENV[&amp;#39;RAILS_MASTER_KEY&amp;#39;]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config/credentials/&amp;lt;env&amp;gt;.key&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config/master.key&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And it will look for the actual encrypted credentials at these locations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;config/credentials/&amp;lt;env&amp;gt;.yml.enc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;config/credentials.yml.enc&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting55</id>
    <published>2017-11-16T21:41:00Z</published>
    <updated>2019-05-13T00:22:08Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2017/11/replacing-rails-51-asset-pipeline-with-webpacker-3"/>
    <title>Replacing the Rails 5.1 asset pipeline with webpacker 3</title>
    <content type="html">&lt;p&gt;My last post was about &lt;a href="/posting/2017/11/using-webpacker-3-on-rails-51"&gt;using &lt;code&gt;webpacker&lt;/code&gt; v3 on Rails 5.1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This time I want to explore how to replace the traditional &lt;code&gt;sprockets&lt;/code&gt;-based asset pipeline completely.&lt;/p&gt;

&lt;p&gt;Our goal will be to add Bootstrap v4 and jQuery v3 to an app, handled entirely through &lt;code&gt;webpacker&lt;/code&gt;. We won&amp;rsquo;t even install the sprockets related gems.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ll also enable &lt;code&gt;rails-ujs&lt;/code&gt;, &lt;code&gt;turbolinks&lt;/code&gt;, and even images using webpacker.&lt;/p&gt;
&lt;a id="more"&gt;&lt;/a&gt;
&lt;h2&gt;First steps&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s start with a new app:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;rails new look_ma_no_sprockets --skip-spring --skip-sprockets --webpack&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that &lt;code&gt;Gemfile&lt;/code&gt; is rather sparse and leaves out all the sprockets related gems.&lt;/p&gt;

&lt;p&gt;Next, create a controller, skipping the default assets that would be for sprockets:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;rails g controller home index --no-assets

# We'll need these in a minute:
mkdir -p app/javascript/stylesheets app/javascript/images&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And make the new route the default in &lt;code&gt;config/routes.rb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="constant"&gt;Rails&lt;/span&gt;.application.routes.draw &lt;span class="keyword"&gt;do&lt;/span&gt;
  root &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;home#index&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;a href="https://github.com/zarqman/look_ma_no_sprockets/tree/17b46d05ff65acd1bad31a022ffde2e5d868fef4"&gt;See app at this stage&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Plumbing in webpacker&lt;/h2&gt;

&lt;p&gt;Now let&amp;rsquo;s adjust our layout file to use webpacker assets.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt;, replace the default stylesheet and javascript tags with their webpacker equivalents:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="tag"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="tag"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;LookMaNoSprockets&lt;span class="tag"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;&amp;lt;%=&lt;/span&gt; csrf_meta_tags &lt;span class="inline-delimiter"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;&amp;lt;%=&lt;/span&gt; stylesheet_pack_tag &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;application&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="key"&gt;media&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;all&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="key"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;data-turbolinks-track&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;reload&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="inline-delimiter"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;&amp;lt;%=&lt;/span&gt; javascript_pack_tag &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;application&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="key"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;data-turbolinks-track&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;reload&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="inline-delimiter"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="tag"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&amp;rsquo;ll be creating all stylesheets in &lt;code&gt;app/javascript/stylesheets/&lt;/code&gt;. Yes, it&amp;rsquo;s a bit of an odd place, but it keeps everything for webpacker in &lt;code&gt;app/javascript/&lt;/code&gt;, which is especially helpful if you decide to use both sprockets and webpacker.&lt;/p&gt;

&lt;p&gt;Create &lt;code&gt;app/javascript/stylesheets/application.scss&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;.webpacker-test {
  color: blue;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add this line to the bottom of &lt;code&gt;app/javascript/packs/application.js&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;require.context(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;../stylesheets/&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="predefined-constant"&gt;true&lt;/span&gt;, &lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;^&lt;/span&gt;&lt;span class="content"&gt;\.&lt;/span&gt;&lt;span class="content"&gt;\/&lt;/span&gt;&lt;span class="content"&gt;[^_].*&lt;/span&gt;&lt;span class="content"&gt;\.&lt;/span&gt;&lt;span class="content"&gt;(css|scss|sass)$&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="modifier"&gt;i&lt;/span&gt;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;FYI, the &lt;code&gt;true&lt;/code&gt; in the second argument is whether to search all subdirectories. We&amp;rsquo;ll leave it as true here, but know that you can restrict which directories are searched if you need to.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s also replace &lt;code&gt;app/views/home/index.html.erb&lt;/code&gt; with a few things to help us check our progress:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="tag"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Home&lt;span class="tag"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

&lt;span class="tag"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="attribute-name"&gt;class&lt;/span&gt;=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;webpacker-test&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;
  I will be blue if webpacker's CSS is working.
&lt;span class="tag"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="tag"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="attribute-name"&gt;class&lt;/span&gt;=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;bootstrap-test text-success&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;
  I will be green if bootstrap is working.
&lt;span class="tag"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

&lt;span class="tag"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="attribute-name"&gt;class&lt;/span&gt;=&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;jquery-test&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;span class="tag"&gt;&amp;gt;&lt;/span&gt;
  jQuery is not yet working.
&lt;span class="tag"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="tag"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
&lt;span class="inline"&gt;  &lt;span class="predefined"&gt;$&lt;/span&gt;(&lt;span class="keyword"&gt;function&lt;/span&gt;(){
    &lt;span class="predefined"&gt;$&lt;/span&gt;(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;.jquery-test&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;).html(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;span class="content"&gt;jQuery is working.&lt;/span&gt;&lt;span class="delimiter"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;);
  });&lt;/span&gt;
&lt;span class="tag"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once this is in place, go ahead and fire up &lt;code&gt;rails server&lt;/code&gt; and check your work at &lt;code&gt;http://localhost:3000/&lt;/code&gt;. You should see the &amp;ldquo;blue&amp;rdquo; test pass, but not the other two (yet).&lt;/p&gt;

&lt;p&gt;Your browser&amp;rsquo;s console log should also show &amp;ldquo;Hello World from Webpacker&amp;rdquo;. (If you don&amp;rsquo;t see it, make sure you&amp;rsquo;re showing all logs, not just errors.)&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://github.com/zarqman/look_ma_no_sprockets/tree/b78e17d2da792a014da9c56db72be1904cbaada1"&gt;See app at this stage&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Adding jQuery and Bootstrap&lt;/h2&gt;

&lt;p&gt;Now let&amp;rsquo;s get Bootstrap going. Since Bootstrap depends on jQuery and popper.js, we&amp;rsquo;ll handle those too.&lt;/p&gt;

&lt;p&gt;As of this writing, Bootstrap 4 is at beta 2. Once v4 is fully released, you can drop the &lt;code&gt;@version&lt;/code&gt; part off the end.&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;yarn add jquery popper.js bootstrap@4.0.0-beta.2

cp node_modules/bootstrap/scss/_variables.scss app/javascript/stylesheets/
ruby -pi -e 'gsub(/ !default/, &amp;quot;&amp;quot;)' app/javascript/stylesheets/_variables.scss&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last two lines above prepare a copy of Bootstrap&amp;rsquo;s variables for your app to customize. We won&amp;rsquo;t customize it here, but it&amp;rsquo;ll be ready for you later.&lt;/p&gt;

&lt;p&gt;Next, add the following three lines to the top of &lt;code&gt;app/javascript/stylesheets/application.scss&lt;/code&gt;. These will instruct our app to use Bootstrap&amp;rsquo;s CSS.&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="directive"&gt;@import&lt;/span&gt; &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;~bootstrap/scss/functions&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;;
&lt;span class="directive"&gt;@import&lt;/span&gt; &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;variables&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;;
&lt;span class="directive"&gt;@import&lt;/span&gt; &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;~bootstrap/scss/bootstrap&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We also need to import &lt;code&gt;jquery&lt;/code&gt; and &lt;code&gt;bootstrap&lt;/code&gt; in our &lt;code&gt;app/javascript/packs/application.js&lt;/code&gt;. Here&amp;rsquo;s the complete new file:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="reserved"&gt;import&lt;/span&gt; &lt;span class="predefined"&gt;$&lt;/span&gt; from &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;jquery&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
global.&lt;span class="predefined"&gt;$&lt;/span&gt; = &lt;span class="predefined"&gt;$&lt;/span&gt;
global.jQuery = &lt;span class="predefined"&gt;$&lt;/span&gt;

&lt;span class="reserved"&gt;import&lt;/span&gt; &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;bootstrap&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;

require.context(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;../stylesheets/&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="predefined-constant"&gt;true&lt;/span&gt;, &lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;^&lt;/span&gt;&lt;span class="content"&gt;\.&lt;/span&gt;&lt;span class="content"&gt;\/&lt;/span&gt;&lt;span class="content"&gt;[^_].*&lt;/span&gt;&lt;span class="content"&gt;\.&lt;/span&gt;&lt;span class="content"&gt;(css|scss|sass)$&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="modifier"&gt;i&lt;/span&gt;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally, we need to help jQuery and popper.js be seen by other .js files you&amp;rsquo;ll write. Replace &lt;code&gt;config/webpack/environment.js&lt;/code&gt; with the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;const { environment } = require(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;@rails/webpacker&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)

const webpack = require(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;webpack&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)
environment.plugins.set(
  &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;Provide&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;,
  &lt;span class="keyword"&gt;new&lt;/span&gt; webpack.ProvidePlugin({
      &lt;span class="predefined"&gt;$&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;jquery&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;,
      &lt;span class="key"&gt;jQuery&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;jquery&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;,
      &lt;span class="key"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;window.jQuery&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;jquery&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;,
      &lt;span class="key"&gt;Popper&lt;/span&gt;: [&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;popper.js&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;default&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;],
  })
)

module.exports = environment&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you reload the page in your browser, you should now see some green text indicating Bootstrap&amp;rsquo;s CSS is working. The jQuery message should also have changed to show it is also working.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://github.com/zarqman/look_ma_no_sprockets/tree/a96a1c5b59517967ee56e505f35fb45446759edc"&gt;See app at this stage&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;rails-ujs and turbolinks&lt;/h2&gt;

&lt;p&gt;If you want to use rails-ujs (and you probably do, since Rails 5.1 now encourages remote/ajax forms), we now install it via yarn too.&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;yarn add rails-ujs&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, to &lt;code&gt;app/javascript/packs/application.js&lt;/code&gt;, add:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="reserved"&gt;import&lt;/span&gt; Rails from &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;rails-ujs&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
Rails.start()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;a href="https://github.com/zarqman/look_ma_no_sprockets/tree/a2baaf3e622ab47726d30ac9ad80f8d79c62e7a1"&gt;See app at this stage&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Adding turbolinks is similar.&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;yarn add turbolinks&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;app/javascript/packs/application.js&lt;/code&gt;, add:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="reserved"&gt;import&lt;/span&gt; Turbolinks from &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;turbolinks&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
Turbolinks.start()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;a href="https://github.com/zarqman/look_ma_no_sprockets/tree/06eb4c212617a90a485ca01b061aa45495b77c86"&gt;See app at this stage&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Images&lt;/h2&gt;

&lt;p&gt;Images work a bit like stylesheets, in that they&amp;rsquo;ll be placed in &lt;code&gt;app/javascript/images/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Add this to &lt;code&gt;app/javascript/packs/application.js&lt;/code&gt;, right after to the stylesheets line:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;require.context(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;../images/&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="predefined-constant"&gt;true&lt;/span&gt;, &lt;span class="regexp"&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="content"&gt;\.&lt;/span&gt;&lt;span class="content"&gt;(gif|jpg|png|svg)$&lt;/span&gt;&lt;span class="delimiter"&gt;/&lt;/span&gt;&lt;span class="modifier"&gt;i&lt;/span&gt;&lt;/span&gt;)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Using images (or other similar assets) within Rails views looks a little bit different from before. Use &lt;code&gt;asset_pack_path()&lt;/code&gt; inside the main asset helper, like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;&amp;lt;%=&lt;/span&gt; image_tag(asset_pack_path(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;images/abc.svg&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;)) &lt;span class="inline-delimiter"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(&lt;a href="https://github.com/zarqman/look_ma_no_sprockets/tree/8a028e0f78ed2842aacb6951ee4384cb6df15162"&gt;See app at this stage&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Wrapping it up&lt;/h2&gt;

&lt;p&gt;That should be about everything. If you find a better way to do some part of this, please add a comment below.&lt;/p&gt;

&lt;p&gt;For that matter, I&amp;rsquo;d love to hear how it goes for you.&lt;/p&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting54</id>
    <published>2017-11-08T23:27:00Z</published>
    <updated>2019-05-13T00:22:08Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2017/11/using-webpacker-3-on-rails-51"/>
    <title>Using Webpacker 3 on Rails 5.1</title>
    <content type="html">&lt;p&gt;I recently started a new Rails 5.1 project. I wanted to try out &lt;code&gt;webpacker&lt;/code&gt;, which is now at version 3. Turns out, the webpacker team has been working hard to simplify things and they&amp;rsquo;ve accomplished quite a bit. Most posts online talk about v1 or v2, and they include a lot more steps than are now necessary. &lt;/p&gt;

&lt;p&gt;My goal here is to show how to use webpacker alongside the traditional asset pipeline (sprockets). The next post will show how to &lt;a href="/posting/2017/11/replacing-rails-51-asset-pipeline-with-webpacker-3"&gt;completely replace the asset pipeline with webpacker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For reference, I&amp;rsquo;m working with ruby 2.4.2, rails 5.1.4, webpacker 3.0.2, node 8.7.0, and yarn 1.2.1.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s dive into the now-simplified webpacker world.&lt;/p&gt;
&lt;a id="more"&gt;&lt;/a&gt;
&lt;h2&gt;Installing node and yarn&lt;/h2&gt;

&lt;p&gt;First things first. You&amp;rsquo;ll need a functioning copy of &lt;code&gt;node&lt;/code&gt; and &lt;code&gt;yarn&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On macOS, these are both easily installed using homebrew.&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;brew install node yarn&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Obviously you&amp;rsquo;ll need ruby and rails installed too. Since that&amp;rsquo;s well covered elsewhere, I won&amp;rsquo;t repeat it here.&lt;/p&gt;

&lt;h2&gt;Creating the app&lt;/h2&gt;

&lt;p&gt;Rails and webpacker provide automatic integration with a handful of popular javascript frameworks. Just for fun, we&amp;rsquo;ll choose react this time around.&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;rails new webpacker3_example --skip-spring --webpack=react&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you had all the prerequisites in place, not only was &lt;code&gt;bundle install&lt;/code&gt; run automatically, but so was &lt;code&gt;yarn install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://github.com/zarqman/webpacker3_example/tree/a103d9d19366934757015149ef775e424bc679d2"&gt;See app at this stage&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Rendering a React component&lt;/h2&gt;

&lt;p&gt;Now let&amp;rsquo;s create a controller that will render the default react component.&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;rails g controller home index&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In &lt;code&gt;config/routes.rb&lt;/code&gt;, make the new route the default:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="constant"&gt;Rails&lt;/span&gt;.application.routes.draw &lt;span class="keyword"&gt;do&lt;/span&gt;
  root &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;home#index&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By default, webpacker 3 is now integrated into the rails server process and will automatically compile all packs inside &lt;code&gt;app/javascript/packs/&lt;/code&gt;. There is no longer any need to run an external webpack-dev-server process. All you need to do is reference one or more .js files inside &lt;code&gt;packs/&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s do that now by adding the following line inside the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; section of our primary layout at &lt;code&gt;app/views/layouts/application.html.erb&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;&lt;span class="tag"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="comment"&gt;&amp;lt;!-- [existing html tags] --&amp;gt;&lt;/span&gt;
  &lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;&amp;lt;%=&lt;/span&gt; javascript_pack_tag &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;hello_react&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt; &lt;span class="inline-delimiter"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class="tag"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&amp;rsquo;s test it by going to &lt;code&gt;http://localhost:3000/&lt;/code&gt; in our browser. You should see:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;Home#index

Find me in app/views/home/index.html.erb

Hello React!&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &amp;ldquo;Hello React!&amp;rdquo; is at the bottom, then everything&amp;rsquo;s working properly!&lt;/p&gt;

&lt;p&gt;And that&amp;rsquo;s it. Nothing more is required any more. &lt;code&gt;webpacker&lt;/code&gt; takes care of it all.&lt;/p&gt;

&lt;p&gt;(&lt;a href="https://github.com/zarqman/webpacker3_example/tree/502a514564e79b43e29142fc6bb84e35214724de"&gt;See app at this stage&lt;/a&gt;)&lt;/p&gt;

&lt;h2&gt;Next steps&lt;/h2&gt;

&lt;p&gt;From here, if you need to install a new js package, use &lt;code&gt;yarn add &amp;lt;package_name&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you (or a colleague) are pulling your code onto a fresh box, you may need to run &lt;code&gt;yarn install&lt;/code&gt; to install all the node packages. Basically, anytime you need to run &lt;code&gt;bundle install&lt;/code&gt;, plan to run &lt;code&gt;yarn install&lt;/code&gt; next. This is true on your dev box and on production servers or containers.&lt;/p&gt;

&lt;p&gt;When going into production, the webpack assets are now automatically compiled as part of the traditional &lt;code&gt;rails assets:precompile&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;So there you have it. Yes, it really is that straightforward now to get up and running with webpacker 3 and rails 5.1.&lt;/p&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting53</id>
    <published>2017-10-10T03:55:00Z</published>
    <updated>2019-05-13T00:22:08Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2017/10/benchmarking-geoip-gems"/>
    <title>Benchmarking GeoIP gems for Ruby</title>
    <content type="html">&lt;p&gt;On a recent project, I had need again to use &lt;a href="http://dev.maxmind.com/geoip/geoip2/geolite2/"&gt;GeoIP&lt;/a&gt; (by the lovely people at &lt;a href="https://maxmind.com/"&gt;MaxMind&lt;/a&gt;). I decided to take some time to benchmark a handful of various GeoIP gems, both for GeoIP v1 (legacy) and the newer GeoIP v2.&lt;/p&gt;

&lt;p&gt;I decided to benchmark the extraction of 3 pieces of data, using the GeoIP Lite City database:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2-character ISO country code (eg: US)&lt;/li&gt;
&lt;li&gt;Full region name (eg: Colorado)&lt;/li&gt;
&lt;li&gt;Timezone (eg: America/Denver)&lt;/li&gt;
&lt;/ul&gt;
&lt;a id="more"&gt;&lt;/a&gt;
&lt;p&gt;Entries are labeled according to the installed gem name. Gems with &amp;ldquo;1&amp;rdquo; use the v1 GeoIP database. Those with &amp;ldquo;2&amp;rdquo; use the v2 database.&lt;/p&gt;

&lt;p&gt;Gems labeled with &amp;ldquo;rb&amp;rdquo; are pure ruby. Those with &amp;ldquo;c&amp;rdquo; have C extensions.&lt;/p&gt;

&lt;p&gt;3 of the tested gems do not return a timezone. Those 3 libraries turned out to be the 3 fastest, strongly suggesting that retrieving a more complete set of data from the GeoIP dataset does come with increased overhead. These 3 gems are labeled with &amp;ldquo;-tz&amp;rdquo; in the results below.&lt;/p&gt;

&lt;p&gt;Lastly, the &lt;code&gt;geoip&lt;/code&gt; gem has the option of preloading the entire GeoIP database into memory. It was benchmarked without and with preloading.&lt;/p&gt;

&lt;p&gt;Without further ado, here are the results, based on 100,000 iterations (ordered by real time):&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;user     system      total        real
geoip-c (1;c) -tz           0.520000   0.010000   0.530000 (  0.533592)
geoip2_compat (2;c) -tz     0.520000   0.020000   0.540000 (  0.534711)
mmdb (2;c) -tz              0.700000   0.010000   0.710000 (  0.725789)
hive_geoip2 (2;c)           3.470000   0.010000   3.480000 (  3.495051)
geoip (1;rb;preload)        3.580000   0.000000   3.580000 (  3.583469)
geoip (1;rb)                4.780000   1.740000   6.520000 (  6.542248)
maxmind_geoip2 (2;c)       12.420000   4.670000  17.090000 ( 17.092035)
maxminddb (2;rb)           27.730000   0.030000  27.760000 ( 27.781552)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As noted earlier, the 3 fastest libraries (&lt;code&gt;geoip2_compat&lt;/code&gt;, &lt;code&gt;geoip-c&lt;/code&gt;, and &lt;code&gt;mmdb&lt;/code&gt;) all have C extensions and all skip timezone loading.&lt;/p&gt;

&lt;p&gt;The next fastest, and also the overall fastest to return a full response from the database, is &lt;code&gt;hive_geoip2&lt;/code&gt;. The API for this gem is rather basic, but it&amp;rsquo;s arguably a very worthwhile tradeoff given its high performance.&lt;/p&gt;

&lt;p&gt;Right behind it is the preload-flavor of the pure Ruby &lt;code&gt;geoip&lt;/code&gt; gem, which is quite impressive. Equally impressive is that the non-preload flavor of the same gem comes in right behind, taking only about twice as long to run.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;maxmind_geoip2&lt;/code&gt; is just slow. Digging into the code, it appears to open and close the database file descriptor on every lookup, resulting in a substantial performance penalty.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;maxminddb&lt;/code&gt; has a friendly API to work with, but I wonder if that&amp;rsquo;s perhaps the cause of its slower performance. That said, unless you&amp;rsquo;re processing a rather high rate of GeoIP lookups, this one is still worth a look.&lt;/p&gt;

&lt;p&gt;If you want a pure ruby solution, both &lt;code&gt;geoip&lt;/code&gt; for GeoIP v1 and &lt;code&gt;maxminddb&lt;/code&gt; for GeoIP v2 are both viable for modest volumes of lookups.&lt;/p&gt;

&lt;p&gt;For higher volumes, definitely use a gem with a C extension. If you need timezones, then &lt;code&gt;hive_geoip2&lt;/code&gt; is your best bet. If not, then you have several choices. Do remember that you&amp;rsquo;ll also need the underlying C library and headers installed before installing the gem. That&amp;rsquo;ll be &lt;code&gt;libgeoip&lt;/code&gt; for v1 and &lt;code&gt;libmaxminddb&lt;/code&gt; for v2.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve published the &lt;a href="https://gist.github.com/zarqman/1cac9fa17caaa39eca356fb33339b003"&gt;benchmark code&lt;/a&gt; if you&amp;rsquo;re interested. There are a couple of gem namespace conflicts. To run the benchmarks, set &lt;code&gt;PASS==1&lt;/code&gt; first and install the matching gems. Then set &lt;code&gt;PASS==2&lt;/code&gt; and install those gems, being careful to uninstall &lt;code&gt;geoip&lt;/code&gt;. If you want to return to pass 1, uninstall &lt;code&gt;geoip-c&lt;/code&gt;.&lt;/p&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting52</id>
    <published>2013-07-13T18:11:00Z</published>
    <updated>2019-05-13T00:22:08Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2013/07/using-mongoid-with-rails-4"/>
    <title>Using Mongoid with Rails 4</title>
    <content type="html">&lt;p&gt;Mongoid 3 is only compatible with Rails 3.x. Rails 4 requires Mongoid 4.&lt;/p&gt;

&lt;p&gt;However, as of this writing, Mongoid 4 is still in development. I&amp;rsquo;ve had success using the master branch though.&lt;/p&gt;

&lt;p&gt;In your &lt;code&gt;Gemfile&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;gem &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;mongoid&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="key"&gt;github&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;mongoid/mongoid&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;

&lt;span class="comment"&gt;# and if you use Sidekiq + Kiqstand:&lt;/span&gt;
gem &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;kiqstand&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="key"&gt;github&lt;/span&gt;: &lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;mongoid/kiqstand&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting51</id>
    <published>2013-07-11T14:47:00Z</published>
    <updated>2019-05-13T00:22:08Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2013/07/upgrading-to-rails-4-0"/>
    <title>Upgrading to Rails 4.0</title>
    <content type="html">&lt;p&gt;I&amp;rsquo;m busy upgrading several apps to Rails 4.0. As is to be expected, there are a few gotchas here and there. Most are documented somewhere&amp;hellip; deep in a changelog&amp;hellip; mixed in with dozens of other things that probably won&amp;rsquo;t bite you.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve been posting some of my notes along the journey. This particular post will serve as a central reference point, a table of contents of sorts, and will just contain links to other posts. I&amp;rsquo;ll try to keep it updated as I add new posts.&lt;/p&gt;

&lt;h3&gt;Overview&lt;/h3&gt;

&lt;p&gt;See the &lt;a href="http://guides.rubyonrails.org/upgrading_ruby_on_rails.html#upgrading-from-rails-3-2-to-rails-4-0"&gt;official Ruby on Rails article&lt;/a&gt; to start.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="/posting/2013/07/preparing-for-an-upgrade-to-rails-4-0"&gt;Preparing a Rails 3.2 app to be upgraded&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Models and datastores&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="/posting/2013/07/using-mongoid-with-rails-4"&gt;Using Mongoid&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Assets&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="/posting/2013/07/missing-assets-in-rails-4-0-part-1"&gt;Missing assets - whole directories (or gems) of assets missing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/posting/2013/07/missing-assets-in-rails-4-0-part-2"&gt;Missing assets - problems with assets referenced by CSS files&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Deployment&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="/posting/2013/07/errors-when-precompiling-assets-in-rails-4-0"&gt;Failure precompiling assets on the server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="/posting/2013/07/capistrano-errors-when-upgrading-to-rails-4"&gt;Capistrano deployment errors&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting50</id>
    <published>2013-07-09T17:00:00Z</published>
    <updated>2019-05-13T00:22:08Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2013/07/missing-assets-in-rails-4-0-part-2"/>
    <title>Missing assets in Rails 4.0 (part 2)</title>
    <content type="html">&lt;p&gt;In addition to the &lt;a href="/posting/2013/07/missing-assets-in-rails-4-0-part-1"&gt;asset path changes&lt;/a&gt; covered in part 1, there are some changes in how processed asset files are exposed to web clients.&lt;/p&gt;

&lt;p&gt;In this case, the problem shows up with asset files that are referenced by name without the md5 fingerprint. Previously, plain-named asset files were also exposed to the webserver. Now they don&amp;rsquo;t seem to be.&lt;/p&gt;

&lt;p&gt;The most likely culprit here are files referenced from within a CSS file, such as:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;src: font-url('custom-webfont.eot');

background: url('background.png');&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, you&amp;rsquo;ll need to use the asset_path helper like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class="CodeRay"&gt;src: url('&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;&amp;lt;%=&lt;/span&gt; asset_path(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;custom-webfont.eot&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="inline-delimiter"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;');

background: url('&lt;span class="inline"&gt;&lt;span class="inline-delimiter"&gt;&amp;lt;%=&lt;/span&gt; asset_path(&lt;span class="string"&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;span class="content"&gt;background.png&lt;/span&gt;&lt;span class="delimiter"&gt;'&lt;/span&gt;&lt;/span&gt;) &lt;span class="inline-delimiter"&gt;%&amp;gt;&lt;/span&gt;&lt;/span&gt;');&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You may need to rename your css file to enable ERB parsing, eg: &lt;code&gt;design.css&lt;/code&gt; becomes &lt;code&gt;design.css.erb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another possibility are hard-coded asset references in your view templates somewhere. Once again, change such references to use the &lt;code&gt;asset_path&lt;/code&gt; helper.&lt;/p&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
  <entry>
    <id>tag:iprog.com,2007:Posting49</id>
    <published>2013-07-08T16:04:00Z</published>
    <updated>2019-05-13T00:22:08Z</updated>
    <link rel="alternate" type="text/html" href="https://iprog.com/posting/2013/07/missing-assets-in-rails-4-0-part-1"/>
    <title>Missing assets in Rails 4.0 (part 1)</title>
    <content type="html">&lt;p&gt;The asset pipeline was introduced in Rails 3.1. It continues to exist in Rails 4 and has seen a number of changes.&lt;/p&gt;

&lt;p&gt;In one key change, Sprockets (the brains behind the asset pipeline) now looks in fewer places for asset files.&lt;/p&gt;

&lt;p&gt;In Rails 3, Sprockets looked in &lt;code&gt;app/assets&lt;/code&gt;, &lt;code&gt;lib/assets&lt;/code&gt;, and &lt;code&gt;vendor/assets&lt;/code&gt; for assets. Importantly, this applied not only to your main app, but also to any asset-providing gems, such as &lt;code&gt;font-awesome-rails&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In Rails 4, Sprockets only looks in &lt;code&gt;app/assets&lt;/code&gt; (both in your app and in gems). If you have any assets that aren&amp;rsquo;t working properly (most likely fonts, images, or CSS files not loading), first check for updated versions of any gems. &lt;/p&gt;

&lt;p&gt;If it&amp;rsquo;s your own gem or a gem that hasn&amp;rsquo;t been updated, it may be as simple as moving &lt;code&gt;lib/assets&lt;/code&gt; or &lt;code&gt;vendor/assets&lt;/code&gt; to &lt;code&gt;app/assets&lt;/code&gt;.&lt;/p&gt;

&lt;!--
For [problems with assets referenced from CSS files](/posting/2013/07/missing-assets-in-rails-4-0-part-2), see part 2.
--&gt;</content>
    <author>
      <name>tm</name>
    </author>
  </entry>
</feed>
