Bookmarklet to generate a commit message for an issue in Linear.app
Your commit messages should include the ID of the issue your code belongs to.
Our preferred syntax prefixes the issue title with its ID in brackets, e.g. [FOO-123] Avatars for users
.
Here is how to generate that from an issue in Linear.
Add a new link to your browser's bookmarks bar with the following URL.
javascript:(() => {
if (document.querySelector('[data-view-id="issue-view"]')) {
const [id, ...words] = document.title.split(' ') ;
prompt('Commit message:', `[${id}] ${words.join(' ')}`)
} else {
alert('Open issue...
Rails: Different flavors of concatting HTML safe strings in helpers
This card describes different flavors for concatting HTML safe strings in a helper method in Rails. You might want to use the tag helper instead of the content_tag helper (the tag
helper knows all self closing tags).
Example
We want to generate HTML like this:
<h1>Navigation</h1>
<ul>
<li>Left</li>
<li>Right</li>
</ul>
Below you ca...
How to handle when an HTML <video> element cannot autoplay
HTML <video>
elements can automatically start playing when the autoplay
attribute is set on them. Except for when they can not, e.g. on pageload, or when the element enters the DOM without user interaction, or when the browser for some other reason decided to not start playing the video.
While there is no native "autoplay failed" event to listen to, you can wait for video data to be loaded and then check if the video actually started playing.
Example
<video autoplay>
<source src="example.mp4" type="video/mp4" />
</video>
...
Using rack-mini-profiler (with Unpoly)
Debugging performance issues in your Rails app can be a tough challenge.
To get more detailed insights consider using the rack-mini-profiler gem.
Setup with Unpoly
Add the following gems:
group :development do
gem 'memory_profiler'
gem 'rack-mini-profiler'
gem 'stackprof'
end
Unpoly will interfere with the rack-mini-profiler widget, but configuring the following works okayish:
// rack-mini-profiler + unpoly
if (process...
Caution: rem in @media query definitions ignore your font-size
Note
Using rem only ever makes sense when the root font size is dynamic, i.e. you leave control to the user. Either by a) respecting their user agent defaults, or by b) offering multiple root font sizes in your application.
By defining @media queries in rem, they will accommodate to the root font size of your page. At a larger root font, breakpoints will be at larger widths, scaling with the font. However, there is a catch in case b) mentioned in the note above.
Relative length units in media queries are based on the initial value,...
Problems with git submodules in Gitlab CI
If you are using git submodules in Gitlab CI, you might run into a "The project you were looking for could not be found or you don't have permission to view it."
Gitlab added a feature that new projects are no longer allowed to be cloned inside CI runs of other repositories by default. To fix this
- Go into the project used as a submodule
- Go to "Settings" -> "CI/CD" (if you don't see this section, enable it in "Settings" -> "General" -> "Visibility, project features, permissions")
- Go to "Token Access"
- Either disable "Limit access to ...
Rails: Testing file downloads with request specs
tl;dr
Prefer request specs over end-to-end tests (Capybara) to joyfully test file downloads!
Why?
Testing file downloads via Capybara is not easy and results in slow and fragile tests. We tried different approaches and the best one is just okay.
Tests for file downloads via Capybara ...
- ... are slow,
- ... are fragile (breaks CI, breaks if Selenium driver changes, ...),
- ... need workarounds for your specia...
Accessibility: Making non-standard elements interactive
A common cause of non-accessible web pages are elements that were made interactive via JavaScript but cannot be focused or activated with anything but the mouse.
❌ Bad example
Let's take a look at a common example:
<form filter>
<input filter--query name="query" type="text">
<span filter--reset>Clear Search</span>
</form>
The HTML above is being activated with an Unpoly compiler like this:
up.compiler('[filter]', function(filterForm) {
const resetButton = filterForm.querySelec...
Heads up: You should always use "current_window.resize_to" to resize the browser window in tests
I recently noticed a new kind of flaky tests on the slow free tier GitHub Action runners: Integration tests were running on smaller screen sizes than specified in the device metrics. The root cause was the use of Selenium's page.driver.resize_window_to
methods, which by design does not block until the resizing process has settled:
We discussed this issue again recent...
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...
Best practices: Writing a Rails script (and how to test it)
A Rails script lives in lib/scripts and is run with bin/rails runner lib/scripts/...
. They are a simple tool to perform some one-time actions on your Rails application. A Rails script has a few advantages over pasting some prepared code into a Rails console:
- Version control
- Part of the repository, so you can build on previous scripts for a similar task
- You can have tests (see below)
Although not part of the application, your script is code and should adhere to the common quality standards (e.g. no spaghetti code). However, a script...
Element.animate() to animate single elements with given keyframes
Today I learned that you can animate HTML elements using the Web Animation API's method .animate(keyframes, options)
(which seems to be Baseline for all browsers since 2022).
const fadeIn = [{ opacity: 0 }, { opacity: 1 }] // this is a keyframe example
const container = document.querySelector('.animate-me')
const animation = container.animate(fadeIn, 2000) // I am just using the animation duration as option here but it can also be given an object
// the animation object can be used for things like querying timings or stat...
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.
...
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...
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...
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 within view specs to isolate specific parts of the render...
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...