SameSite cookies
TL;DR Most web applications do not require action on this. SameSite=None
(old browser default) will continue to work, and SameSite=Lax
(new Chrome default, gradually rolled out) is an even better default for cookies. Set SameSite=Strict
only for extra security in special cases (see below). If your application is rendered in an iframe (e.g. a video player or some news stream), you need to configure its relevant cookies as SameSite=None
.
The SameSite
cookie attribute targets **c...
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
require
all files yourself - no
active_support
niceties
Also, their scope...
Rails asset pipeline: Using ESNext without a transpiler
If your app does not need to support IE11, you can use most ES6 features without a build step. Just deliver your plain JavaScript without transpilation through Babel or TypeScript, and modern browsers will run them natively.
Features supported by all modern browsers include:
- fat arrow functions (
() => { expr }
) -
let
/const
class
-
async
/await
- Promises
- Generators
- Symbols
- Rest arguments (
...args
) - Destructuring
You won't be able to use import
and export
, or use npm modules.
See this [ES6 compatibility mat...
Always disable autocomplete for date pickers
When we write a form with date fields, we often use graphical data picker like Rome to get a consistent calendar popup on all browsers.
When you integrate a date picker popup, remember to also set autocomplete="off"
on the text input that opens the calendar on click
. Otherwise the autocomplete suggestions will cover the calendar box and make it unusable:
If you are using a tool like Unpoly you might want to set autocomplete="off"
i...
A reasonable default CSP for Rails projects
Every modern Rails app should have a Content Security Policy enabled.
Very compatible default
The following "default" is a minimal policy that should
- "just work" for almost all applications
- give you most of the benefits of a CSP
In your config/initializers/content_security_policy.rb
, set
Rails.application.config.content_security_policy do |policy|
policy.object_src :none
policy.script_src :unsafe_eval, :strict_dynamic, :https # Browsers with support for "'strict-dynamic'" will ignore "https:"
po...
Rails asset pipeline: Why relative paths can work in development, but break in production
The problem
When using the asset pipeline your assets (images, javascripts, stylesheets, fonts) live in folders inside app
:
app/assets/fonts
app/assets/images
app/assets/javascripts
app/assets/stylesheets
With the asset pipeline, you can use the full power of Ruby to generate assets. E.g. you can have ERB tags in your Javascript. Or you can have an ERB template which generates Haml which generates HTML. You can chain as many preprocessors as you want.
When you deploy, Rails runs assets:precompile
...
Matching line feeds with regular expressions works differently in every language
Although regular expression syntax is 99% interchangeable between languages, keep this in mind:
- By default, the dot character (
"."
) does not match a line feed (newline, line break,"\n"
) in any language. - Some languages allow you to modify the behavior of a regular expression by appending a modifier to the pattern expression. E.g.
/foo/i
makes the pattern case-insensitive in many languages. Note however that some of these modifiers may not exist or mean entirely different things in different languages. - Some languages have a m...
Use -webkit-line-clamp to natively truncate long (multi-line) texts with an ellipsis
Note: You won't need this for single lines of text. In this case it is better to just use the text-overflow
property: Use CSS "text-overflow" to truncate long texts
You can use -webkit-line-clamp
in your CSS/SASS to natively render an ellipsis (...
) after a specific amount of lines for a multi-line text in your HTML.
Earlier, it was necessary to implement JavaScript solutions like Superclamp.js to enable this because the browser support has been rather limited...
Webpack: How to avoid multiple versions of jQuery
To avoid multiple versions of a package, you can manually maintain a resolutions
section in your package.json
. We recommend you to do this for packages like jQuery. Otherwise the jQuery library attached to window
might not include the functions of your packages that depend on jQuery.
Note: This is only an issue in case you want to use a package functionality from window
e.g. $(...).datepicker()
from your dev console or any other javascript within the application.
Background
By default yarn will create a folder node_modules
...
HTTP 302 redirects for PATCH or DELETE will not redirect with GET
A HTTP 302 Found
redirect to PATCH
and DELETE
requests will be followed with PATCH
or DELETE
. Redirect responses to GET
and POST
will be followed with a GET
. The Rails form_for
helper will use a workaround to send POST
requests with a _method
param to avoid this issue for PATCH
/DELETE
.
If you make requests yourself, watch out for the following behavior.
When you make an AJAX request PATCH /foo
and the /foo
action redirects to /bar
, browsers will request PATCH /bar
. You probably expected the second requ...
Preventing users from uploading malicious content
When you allow file uploads in your app, a user might upload content that hurts other users.
Our primary concern here is users uploading .html
or .svg
files that can run JavaScript and possibly hijack another user's session.
A secondary concern is that malicious users can upload executables (like an .exe
or .scr
file) and use your server to distribute it. However, modern operating systems usually warn before executing files that were downloaded from t...
Ensure passing Jasmine specs from your Ruby E2E tests
Jasmine is a great way to unit test your JavaScript components without writing an expensive end-to-end test for every small requirement.
After we integrated Jasmine into a Rails app we often add an E2E test that opens that Jasmine runner and expects all specs to pass. This way we see Jasmine failures in our regular test runs.
RSpec
In a [feature spec](https://web.archive.org/web/20150201092849/http://www.rel...
How to configure Selenium WebDriver to not automatically close alerts or other browser dialogs
tl;dr
We recommend configuring Selenium's unhandled prompt behavior to "ignore".
When running tests in a real browser, we use Selenium. Each browser is controlled by a specific driver, e.g. Selenium::WebDriver::Chrome
for Chrome.
There is one quirk to all drivers (at least those following the W3C webdriver spec) that can be impractical:
When any user prompt (like an alert
) is encountered when trying to perform an action, they will [dismiss the dialog by default](https://w3c....
The developer console can do more than you think!
You can do so much more than console.log(...)
! See the attached link for a great breakdown of what the developer console can give you.
Some of my favorites:
console.log takes many arguments
E.g. console.log("Current string:", string, "Current number:", 12)
Your output can have hyperlinks to Javascript objects
E.g. console.log("Check out the current %o, it's great", location)
[Di...
Better numeric inputs in desktop browsers
You want to use <input type="number">
fields in your applications.
However, your desktop users may encounter some weird quirks:
- Aside from allowing only digits and decimal separators, an "e" is also allowed (to allow scientific notation like "1e3").
- Non-technical users will be confused by this.
- Your server needs to understand that syntax. If it converts only digits (e.g.
to_i
in Ruby) you'll end up with wrong values (like 1 instead o...
Capybara: Preventing server errors from failing your test
When your Rails application server raises error, Capybara will fail your test when it clears the session after the last step. The effect is a test that passes all steps, but fails anyway.
Capybara's behavior will help you to detect and fix errors in your application code. However, sometimes your application will explode with an error outside your control. Two examples:
- A JavaScript library references a source map in its build, but forgets to package the source map
- CarrierWave cleans up an upload or cache file after the record was delet...
How to create memory leaks in jQuery
jQuery doesn't store information about event listeners and data
values with the element itself. This information is instead stored in a global, internal jQuery cache object. Every time you add an event listener or data value to a jQuery object, the jQuery cache gains another entry.
The only way that a jQuery cache entry gets deleted is when you call remove()
on the element that put it there!
Since cache entries also have a pointer back to the element that spawned them, it is easy to create DOM elements that can never be garbage-co...
Popular mistakes when using nested forms
Here are some popular mistakes when using nested forms:
- You are using
fields_for
instead ofform.fields_for
. - You forgot to use
accepts_nested_attributes
in the containing model. Rails won't complain, but nothing will work. In particular,nested_form.object
will benil
. - The
:reject_if
option lambda in youraccepts_nested_attributes
call is defined incorrectly. Raise the attributes hash given to your:reject_if
lambda to see if it looks like you expect. - If you are nesting forms into nested forms, each model involved ne...
Mock the browser time or time zone in Selenium features
In Selenium features the server and client are running in separate processes. Therefore, when mocking time with a tool like Timecop, the browser controlled by Selenium will still see the unmocked system time.
timemachine.js allows you to mock the client's time by monkey-patching into Javascript core classes. We use timemachine.js in combination with the Timecop gem to synchronize the local browser time to the ...
Use <input type="number"> for numeric form fields
Any form fields where users enter numbers should be an <input type="number">
.
Numeric inputs have several benefits over <input type="text">
:
- On mobile or tablet devices, number fields show a special virtual keyboard that shows mostly digit buttons.
- Decimal values will be formatted using the user's language settings.
For example, German users will see1,23
for<input type="number" value="1.23">
. - Values in the JavaScript API or when submitting forms to the server will always use a point as decimal separator (i.e.
"1.23"
eve...
Google Analytics: Changing the tracked URL path
By default, Google Analytics tracks the current URL for every request. Sometimes you will want to track another URL instead, for example:
- When an application URL contains a secret (e.g. an access token)
- When you want to track multiple URLs under the same bucket
- When you want to track interactions that don't have a corresponding URL + request (e.g. a Javascript button or a PDF download)
Luckily the Analytics code snippet allows you to freely choose what path is being tracked. Simple change this:
ga('send', 'pageview');
......
HTML5: disabled vs. readonly form fields
Form fields can be rendered as noneditable by setting the disabled
or the readonly
attribute. Be aware of the differences:
disabled fields
- don’t post to the server
- don’t get focus
- are skipped while tab navigation
- available for
button
,fieldset
,input
,select
,textarea
,command
,keygen
,optgroup
,option
Browser specific behavior:
- IE 11: text inputs that are descendants of a disabled fieldset appear disabled but the user can still interact with them
- Firefox: selecting text in a disabled text field is no...
Chaining Capybara matchers in RSpec
You can chain multiple Capybara matchers on the page
or any element:
expect(page)
.to have_content('Example Course')
.and have_css('.course.active')
.and have_button('Start')
When you chain multiple matchers using and
, [Capybara will retry the entire chain](https://github.com/teamcapybara/capybara/blob/c0cbf4024c1abd48b0c22c2930e7b05af58ab284/lib/capybara/rspec/matc...
Migration from the Asset Pipeline to Webpacker
This is a short overview of things that are required to upgrade a project from the Asset Pipeline to Webpacker. Expect this upgrade to take a few days even the diff is quite small afterwards.
Preparations
1. Find all libraries that are bundled with the asset pipeline. You can check the application.js
and the application.css
for require
and import
statements. The source of a library is most often a gem or a vendor directory.
2. Find an working example for each library in the application and write it down.
3. Find out the ver...