Adding jQuery to Webpacker 6 under Rails 6

From time to time we post some notes about technical issues that we’ve encountered during our development work on Spiffy Stores. There are a lot of moving parts to manage, and sometimes we come across some tips or techniques that can help others to build their projects.

In this case, we’ve been looking at how to configure Webpacker 6 (currently Beta 7) under Rails 6.1, which acts as a wrapper to the latest version of Webpack 5. Now, as anyone who’s used Webpack since it was introduced as an option in Rails 5 will attest to, it’s not an easy package to get working properly.

The new versions of Webpacker and Webpack bring around some changes to the way things are configured, and unfortunately, some of the documentation is lacking, or indeed, wrong.

For our environment, we need jQuery as a starter. The trick with Webpack is to get the code loaded and assigned to the global variables, $ and jQuery. The trick with jQuery is to realize that the node modules version provides both a distributed module and also the source code which can be used to build the module with Webpack. If you just

require("jquery")

then you’ll get the pre-built module. It turns out that it’s better to build it from source instead.

If you’ve followed the migration documentation, you should have a custom.js under your webpack directory.

module.exports = {
   resolve: {
     alias: {
       jquery: 'jquery/src/jquery'
     }
   }
 }

Requiring jquery now, pulls in the source files instead, and this will build jQuery with the appropriate global references.

Another important “gotcha” with Webpacker 6 is that when you include the javascript_pack_tag in your layout, you MUST include it only once.

<%= javascript_pack_tag('application', 'common', 'customer', data: { turbolinks_track: :reload }) %>

Webpack builds a number of different file chunks for each entry point, and this means that the javascript_pack_tag will generate a number of <script> tags, one for each chunk. If you have multiple entry point files, then you must include them all on a single javascript_pack_tag and not create a separate tag for each entry point.

Unfortunately, coming from a Sprockets background, most Rails programmers will be used to creating multiple javascript_include_tags, but this is not the case for Webpacker.

If you happen to use multiple javascript_pack_tags, you’ll likely find that scripts may be loaded multiple times. In many cases, this may not be obvious, but if you see errors from @rails/ujs, then this is probably because it is being loaded multiple times by Webpack.

Problems rendering a layout in Rails3

From time to time we like to share technical tips when we’ve uncovered a solution to a problem that might help other Rails developers.

Spiffy Stores is written using the Ruby on Rails framework, and we encountered a glitch with the Rails3 layouts. Basically we couldn’t get the layout to display, even though all the syntax was correct. Others have experienced this sort of problem. See http://stackoverflow.com/questions/6605716/cant-render-layout-in-rails-3 for an example.

After lots of digging around and tracing, the answer became clear. The AbstractController::Layouts module has an initialize method, but this method was not being called when a new controller was created.

If you experience this problem, then check any modules that you have included in your controller, as one of them has an initialize method that doesn’t call ‘super’.

If an included module needs an initialize method, then it needs to follow this pattern:

[ruby]
def initialize(*)
# Module initialization code here
super
end
[/ruby]

If the call to ‘super’ isn’t included, then the initialization chain stops, and your controller won’t be properly initialized. You can find out all the included modules for a controller by executing this code from the console:

[ruby]
MyController.ancestors
[/ruby]

How to Fake an Uploaded File

Our store software contains an extensive set of routines for processing uploaded images and resizing them into various image sizes. We’ve recently been adding some code to support a bulk import function and it’s become necessary to somehow fake uploading a file, given a specific URL for an image.

The basic plan is to use Net::HTTP to connect to the remote server and grab the image and save it in a temporary file. It turns out that Rails contains a UploadedTempfile class which is a subclass of Tempfile, and this is used by the CGI routines to handle any uploaded files.

Continue reading