Unpoly 3.7.1, 3.7.2 and 3.7.3 released
Version 3.7.0 broke some things in complex forms. Sorry for that. Concurrent user input is hard.
3.7.1
This change fixes two regressions for form field watchers, introduced by 3.7.0:
- When a change is detected while waiting for an async callback, prevent the new callback from crashing with
Cannot destructure property { disable } of null
. - When a change is detected while waiting for an async callback, the full debounce delay of that new change is honored.
...
Capistrano: creating a database dump if migrating
In Capistrano 3, your Capfile requires 'capistrano/rails/migrations'
, which brings two Capistrano tasks: deploy:migrate
and deploy:migrating
. The former checks whether migrations should be performed. If so, the latter is invoked, which performs the actual migrations.
Knowing this, it is easy to dump the db only if migrations will run. First, enable conditional migrations:
# config/deploy.rb
set :conditionally_migrate, true # Only attempt migration if db/migrate changed
Then hook up the dump task to deploy:migrating
:
RailsStateMachine 2.2.0 released
-
Added: State machine can now use the
:prefix
-option to avoid name collision if you define multiple state machines on the same model, and use state names more than once- Previously
state_machine
-definitions like this:
would produce the following warning:class Form state_machine :first_wizard_stage do state :completed end state_machine :second_wizard_stage do state :completed end end
rails_state_machine-2.1....
- Previously
Javascript: Avoid using innerHTML for unsafe arguments
Make sure that you use the correct property when editing an HTML attribute. Using innerHTML
with unsafe arguments makes your application vulnerable to XSS.
-
textContent
: Sets the content of aNode
(arguments are HTML-safe escaped) -
innerHTML
: Sets the HTML of anElement
(arguments are not escaped and may not contain user content)
Hierarchy
This hierarchy gives you a better understanding, where the textContent
and the innerHTML
properties are defined. It also includes (just for completeness) the innerText
property, whi...
Transfer records to restore database entries (with Marshal)
If you ever need to restore exact records from one database to another, Marshal
might come in handy.
Marshal.dump
is part of the ruby core and available in all ruby versions without the need to install anything. This serializes complete ruby objects including id
, object_id
and all internal state.
Marshal.load
deserializes a string to an object. A deserialized object cannot be saved to database directly as the the dumped object was not marked dirty, thus rails does not see the need to save it, even if the object is not present in...
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...
How to: Upgrade CarrierWave to 3.x
While upgrading CarrierWave from version 0.11.x to 3.x, we encountered some very nasty fails. Below are the basic changes you need to perform and some behavior you may eventually run into when upgrading your application. This aims to save you some time understanding what happens under the hood to possibly discover problems faster as digging deeply into CarrierWave code is very fun...
Whitelists and blacklists
The following focuses on extension allowlisting, but it is the exact same thing for content type allowlisting with the `content_ty...
Zeitwerk: How to collapse folders in Rails
All direct child directories of app
are automatically added to the eager- and autoload paths. They do NOT create a module for namespacing. This is intuitive, since there normally is no module Model
, or module Controller
. If you want to add a new base directory, there's no additional config needed.
Example
app
├── controllers
├── helpers
├── inputs # No config needed
├── mailers
├── models
├── uploaders # No config needed
├── util # No config needed
└── workers # No config needed
Sometimes it's handy to group files wit...
Debug MiniMagick calls in your Rails app
Most of our applications use CarrierWave for file uploads. CarrierWave has an integrated processing mechanism for different file versions with support for ImageMagick through CarrierWave::MiniMagick
(which requires the mini_magick
gem). In case your processing runs into an error, CarrierWave will just swallow it and rethrow an error with a very generic message like Processing failed. Maybe it is not an image?
which does not help you finding out what the actual problem is. CarrierWave probably does this for security purposes, but does n...
RSpec: Leverage the power of Capybara Finders and Matchers for view specs
View specs are a powerful tool to test several rendering paths by their cases instead of using a more costing feature spec. This is especially useful because they become quite convenient when used with Capybara::Node::Finders and Capybara::RSpecMatchers. This allows to wirte view unit specs as you can isolate specific part...
Spreewald, Cucumber: Selector for the nth element
The recommended additional setup of the spreewald gem, a useful set of cucumber steps, includes adding a file for defining custom selectors which can be used as prose within steps:
When I follow "Edit" within the controls section
Where the controls section
can be any arbitrary defined css selector within selectors.rb
Often it can be useful to select the nth element of a specific selector. Luckily, this can ...
How to work around selenium chrome missing clicks to elements which are just barely visible
Chromedriver (or selenium-webdriver?) will not reliably scroll elements into view before clicking them, and actually not click the element because of that.
We've seen this happen for elements which are just barely in the viewport (e.g. the upper 2px of a 40px button). Our assumption is that the element is considered visible (i.e. Capybara::Selenium::ChromeNode#visible?
returns true
for such elements) but the Selenium driver wants to actually click the center of the element which is outside of the viewport.
We don't know who exactly i...
HTML: Auto fill-in OTP received in text message (SMS)
Browsers can auto fill-in one time codes if advised. Use it like this:
<input autocomplete="one-time-code">
Demo: https://twitter.com/sulco/status/1320700982943223808
Browser support is pretty good since mid-2022 (Chrome 93+, no Firefox).
Lightning Talk: Coverage based Test Case Prioritization in Ruby on Rails
For my computer science bachelor's thesis I programmed and evaluated a CLI Test Case Prioritization (TCP) tool for makandra. It has been written as a Ruby Gem and was tested and evaluated against one Ruby on Rails project. This card will summarize and present the research results, the evaluation and the programmed CLI tool.
The code has been published for educational purposes on GitHub. The german bachelor's thesis has also been included for download at the end.
...
Do not pass params directly into url_for or URL helpers
Rails' url_for
is useful for generating routes from a Hash, but can lead to an open redirect vulnerability.
Your application's generated route methods with a _url
suffix are also affected because [they use url_for
unter the hood](https://github.com/rails/rails...
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...
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</...
Checklist for Implementing Design
We have a long-standing checklist for merge requests. However, it hardly matches the intricate requirements for design. This checklist fills the gap.
Before starting implementing, look at all designs: are there components similar to yours? Have they already been implemented? Can you build on this prior art when implementing yours?
Checklist: I confirm my design implementation
- has been tested manually by me
- adheres to the code style of the project (e.g. BEM)
- avoids "magic numbers" (don't say e.g. ...
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...
Better HTML forms: use type, inputmode, enterkeyhint and autocomplete
Web forms can be made much more usable with a few HTML attributes. Short summary:
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...
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...