How to exclusively lock file access in ruby
We will achieve this by creating a block accepting method to optionally create and then lock a .lock
File of the underlying accessed file.
Why create a .lock
file?
- The main advantage of creating a
.lock
file is that#flock
might block some operations and require the index node of the file to be consistent. Some operations might change that index node. - In some cases it might also be convenient to just read/write the lock file first and update the other file afterwards or vice versa, such that breaking of a process does not...
Rails developers: Have better context in Git diffs
Git diffs show the surrounding contexts for diff hunks. It does so by applying regular expressions to find the beginning of a context. When it comes to Ruby, however, it will not find method heads and travel up to the class definition:
@@ -24,7 +24,7 @@ class TicketPdf # <=== Actually expected here: the method definition
ApplicationController.render(
"tickets/index.html.haml",
layout: "tickets",
- assigns: { tickets: tickets }
+ assigns: { tickets: tickets, event_name: event_name }
)
end
end
```...
Git: Improve your commits by reviewing changes one-by-one
Git commits should be very deliberate, and only contain changes that you really want to be in there. In order to reduce the chance to accidentally commit something you didn't intend, review your changes before committing.
My preferred way of doing this is (only using git)
git add -N . # Add all paths, but not their contents
git add -p
Git will now show you all your changes in small chunks and ask you in an interactive mode whether you really want to add them.
The most helpful commands are
- y: yes (add the change)
- ...
Project management best practices: Project team responsibilities
In a project team for a bigger project people have several roles:
- Developer: at makandra
- Project lead: at makandra
- Project manager (PM): at makandra, external, or with the customer. In a smaller project this person is also the project lead.
- Product owner (PO): with the customer
Developer
- Development
- Take responsibility for their stories. This includes always gathering all necessary information from the project lead or the PM, communicate blockers, make sure stories are merged, deployed etc.
- Tell the project lead, if y...
SASS: Reusing styles from other files
SASS has an @extend
keyword to inherit styles.
.alert
color: red
&.-framed
border: 1px solid red
padding: 5px
&.-homepage
@extend .-framed
border-width: 5px
When compiling, SASS will simply join the selectors. Note how .-homepage
is written where .-framed
was defined:
...
.alert.-framed, .alert.-homepage {
border: 1px solid red;
padding: 5px;
}
.alert.-homepage {
border-width: 5px;
}
Warning
Unfortunately, this does...
How to enable template coverage support for simplecov
Since Ruby 3.2.0 you can measure coverage support for eval
statements and support has been added for the simplecov gem as well.
This allows to track coverage across ruby templates such as haml, erb, ...
Simply set this within simplecov
SimpleCov.start do
enable_coverage_for_eval
end
SVGO: SVG Optimizer
SVG files are often much larger than necessary, containing comments, metadata, hidden elements etc.
Optimize them with this tool.
- Web UI: https://jakearchibald.github.io/svgomg/
- Binary: https://github.com/svg/svgo
Note that for a properly scaling SVG, you need to keep the viewBox
attribute. There's an option --disable=removeViewBox
for this.
FactoryBot: Passing attributes to associated records using transient attributes
FactoryBot.define do
factory :parent do
transient do
child_name nil
child_allowed_to_drive false
end
child do
association(:child, name: child_name, allowed_to_drive: child_allowed_to_drive)
end
end
factory :child do
name 'Child'
allowed_to_drive false
end
end
# Usage
daughter = FactoryBot.create(:parent, child_name: 'Lisa').child
daughter.name # => 'Lisa'
daughter.allowed_to_drive? # => false
son = FactoryBot.create(:parent, child_name: 'Benedikt', child_allowed_to_drive: tr...
Project management best practices: User stories & Issues
We organize our daily work with issues in our Linear workspace.
Issue format
A good issue needs to be precise. It should be very clear what is part of an issue, and what is not. If there are different expectations between the person who writes and who implements an issue, there will be rejects.
To this end, we use a consistent format for issues that looks like this:
Issue: Autocomplete
As a journalist, I want to have an autocomplete in the search bar, to have a more efficient way to find articles.
Acceptance criteri...
Deterministic ordering of records by created_at timestamp
Creating records in specs can be so fast that two records created instantly after one another might have the same created_at timestamp (especially since those timestamps don't have an indefinitely high resolution). When ordering lists by timestamps, you should therefore always include a final order condition using the primary key of the table.
class Photo < ActiveRecord::Base
scope :by_date, -> { order('created_at DESC, id DESC') }
end
Photo.by_date
Remember to include the id
field in the database index.
Rails migration: Changing a column type without losing the content
The change_column
method for rails migrations support casting with a custom SQL statement. This allows us to change a column type and keep the former content as the new type. This way, we can for example prepare an address number column to hold German address numbers, which can contain letters:
Example (in most cases not a good idea!)
class ChangeAnIntegerColumnToString < ActiveRecord::Migration[6.1]
def up
change_column :users, :address_number, 'varchar USING CAST(rating AS varchar)'
end
def down
change_column ...
CSS: CSS Container Queries
Container queries enable you to apply styles to an element based on the size of the element's container. If, for example, a container has less space available in the surrounding context, you can hide certain elements or use smaller fonts. Container queries are an alternative to media queries, which apply styles to elements based on viewport size or other device characteristics.
This feature is now stable across browsers.
Warning
This feature landed in browsers in the beginning of 2023. According to our support policy this will bec...
Creating a sample video with ffmpeg
If you need a sample video with certain properties for a test you can create one using ffmpeg.
You might want a very low bitrate file to speed up processing in your test. (e.g. you only care about the length, then you can create a video with a very low resolution and framerate)
Create a 21s video with 1fps and 10x10 resolution:
ffmpeg -t 21 -s 10x10 -r 1 -f rawvideo -pix_fmt rgb24 -i /dev/zero sample_21_seconds.mp4
Option | Explanation |
---|---|
-t 21 |
set the length to 21s |
-s 10x10 |
set the resolution the 10 by 10 p... |
How to split up a git commit
Quick steps
-
git rebase -i
-> mark your commit withedit
-
git reset HEAD~
(remove the marked commit, but keep its changes) - Make several commits (optionally setting the previous author manually)
git rebase --continue
Detailed instructions
Basically, you will review the last n
commits and stop at the splittable commit. Then you'll undo that commit and put its changes into new commits at your liking.
-
Review commits (
rebase
)git rebase -i HEAD~3 # or git rebase -i origin/master
...
Shorthand function properties in ES6
Here is an ES5 object literal with two string properties and a function property:
let user = {
firstName: 'Max',
lastName: 'Muster',
fullName: function() { return this.firstName + ' ' + this.lastName }
}
user.fullName() // => 'Max Muster'
In ES6 we can define a function property using the following shorthand syntax:
let user = {
firstName: 'Max',
lastName: 'Muster',
fullName() { return this.firstName + ' ' + this.lastName }
}
user.fullName() // => 'Max Muster'
We can also define a gette...
nvm: Setting a default Node.js version
To set a default Node version for new shells, use nvm alias default <VERSION>
:
nvm alias default 1.2.3
I like to use the most recent LTS version as my default:
nvm alias default lts/erbium
Rails Partials
Rails partials have a lot of "hidden" features and this card describes some non-obvious usages of Rails Partials.
Rendering a basic partial
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: ...
Heads up: Deployment with newly generated SSH key (using ED25519) might fail
If you use a newer SSH key generated with the ED25519 algorithm instead of RSA (see Create a new SSH key pair), the deployment with Capistrano may fail with the following message:
The deploy has failed with an error: unsupported key type `ssh-ed25519'
net-ssh requires the following gems for ed25519 support:
* ed25519 (>= 1.2, < 2.0)
* bcrypt_pbkdf (>= 1.0, < 2.0)
See https://github.com/net-ssh/net-ssh/issues/565 for more information
Gem::LoadError : "ed25519 i...
Issue Checklist Template
This is a checklist I use to work on issues. For this purpose I extracted several cards related to the makandra process and ported them into a check list and refined that over time a little bit.
This task list is divided by the Gate keeping process in the following steps:
1. Starting a new feature
2. Working on the issue
3. Finishing a feature
4. After Review
Here are some ti...
Linux: Open a file with the default application
If you are on a Linux shell and want to open a file with whatever default application is configured for that type, this often works:
xdg-open Quote.odt
xdg-open invoice.pdf
xdg-open index.html
Pro Tip
Make an alias so you have a simpler API (like Mac OS): alias open=xdg-open
or alias x=xdg-open
.
Background
You can choose your "Default applications" via UI in the Ubuntu "Settings" application (gnome-control-center
). This is just a very rough setting (e.g. open Photos with Shotwell Viewer).
If a certain file...
Manipulate color with Sass functions
Sass comes with many built-in functions to manipulate color. Some of the more interesting functions include:
adjust-hue($color, $degrees)
:Changes the hue of a color.
lighten($color, $amount)
:Makes a color lighter.
darken($color, $amount)
:Makes a color darker.
saturate($color, $amount)
:Makes a color more saturated.
desaturate($color, $amount)
:Makes a color less saturated.
grayscale($color)
:Converts a color to grayscale.
complement($color)
:Return...
Jasmine: Testing AJAX calls that manipulate the DOM
Here is a Javascript function reloadUsers()
that fetches a HTML snippet from the server using AJAX and replaces the current .users
container in the DOM:
window.reloadUsers = ->
$.get('/users').then (html) ->
$('.users').html(html)
Testing this simple function poses a number of challenges:
- It only works if there is a
<div class="users">...</div>
container in the current DOM. Obviously the Jasmine spec runner has no such container. - The code requests
/users
and we want to prevent network interaction in our uni...
Rails: Using database default values for boolean attributes
In the past we validate and set default values for boolean attributes in Rails and not the database itself.
Reasons for this:
- Older Rails didn't support database defaults when creating new records
- Application logic is "hidden" in the database
An alternative approach, which currently reflects more the general opinion of the Rails upstream on constraints in the database, is adding default values in the schema of the database itself. We also ...
HTTP headers can only transport US-ASCII characters safely
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...