Do not use "permit!" for params
Rails' Strong Parameters enable you to allow only specific values from request params
to e.g. avoid mass assignment.
Usually, you say something like params.permit(:email, :password)
and any extra parameters would be ignored, e.g. when calling to_h
.
This is excellent and you should definitely use it.
What is permit!
and why is it dangerous?
However, there is also params.permit!
whic...
Chromedriver issue #4550 breaks the user agent for device emulation via device name
Newest versions of Chromedriver breaks the user agent for device emulation via device name. In previous versions the user agent of the emulated device was set. In the newest versions the user agent differs from the emulated device.
- Version Chrome: 116.0.5845.110
- Version Chromedriver: 116.0.5845.96
- Bug: https://bugs.chromium.org/p/chromedriver/issues/detail?id=4550&q=userAgent&can=2
- Setting: https://chromedriver.chromium.org/capabilities
In Capybara an affected config looks like following:
Capybara.register_driver :mobi...
Minifying object properties in JavaScript files
An introduction to mangling
When you minify ("compress", "optimize") your JavaScript for production, the names of your functions and variables will be renamed for brevity. This process is often called mangling.
E.g. if this is your source code:
function function1() {
function2()
}
After mangling it would look like this:
function a() {
b()
}
Object properties are not mangled by default
Minfiers never mangle properties by default, as this can be an unsafe transformation. This leads to larger file sizes if...
Postgres in Alpine docker container: sorting order might differ
In CI test runs I noticed that string sorting order changed after switching from a debian-based PostgreSQL docker image to one that is based on Alpine Linux.
Debian image sorting: bar Bar foo Foo
Alpine image sorting: Bar Foo bar foo
Explanation
Alpine Linux is a very slim linux distribution that results in small docker image sizes (roughly 100MB instead of 150MB), so it's a popular choice. However, it does not have all comman locales installed and does not use all locales that a user installs by default.
Postgres orders string co...
Node: How to run a globally installed package with npx
You can tell npm
to install a package globally with npm -g install @puppeteer/browsers
. However, it seems that its not possible that npx
can run commands from global packages without referencing the global package path.
Example
Installing @puppeteer/browsers
globally:
$ npm -g install @puppeteer/browsers
The globally installed package @puppeteer/browsers
can not be access via npx
:
$ npx --no-install @puppeteer/browsers
npm ERR! canceled # Error message when package is not installed
But it is installed g...
RSpec: How to write isolated specs with cookies
Background
Rails offers several methods to manage three types of different cookies along with a session storage for cookies. These are normal, signed and encrypted cookies.
By following the happy path of testing a web application, that is only the main use-case is tested as a integration test and the rest as isolated (more unit ...
How to transition the height of elements with unknown/auto height
If you want to collapse/expand elements with dynamic content (and thus unknown height), you can not transition between height: 0
and height: auto
.
Doing it properly, with modern CSS features
In the past, you might have resorted to bulky JavaScript solutions or CSS hacks like transitioning between max-height: 0
and max-height: 9999px
. All of them were awkward and/or have several edge cases.
With modern CSS, there is actually a way to do it properly:
Just use a display: grid
container which transitions its grid row height betwe...
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...
Using git patchfiles to speed up similar implementation tasks
Sometimes you'll find yourself with a set of tasks that require similar code for different models. For example, if you start working at a new application that allows CRUDing pears and apples, each commit might look similar to this:
commit 41e3adef10950b324ae09e308f632bef0dee3f87 (HEAD -> ml/add-apples-12345)
Author: Michael Leimstaedtner <michael.leimstaedtner@acme.com>
Date: Fri Aug 11 09:42:34 2023 +0200
Add Apples as a new fruit
diff --git a/app/models/apple.rb b/app/models/apple.rb
new file mode 100644
index 0000000..a51...
CarrierWave: Processing images with libvips
When you write your next CarrierWave uploader, consider processing your images with libvips instead of ImageMagick.
Reasons for libvips
There are several upsides to using libvips over ImageMagick:
- libvips is considerably faster and uses less memory.
- ImageMagick has a large attack surface that has repeatedly caused security incidents in the past (compare [ImageMagick CVEs](https://www....
How to find child nodes that match a selector with JavaScript
Using querySelector
or querySelectorAll
in JavaScript, you can easily find descendants of a node that match a given selector.
But what if you want to find only children (i.e. direct descendants) of an element?
Easy: use :scope
. It references the element on which DOM API methods are being called:
element.querySelectorAll(':scope > .your-selector')
Example
Consider this HTML
<body>
<div id="container1">
<div id="container1a">foo</div>
<div id="container1b">bar</div>
<div id="container1c">baz</...
Balance your texts today with text-wrap: balance
So you have a heading that is just barely wider than the container it should fit into, and it wraps a single word to a new line and it's not really pretty?
Cry no more, for you can use text-wrap: balance
today to fix that. At least in some browsers.
When browsers encounter a text-wrapping element with text-wrap: balance
style, they will try breaking to a new line sooner, if it balances out the width of lines.
text-wrap: unset |
text-wrap: balance |
---|---|

- avoids "magic numbers" (don't say e.g. ...
Best practice: How to manage versions in a package.json
It most cases it's not necessary to add a version constraint next to your packages in the package.json
. Since all versions are saved in a lockfile, everyone running yarn install
will get exactly the same versions. Yarn saves this lockfile as yarn.lock
and npm as package-lock.json
.
There are some exceptions, where you can consider adding a version constraint to the package.json
:
- You are not checking the lockfile into version control (not recommended)
- A specific package has a bug in a more recent version
- You want to ensure no...
Best practice: How to manage versions in a Gemfile
It most cases it's not necessary to add a version constraint next to your gems in the Gemfile
. Since all versions are saved in the Gemfile.lock
, everyone running bundle install
will get exactly the same versions.
There are some exceptions, where you can consider adding a version constrain to the Gemfile
:
- You are not checking in the
Gemfile.lock
into the version control (not recommended) - A specific gem has a bug in a more recent version (adding a comment for the reason is highly recommended)
- You want to ensure no one upgrade...
Code splitting in esbuild: Caveats and setup
Code splitting is a feature of esbuild that can keep huge libraries out of the main bundle.
How code splitting works
Like Webpack esbuild lets you use the await import()
function to load code on demand:
// application.js
const { fun } = await import('library.js')
fun()
However, esbuild's code splitting is disabled by default. The code above would simply inline (copy) `l...
Don't assert exceptions in feature specs
As we are slowly switching from Cucumber scenarios to RSpec feature specs, you might be tempted to write assertions like this one:
feature 'authorization for cards management' do
let(:guest_user) { create(:user, :guest) }
scenario "rejects guest users from adding new cards", js: true do
sign_in guest_user
expect { visit new_cards_path }.to raise_error(Consul::Powerless)
end
end
While this might work under certain circumstances¹, there is a good chance you'll see two exceptions when running this single spec:
- ...
Byebug cheatsheet
Context and further resources
Even though you can get 90% of debugging done with up to 5 basic byebug
commands, it comes in handy with it's features for many use cases beyond that to make your life easier.
For this cheatsheat I tried to structure the most useful commands by different use cases, such that a practical oriented overview of all the commands can be gathered by going over this cheatsheet. For some commands I added some tips for their usage and further details on their subcommands
- For most of the commands shortl...
How to open files from better_errors with RubyMine on Linux
I recently noticed that better_errors
allows you to to open files from within your favorite editor. However it was not so easy to get rubymine://
links to work on Gnome/Linux. Here is how it finally worked for me:
Step 1: Add a Desktop launcher
Add this file to ~/.local/share/applications/rubymine.desktop
:
[Desktop Entry]
Version=1.0
T...
Chromedriver: Connect local chromedriver with docker
Debugging your integration tests, that run a headless Chrome inside a docker image, is tricky.
In many cases you can connect your Chrome to a remote docker container like docker-selenium, which should be the preferred way when you try to inspect a page within your integration test.
Otherwise you might be able to start your docker container with --net=host
and access your local chromedriver in the host address space host.docker.internal
.
If both options above don't work for you here is a...
Allow capybara to click on labels instead of inputs for checkboxes
Within Capybara you most certainly use the #check
- and #uncheck
-method to (un)check checkboxes.
But there's one problem, if you want to test a custom styled checkbox, which hides its <input>
-Tag:
- The methods cannot (un)check checkboxes without an visible
<input>
. - The error message will be something like:
Unable to find visible checkbox "Some label" that is not disabled
Solution 1
Use the keyword argument allow_label_click: true
within the method call.
So instead of check('Some label')
, use `check('Some label', allow...
The numericality validator does not care about your BigDecimal precision
Looking at the source code of the validates_numericality_of validator, it becomes clear that it converts the attribute in question to either an integer or float:
if configuration[:only_integer]
unless raw_value.to_s =~ /\A[+-]?\d+\Z/
record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number])
next
end
raw_value = raw_value.to_i
else
begin
raw_value = Kernel.Float(raw_val...
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...
Rails: Fixing ETags that never match
Every Rails response has a default ETag
header. In theory this would enable caching for multiple requests to the same resource. Unfortunately the default ETags produced by Rails are effectively random, meaning they can never match a future request.
Understanding ETags
When your Rails app responds with ETag
headers, future requests to the same URL can be answered with an empty response if the underlying content ha...