Upgrade guide for moving a Rails app from Webpack 3 to Webpack 4
Webpacker is Rails' way of integrating Webpack, and version 4 has been released just a few days ago, allowing us to use Webpack 4.
I successfully upgraded an existing real-world Webpack 3 application. Below are notes on everything that I encountered.
Note that we prefer not using the Rails asset pipeline at all and serving all assets through Webpack for the sake of consistency.
Preparations
- Remove version locks in
Gemfileforwebpacker - Remove version locks in
package.jsonforwebpackandwebpack-dev-server - Install by ca...
Carrierwave: Built-in resize methods
Carrierwave includes some handy helper methods you can use to resize your images. Here is a quick summary of them, if you need more details read the docs. You can also use all command line options from RMagick directly if these helpers are not good enough for you.
resize_to_limit(width, height)
resize_to_fit(width, height)
resize_to_fi...
JavaScript without jQuery
This is a presentation from 2019-01-21.
Summary
- We want to move away from jQuery in future projects
- Motivations are performance, bundle size and general trends for the web platform.
- The native DOM API is much nicer than it used to be, and we can polyfill the missing pieces
- Unpoly 0.60.0 works with or without jQuery
Is jQuery slow?
From: Sven
To: unpoly@googlegroups.com
Subject: performance on smartphones and tablets
Hello
I just used your framework in one project and must say,
I am really pleased with it -- but o...
How not to turn your application into a spam relay
Spammers have started abusing other application to send their spam. This works like this:
- The application has some form that allows to send e-mails to arbitrary users. This can be something like a newsletter sign-up with a double-opt in, a registration confirmation e-mail (or even password reset e-mail), or something similar.
- The e-mail also includes some reflected text. For example, a user may be able to give their name, and the name is used within the e-mail. The spammer will then abuse that text to include his advertisment.
Potentia...
Auto-generating plain-text bodies for HTML e-mails in Rails apps
When building an application that sends e-mails to users, you want to avoid those e-mails from being classified as spam. Most obvious scoring issues will not be relevant to you because you are not a spammer.
However, your application must do one thing by itself: When sending HTML e-mails, you should include a plain-text body or tools like SpamAssassin will apply a significant score penalty. Here is how to do that automatically.
- Add
premailer-railsto yourGemfileandbundle. - Done! ...
Upgrading Ruby from 1.8.7 to 2.3.5
Suggested Workflow
Set the ruby version in .ruby-version to 2.3.5, then perform these steps one by one, fixing errors as they occur:
- Update gems as listed below, and bundle
- Boot a Rails console - see below for a list of changes you will probably need
- Run Specs with
--backtraceoption - Run Cucumber features (with Geordi's
--debugoption) - When all tests are green, look through your Gemfile and remove as many version constraints as possible.
- Boot the application in different environements to spot further issues, e...
Ruby: Reading and writing CSVs
In ruby you can easily read and write CSVs with the standard CSV library class.
On top of this, you can use the gem smarter_csv for reading (not writing) CSVs in a more comfortable way:
- Keep in mind, that the development of this gem is in an unknown state and the 2.0 release seems to happen never
- The API will change completely for 2.0, so you might find a bunch of unrelated documentation for 1.2
Here is an example...
How to: Use Ace editor in a Webpack project
The Ace editor is a great enhancement when you want users to supply some kind of code (HTML, JavaScript, Ruby, etc).
It offers syntax highlighting and some neat features like auto-indenting.
For Webpack 3+
Integrate as described in the documentation. For example load ace Editor like this:
function loadAceEditor() {
return import(/* webpackChunkName: "ace" */ 'ace-builds/src-noconflict/ace').then(() => {
return import(/* webpackChunkName: "ace" */ 'ace-builds/webpack-r...
Rubymine FileType mismatch
If your Rubymine does not recognize a file type correctly although you have entered the unmistakeable file extension like material_orders_controller.rb, this may help you:
Causing the Problem
Sometimes you create a new file and forget to enter the ending like material_orders_controller
Rubymine handles such files per default as simple txt files.
You delete this file and create a new one with correct ending: material_orders_controller.rb. But still Rubymine treats this file as text file, no highlighting is available.
What happene...
How to: expand an element's cover area beyond its container
Occasionally, your designer will hand you designs where elements break the layout's horizontal container width, like navigation buttons of a slider that should be at the left/right of the browser window, or simply by applying a background color that reaches until the left and right of the browser window.
In the past, we've done some horrible things to achieve that. Like margin: 0 -10000px plus overflow-x: hidden.
There is a much saner approach.
Consider the following markup:
<body>
<div class="container">
<div class="sec...
Katapult 0.5.0 released
New Features
- Deployment ready for Opscomplete
- Copying view and controller templates over to target application during
basics configuration or via new commandkatapult templates. - "Usage" section in README rewritten: Now describes two usage scenarios.
Improvements
- Generating a fixed Gemfile.lock. Run
bundle updateafter code generation to
update all gems to recent versions. - Better deployment with Webpack
- Navigation only rendered if requested
- Some minor fixes
jQuery: How to remove classes from elements using a regular expression
jQuery's removeClass removes the given class string from an element collection. If you want to remove multiple/unknown classes matching a given pattern, you can do that.
For example, consider a DOM node for the following HTML. We'll reference it by $element below.
<div class="example is-amazing is-wonderful"></div>
Option A: Selecting classes, then removing them
You can iterate over existing classes, and select matching ones. The example below is ES6, on ES5 could write something similar using jQuery.grep.
let classes ...
Accessing Rails config in webpack(er)
It is possible to access Rails config (for example secrets) from within your webpack bundles, thanks to rails-erb-loader. When using webpacker, the setup is like this:
-
Install
rails-erb-loader:yarn add rails-erb-loader -
Add this to your
config/webpacker/environment.js:environment.loaders.prepend('erb', { test: /\.erb$/, enforce: 'pre', use: [{ loader: 'rails-erb-loader', }] }) -
Start using erb. For examp...
Does <html> or <body> scroll the page?
TL;DR: All modern browsers default to using the <html> element as the main document viewport. In CSS, prefer to set overflow properties to html (or :root).
Scrolling the main viewport with JavaScript
The browser's main document viewport is also scrollable by default. The element that corresponds to the main viewport is either <html> (document.documentElement) or <body> (document.body). Which one depends on the browser.
When you want to update the current `sc...
Raising JavaScript errors in Ruby E2E tests (RSpec, Cucumber)
A JavaScript error in an E2E test with Selenium will not cause your test to fail. This may cause you to miss errors in your frontend code.
Using the BrowserConsole helper below you can check your browser's error console from your E2E tests.
The following will raise BrowserConsole::ErrorsPresent if there is an error on the browser console:
BrowserConsole.assert_no_errors!
Ignoring errors
You can ignore errors by their exact message:
BrowserConsole.ignore('Browser is burning')
You can ignore errors with me...
HTML file inputs support picking directories
HTML's <input type="file"> accepts a single file. You can allow multiple files via <input type="file" multiple>.
But sometimes, selecting multiple files is not enough and can be cumbersome for the user. Enter webkitdirectory:
<input type="file" webkitdirectory multiple>
Using webkitdirectory switches the browser's file picker to select a directory. All files inside that directory, and inside any nested subdirectories, will be selected for the file input.
This can be useful when users want to upload all files from a nested dire...
Rails < 5: How to get after_commit callbacks fired in tests
If you use transactional_fixtures or the database_cleaner gem with strategy :transaction, after_commit callbacks will not be fired in your tests.
Rails 5+
Rails 5 has a fix for this issue and no further action is needed.
Rails 3, Rails 4
Add the gem test_after_commit to your test group in the Gemfile and you are done. You don't need to change the database strategy to deletion (wh...
Do not use "flex: 1" or "flex-basis: 0" inside "flex-direction: column" when you need to support IE11
Flexbox is awesome. Most of it even works in IE11, but flex: 1 won't work reliably in Internet Explorer.
This it because implicitly sets flex-basis: 0 which IE fails to support properly.
Example
Consider the following HTML and CSS.
<div class="container">
<div class="child">
foo
</div>
<div class="bar">
bar
</div>
</div>
.container {
display: flex;
flex-direction: column;
}
.child {
flex: 1;
}
See it in action at Plunker.
Background
...
HTML forms with multiple submit buttons
Most forms have a single submit button that will save the record when pressed.
Sometimes a form needs additional submit buttons like "accept" or "reject". Such buttons usually attempt a state transition while updating the record.
To process a form with multiple buttons, your server-side code will need to know which button was pressed. To do so you can give each submit button a different [formaction] attribute. This will override the ...
Project management best practices: The story tracker
In general, the tracker should always be the definitive source of truth of what needs to be done as part of a project. If you identify a task that needs to be done, you should create a story. If you learn something that contradicts an existing story, change it.
The tracker can contain two types of stories: Developer stories, and non-developer stories.
Non-developer stories
Non-developer stories should be clearly marked. They usually belong to the PM (or maybe people from the operations team). Those story can take all forms, could just...
How to make changes to a Ruby gem (as a Rails developer)
At makandra, we've built a few gems over the years. Some of these are quite popular: spreewald (> 1M downloads), active_type (> 1M downloads), and geordi (> 200k downloads)
Developing a Ruby gem is different from developing Rails applications, with the biggest difference: there is no Rails. This means:
- no defined structure (neither for code nor directories)
- no autoloading of classes, i.e. you need to
requireall files yourself - no
active_supportniceties
Also, their scope...
Chrome bug: Wrong stacking order when transitioning composited elements
Google Chrome has a subtle rendering bug that hits me once in a while. It usually occurs in sliders with HTML content.
The issue
When a slider contains a composited[1] element, the element will overlap any other element when sliding, being rendered as frontmost element. After the slider has settled, stacking order jumps back to normal.
It seems like Chrome is doing its compositing wrong. This doesn't happen in Firefox.
The cause
The issue only occurs if:
- two elements A and B are nested inside an element C
- A overlaps B (part...
Haml: Generating a unique selector for an element
Having a unique selector for an element is useful to later select it from JavaScript or to update a fragment with an Unpoly.
Haml lets you use square brackets ([]) to generate a unique class name and ID from a given Ruby object. Haml will infer a class attribute from the given object's Ruby class. It will also infer an id attribute from the given object's Ruby class and #id method.
This is especially useful with ActiveRecord instances, which have a persisted #id and will hence **generate the same selector o...
Haml: Prefixing a group of attributes
Haml lets you prefix a group of attributes by wrapping them in a hash. This is only possible with the {} attribute syntax, not with the () attribute syntax.
Example: HTML5 data attributes
HTML5 allows you to use arbitrary attributes like data-method and data-confirm. You can prefix a group of data- attributes like this:
%a{href: '/path', data: { method: 'delete', confirm: 'Really delete?' }} Label
This compiles to:
<a data-confirm='Really delete?' data-method='delete' href='/path'>Label</a>