Maintaining larger projects makes it more difficult to balance refactoring and upgrade tasks according to its actual value. Consider to create and periodically maintain a summary, which helps you and your team in the decision which refactoring task should be taken next.
Here is an template on how you might categorize your tasks:
| Technical debt | Estimated Efforts | Customer value| Customer value explained| Developer value|Developer value explained|
|-----------------------------|----------------|-----------|------...
Rails offers the fresh_when
method to automatically compute an ETag from the given record, array of records or scope of records:
class UsersController < ApplicationController
def show
@user = User.find(params[:id])
fresh_when @user
end
def index
@users = User.all.to_a
fresh_when @users
end
end
When your view also displays other records (typically associations), those other records should be included in the ETag
. You can do so by passing an array of ETaggable objects to fresh_when
.
...
By activating strict_loading
you force developers to address n+1 queries by preloading all associations used in the index view. Using an association that is not preloaded will raise an ActiveRecord::StrictLoadingViolationError
.
I think it's a good default to activate strict_loading
in your controllers' #index
actions. This way, when a change introduces an n+1 query, you...
Rails partials have a lot of "hidden" features and this card describes some non-obvious usages of Rails Partials.
The most basic way to render a partial:
render partial: 'partial'
This will render a _partial.html.erb
file. Notice how all partials need to be prefixed with _.
It's possible to define local variables that are only defined in the partial template.
# _weather.html.erb
<h1>The weather is <%= condition %></h1>
# index.html.erb
render partial: 'weather', locals: { condition: ...
HTTP header values must only contain low-ASCII (7-bit) characters for safe transport. From RFC 7230:
Historically, HTTP has allowed field content with text in the ISO-8859-1 charset [ISO-8859-1], supporting other charsets only through use of [RFC2047] encoding. In practice, most HTTP header field values use only a subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD limit their field values to US-ASCII octets.
If you need to transport 8-bit+ characters (e.g...
Carrierwave's BaseUploader
can have some validations that you can use by overriding a certain method, which's expected name is hard coded. A popular example is extension_allowlist
, which returns an array of strings and let's you only upload files that have a filename with an extension that matches an entry in that array. Another useful validation can be size_range
, which gives you a little bit of control over how your storage gets polluted.
This is often good enough, but some times you need to validate special cases.
vertical-align
is hard. Have you ever wanted to vertically center an icon with text? This usually means "vertically align with capital letters", as visually, a text line goes from baseline up to the capital top. (That's because descenders are far less frequent than ascenders.)
In this card we'll vertically center an icon (or any "blockish" inline element, really) with the capital letters of surrounding text. This works well with our [modern approach to SVG icons](/mak...
Timecop is a great gem to set the current time in tests. However, it is easy to introduce flakyness to your test suite when you forget to reset the time after the test.
This might be the case if:
Often you only notice these kinds of errors in rare cases when tests are executed in a particular order.
A way to avoid this is by using block notation (`Timecop.travel(...) ...
In a Jasmine spec you want to spy on a function that is imported by the code under test. This card explores various methods to achieve this.
We are going to use the same example to demonstrate the different approaches of mocking an imported function.
We have a module 'lib'
that exports a function hello()
:
// lib.js
function hello() {
console.log("hi world")
}
export hello
We have a second module 'client'
that exports a function helloTwice()
. All this does is call hello()
...
We usually rely on VCR and WebMock to prevent any real network connection when running our unit tests.
This is not entirely true: They are both limited to a set of HTTP libraries listed below (as of 2022). Direct calls to Kernel#open
or OpenURI#open_uri
are not mocked and will trigger real network requests even in tests. This might bite you e.g. in [older versions of CarrierWave](https://github.com/carrierwaveuploader/carrierwave/blob/0.11-stable/lib/carrierwave/upl...
By default subscript (<sub></sub>
) and superscript (<sup></sup>
) tags are styled with vertical-align: sub
, respectively vertical-align: super
by most browsers.
However, without adaptations, this will probably break your line-heights.
A common suggestion is to style those two tags accordingly:
sup, sub {
vertical-align: baseline;
position: relative;
top: -0.4em; /* can be adapted according to preferences */
}
sub {
...
You have some SVG files you want to use as icons on your website. How would you embed them?
Common options are:
<img src='path-to-icon.svg'>
<svg>$ICON</svg>
background-image: url(path-to-icon.svg)
or even background-image: url(data:$ICON)
.All of these have drawbacks:
background-image
do not allow to recolor the image using CSS.<svg>
are unnecessary work for the server and are...In esbuild, you usually import other files using relative paths:
import './some-related-module'
import `../../utils/some-utility-module`
import `../../../css/some-css.sass`
This is totally fine if you import closely related files, but a bit clunky when you're trying to import some "global" module, like a utility module. When moving a file, your imports also need to change.
To get around this, esbuild support a mechanism first introduced in TypeScript called "path aliases". It works like this:
First, you create a file called `js...
Jasmine specs for the frontend often need some DOM elements to work with. Because creating them is such a common task, we should have an efficient way to do it.
Let's say I need this HTML structure:
<ul type="square">
<li>item 1</li>
<li>item 2</li>
</ul>
This card compares various approaches to fabricating DOM elements for testing.
While you can use standard DOM functions to individually create and append elements, this is extremely verbose:
let list = document.createElement('...
Jasmine specs that work with DOM elements often leave elements in the DOM after they're done. This will leak test-local DOM state to subsequent tests.
For example, this test creates a <spoiler-text>
element, runs some expectations, and then forgets to remove it from the DOM:
describe('<spoiler-text>', function() {
it ('hides the secret until clicked', function() {
let element = document.createElement('spoiler-text')
element.secret = 'The butler did it'
document.body.appendChild(element)
...
tl;dr
The Chrome DevTools are a neat collection of tools for the daily work as a web developer. If you're lucky, you'll maybe find some handy stuff in here.
You can use ETags to allow clients to use cached responses, if your application would send the same contents as before.
Besides what "actually" defines your response's contents, your application probably also considers "global" conditions, like which user is signed in:
class ApplicationController < ActionController::Base
etag { current_user&.id }
etag { current_user&.updated_at }
end
Under the hood, Rails generates an ETag header value like W/"f14ce3710a2a3187802cadc7e0c8ea99"
. In doing so, all objects from that etagge...
tl;dr
git checkout
is the swiss army of git commands. If you prefer a semantically more meaningful command for restoring tasks, usegit restore
instead.With this command you can ...
- ... do unstaging -
git restore --staged
- ... discard staged changes -
git restore --staged --worktree
- ... discard unstaged changes -
git restore
- ... restore deleted files -
git restore
- ... restore historic versions -
git restore --source
- ... recreate merge conflicts -
git restore --merge
- ... specifiy...
You have uncommited changes (you can always check by using git status
), which you want to discard.
Now there are several options to discard these depending on your exact situation.
The headlines will differentiate the cases whether the files are staged or unstaged.
git reset --hard
git stash
will add the changes to the stash, reverting the local repository to HE...
tl;dr
In RubyMine you can use find and replace with capture groups
(.*?)
and backreferences$1
(if you have several groups:$[Capture-Group ID]
).
Named captures(?<text>.*)
are also supported.
If you want to replace double quotes with single quotes, replacing every "
with a '
is prone to errors. Regular expressions can help you out here.
.*
icon next to the "find" field).To allow HTTP 304 responses, Rails offers the fresh_when
method for controllers.
The most common way is to pass an ActiveRecord instance or scope, and fresh_when
will set fitting E-Tag
and Last-Modified
headers for you. For scopes, an extra query is sent to the database.
fresh_when @users
If you do not want that magic to happen, e.g. because your scope is expens...
When you build a JSON API you need to come up with a style to represent attributes, pagination, errors or including associated objects. Instead of reinventing the wheel, you may reuse successful API designs.
JSON:API specifies common features found in most JSON APIs, like pagination, ordering and nested resources. The spec looks very similar to how one would build an API with Rails and uses similar patterns. Even if you don't plan on supporting the whole spec, it can still make sense to know how th...
When working with feature branches, stale branches pile up over time. It's best to remove them right after merge, locally and on the remote, but it is a little tedious: you need to remember it, and perform the few steps manually each time.
Enter Git hooks. The folks at Liquid Light have built a little post-merge hook that will delete a feature branch on confirmation....
Recently we detected a memory leak in one of our applications. Hunting it down, we found that the memory leak was located in Rails' #prepend_view_path
. It occurs when the instance method prepend_view_path
is called in each request, which is a common thing in a multi-tenant application.
On top of leaking memory, it also causes a performance hit, since templates rendered using the prepended view path will not be cached and compiled anew on each requqest.
This is not a new memory leak. It was [first reported in in 2014](https://github.com...