Updated: Controlling issue grouping in Sentry
Added that usage of * wildcards might be necessary in custom fingerprinting rules.
How to start Terminator with split screens and custom commands running
Starting Terminator with split screens is quite simple: Just store a layout and start Terminator with the --layout <your layout>
option.
However, if you want to run custom commands in your terminals, you need to do some work to keep these terminals from closing after a command exits. You accomplish this by tweaking bash to run a command before actually starting.
Pimp your .bashrc
Add this to the end of .bashrc
:
# hack to keep a bash open when starting it with a command
[[ $startup_cmd ]] && { declare +x $startup_cmd; hi...
JavaScript: Testing the type of a value
Checking if a JavaScript value is of a given type can be very confusing:
- There are two operators
typeof
andinstanceof
which work very differently. - JavaScript has some primitive types, like string literals, that are not objects (as opposed to Ruby, where every value is an object).
- Some values are sometimes a primitive value (e.g.
"foo"
) and sometimes an object (new String("foo")
) and each form requires different checks - There are three different types for
null
(null
,undefined
andNaN
) and each has different rules for...
How to Work With Time Zones in Rails
When dealing with time zones in Rails, there is one key fact to keep in mind:
Rails has configurable time zones, while
Ruby is always in the server's time zone
Thus, using Ruby's time API will give you wrong results for different time zones.
"Without" time zones
You can not actually disable time zones, because their existence is a fact. You can, however, tell Rails the only single time zone you'll need is the server's.
config.time_zone = "Berlin" # Local time zone
config.active_record.default_timezone = :loca...
Updated: Controlling issue grouping in Sentry
- Updated card title
- Added a section about controlling issue grouping in the Sentry UI (i.e. without modifying the application)
Updated: Your browser might silently change setTimeout(f, 0) to setTimeout(f, 4)
Added a reference to a similar behavior when chrome is deliberately slowing down the setInterval and setTimeout rate
Avoiding Test-Case Permutation Blowout - Steven Hicks
Sometimes you want to write a test for a business rule that's based on multiple variables. In your goal to cover the rule thoroughly, you start writing tests for each permutation of all variables. Quickly it blows up into something unsustainable. With n variables for the business rule, you get 2n permutations/test cases. This is manageable with 2 variables (4 test cases), but at 3 variables (8 test cases) it becomes ridiculous, and anything beyond that feels immediately uncomfortable.
I've noticed myself using an alternate pattern for...
A gotcha of Ruby variable scoping
I recently stumbled over a quirk in the way Ruby handles local variables that I find somewhat dangerous.
Consider:
def salutation(first_name, last_name = nil)
if last_name
full_name = "#{first_name} #{last_name}"
end
"Hi #{full_name}"
end
This is obviously wrong, full_name
is unset when last_name
is nil.
However, Ruby will not raise an exception. Instead, full_name
will simply be nil
, and salutation('Bob')
returns 'Hi '
.
The same would happen in an else
branch:
def salutation(fi...
Compare library versions as "Gem::Version" instances, not as strings
Sometimes we have to write code that behaves differently based on the version of a specific gem or the Ruby Version itself. The version comparison can often be seen with simple string comparison like so.
# ❌ Not recommended
if Rails.version > '6.1.7.8' || RUBY_VERSION > '3.1.4'
raise Error, 'please check if the monkey patch below is still needed'
end
If you are lucky, the version comparison above works by coincidence. But chances are that you are not: For example, Rails version 6.1.10.8
would not raise an error in the code ...
Updated: Test-Driven Development with integration and unit tests: a pragmatic approach
Further relaxed the requirements for implementation. Once all scenarios/examples are written down, the order of test-writing and implementation does not actually matter.
How to write complex migrations in Rails
Rails gives you migrations to change your database schema with simple commands like add_column
or update
.
Unfortunately these commands are simply not expressive enough to handle complex cases.
This card outlines three different techniques you can use to describe nontrivial migrations in Rails / ActiveRecord.
Note that the techniques below should serve you well for tables with many thousand rows. Once your database tables grows to millions of rows, migration performance becomes an iss...
Working on the Linux command line: Use the `tree` command instead of repeated `cd` and `ls`
The tree
command will show you the contents of a directory and all its sub directories as a tree:
>tree
.
├── a
│ ├── file_1.txt
│ └── file_2.txt
└── b
├── c
│ └── even_more.txt
└── more.txt
3 directories, 4 files
If you have deeply nested directories, the output will be quite long though. To avoid that, you can limit the depth, e.g. tree -L 2
will only go 2 directories deep.
If you use that regularly, consider adding aliases for that to your ~/.bashrc
:
alias tree2='tree -L 2'
alias tree3='tree -L 3'
...
Your browser might silently change setTimeout(f, 0) to setTimeout(f, 4)
When you're nesting setTimeout(f, 0)
calls, your browser will silently increase the delay to 5 milliseconds after the fourth level of nesting.
This is called "timeout clamping" and defined in the HTML spec:
If nesting level is greater than 5, and timeout is less than 4, then set timeout to 4.
Timeouts are clamped harder in background tabs
On a similar note, all major browsers have implemented throttling rules for setInterval
and setTimeout
calls from tabs...
How to speed up JSON rendering with Rails
I was recently asked to optimize the response time of a notoriously slow JSON API endpoint that was backed by a Rails application.
While every existing app will have different performance bottlenecks and optimizing them is a rabbit hole of arbitrary depth, I'd like to demonstrate a few techniques which could help reaching actual improvements.
The baseline
The data flow examined in this card are based on an example barebone rails app, which can be used to reproduce the r...
RubyMine: Adjust Code Templates
tl;dr
To adjust code templates in RubyMine, navigate to Settings -> Editor -> File and Code Templates.
Example
You can navigate to the test file of the currently open file with the shortcut Ctrl + T
. If no test file exists, you can generate a new test file. If you are not pleased with the output, you can adjust the related code template. To do this, open the project settings and navigate to Editor -> File and Code Templates -> Files. Now, choose your relevant file type and adjust the code template according ...
Protected and Private Methods in Ruby
In Ruby, the meaning of protected
and private
is different from other languages like Java. (They don't hide methods from inheriting classes.)
private
Private methods can only be called with implicit receiver. As soon as you specify a receiver, let it only be self
, your call will be rejected.
class A
def implicit
private_method
end
def explicit
self.private_method
end
private
def private_method
"Private called"
end
end
A.new.implicit
# => "Private called"
A.new.explicit
# => NoMethod...
Advisory: Excel converts CSV entries to formulas
If your application exports CSV, be advised that Excel and other spreadsheet applications treat certain cells (those starting with =
, +
, -
or @
) as formulas.
This is an issue if you output user input. Not only is it probably not what you want, it also poses a security risk. See the link for attack vectors.
Note that current Excel versions will warn the user when opening the file. At least for the code execution vulnerability, these three warnings seems adequate to me.
Code execution warnings:
![Image](/makandra/47624/attach...
How to: Ensure proper iconfont rendering with Webpack
Background
After switching a project from Sprockets to Webpack, I started observing a bug that was hard to debug: Our custom icon font could sometimes not be displayed until a full page reload.
Digging deeper the only difference before and after the page load was the encoding interpretation of the iconfont stylesheet:
Correct representation (UTF-8):
.icon:before {
content: ""
}
Broken representation (other charset):
`...
How to query GraphQL APIs with Ruby
While most Rails Apps are tied to at least one external REST API, machine-to-machine communication via GraphQL is less commonly seen. In this card, I'd like to give a quick intro on how to query a given GraphQL API - without adding any additional library to your existing app.
Core aspects of GraphQL
Interacting with GraphQL feels a bit like querying a local database. You are submitting queries to fetch data in a given structure (like SELECT in SQL) or mutations to alter the database (similar to POST/PUT/DELETE in REST). You can ...
Rails npm packages will use an uncommon versioning scheme
When Rails releases a new version of their gems, they also release a number of npm packages
like @rails/activestorage
or @rails/actioncable
.
Unfortunately Rails uses up to 4 digits for their gem version, while npm only allows 3 digits and a pre-release suffix.
To map gem versions and npm versions, Rails is going to use a naming scheme like this:
Gem version | npm version |
---|---|
7.0.0 |
7.0.0 |
7.0.1 |
7.0.100 |
... |
JavaScript: Humanizing durations
Modern JavaScript includes Intl.NumberFormat to format numbers in different formats and locales.
In this card, we describe a wrapper for it that humanizes a given number of seconds in the "next best" unit, like seconds, minutes, etc.
Example usage
>> new Duration(42).humanized()
=> '42 Sekunden'
>> new Duration(123456).humanized()
=> '1 Tag'
>> new Duration(123456).humanized('es')
=> '1 día'
Code
Here is the code ...
Use the Git stash without shooting yourself in the foot
The Git stash does not work like a one-slot clipboard and you might shoot yourself in the foot if you pretend otherwise.
In particular git stash apply
does not remove the stashed changes from the stash. That means you will probably apply the wrong stash when you do git stash apply
after a future stashing.
To keep your stash clean, you can use
git stash pop
instead.
Another way to look at it:
git stash pop
is the same as
git stash apply && git stash drop
Notice: In case of a conflict git will not pop th...
Too many parallel test processes may amplify flaky tests
By default parallel_tests will spawn as many test processes as you have CPUs. If you have issues with flaky tests, reducing the number of parallel processes may help.
Important
Flaky test suites can and should be fixed. This card is only relevant if you need to run a flaky test suite that you cannot fix for some reason. If you have no issues...
Ruby: Retrieving and processing files via Selenium and JavaScript
This card shows an uncommon way to retrieve a file using selenium where JavaScript is used to return a binary data array to Ruby code.
The following code example retrieves a PDF but the approach also works for other file types.
require "selenium-webdriver"
selenium_driver = Selenium::WebDriver.for :chrome
selenium_driver.navigate.to('https://example.com')
link_to_pdf = 'https://blobs.example.com/random-pdf'
binary_data_array = selenium_driver.execute_script(<<-JS, link_to_pdf)
const response = await fetch(arguments[0])
if (!r...