Test-Driven Development with integration and unit tests: a pragmatic approach
Test-Driven Development (TDD) in its most dogmatic form (red-green-refactor in micro-iterations) can be tedious. It does not have to be this way! This guide shows a pragmatic approach with integration and unit tests, that works in practice and improves on productivity.
Advantages
- No added effort: tests need to be written anyway.
- Test heads serve as todo lists. You'll always know what is finished and what is left to do.
- Big tasks are broken down into smaller tasks that can be processed one by one.
- You will not forget a test.
- You...
Bundler in deploy mode shares gems between patch-level Ruby versions
A recent patch level Ruby update caused troubles to some of us as applications started to complain about incompatible gem versions. I'll try to explain how the faulty state most likely is achieved and how to fix it.
Theory
When you deploy a new Ruby version with capistrano-opscomplete, it will take care of a few things:
- The new Ruby version is installed
- The Bundler version stated in the Gemfil...
Video transcoding: Web and native playback overview (April 2020)
Intro
Embedding videos on a website is very easy, add a <video>
tag to your source code and it just works. Most of the time.
The thing is: Both the operating system and Browser of your client must support the container and codecs of your video. To ensure playback on every device, you have to transcode your videos to one or more versions of which they are supported by every device out there.
In this card, I'll explore the available audio and video standards we have right now. The goal is to built a pipeline that...
Devise: How to allow only HTTP Basic Auth and disable the HTML sign-in form
By default, Devise redirects to a sign-in form when accessing a route that requires authentication. If for some reason you do not want this, but use Basic Authentication (and the corresponding browser username/password dialog) instead, this is a simple change.
Note that Devise's default configuration actually only redirects requests for HTML content (as requested by the HTTP Accept
header).
For all other formats (like JSON) it would use Basic Auth if the http_authenticatable
setting was enabled. So you can simply enable that flag and cl...
Heads up: Ruby's Net::HTTP silently retries a failing request
Ruby's Net::HTTP library repeats a failing request once, as long as it deems it idempotent (GET, HEAD etc). Both requests will use the configured timeout. Hence, if both requests time out, Net::HTTP will only return after twice the configured timeout.
This can become an issue if you rely on the timeout to strike precisely.
Letting a DOM element fade into transparency
You can use the CSS property mask-image
to define an "alpha channel" for an element.
E.g. to let an element start at full opacity at the top and gradually fade into transparency at the bottom:
.box {
-webkit-mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
mask-image: linear-gradient(to bottom, black 0%, transparent 100%);
}
- A fully opaque black pixel will render the masked pixel fully opaque
- A fully transparent black pixel will render the ...
Ruby: How to fetch a remote host's TLS certificate
TLS/SSL certificates are often used for HTTPS traffic. Occasionally a service may also use their TLS certificate to support public-key encrypting data (e.g. when it is part of the URI and visible to the user, but contains sensitive information).
Here is how to easily fetch such certificate data.
certificate = Net::HTTP.start('example.com', 443, use_ssl: true) { |http| http.peer_cert }
# => #<OpenSSL::X509::Certificate: subject=#<OpenSSL::X509::Name CN=www.example.org,...>
certificate.public_key
# => #<OpenSSL::PKey::RSA:0x...
Rails: Rest API post-mortem analysis
This is a personal post-mortem analysis of a project that was mainly build to provide a REST API to mobile clients.
For the API backend we used the following components:
- Active Model Serializer (AMS) to serializer our Active Record models to JSON.
- JSON Schema to test the responses of our server.
- SwaggerUI to document the API.
It worked
The concept worked really good. Here are two points that were extraordinary compared to normal Rails project with many UI components:
- Having a Rails application, that has no UI components (only...
Structuring Rails applications: the Modular Monorepo Monolith
Root Insurance runs their application as a monolithic Rails application – but they've modularized it inside its repository. Here is their approach in summary:
Strategy
- Keep all code in a single repository (monorepo)
- Have a Rails Engine for each logical component instead of writing a single big Rails Application
- Build database-independent components as gems
- Thus: gems/ and engines/ directories instead of app/
- Define a dependency graph of components. It should have few edges.
- Gems and Engines can be extracted easier once nece...
Checklist: Using Carrierwave in a Rails project
This checklist should help you to check edge cases that are not part of the default Carrierwave configuration.
- Check Default Configuration and Suggested Changes
- Use secret URLs.
- Check if you need expiring public URLs.
- Check if you need an optimized cache
- Use a [nested directory structure](https://makandracards.com/m...
Always convert and strip user-provided images to sRGB
Debugging image color profiles is hard. You can't trust your eyes in this matter, as the image rendering depends on multiple factors. At least the operation system, browser or image viewer software and monitor influence the resulting image colors on your screen.
When we offer our users the possibility to upload images, they will most likely contain tons of EXIF metadata and sometimes exotic color profiles like eciRGB. We want to get rid of the metadata, as it might contain sensitiv...
A Migration Path to Bundler 2+
Bundler 2 introduced various incompatibilites und confusing behavior. To add to the confusion, Bundler's behavior changed after the release of their version 2.
The linked article explains what happened.
Understanding grid sizes of (SVG) icons
A primer on vector graphics
For rastered image formats like JPG or PNG, each pixel is basically drawn on a fixed size canvas. To display such an image in a different size (say: 1.5 times larger than original), the renderer (your Browser / GPU / Monitor) needs to interpolate the color values of missing pixels. The image will appear slightly blurred.
This is different for vector graphics like the SVG (Scalable Vector Graphics) format. You can imagine SVG files as XML file contai...
Automated wordbreaks for long words
The problem:
So I had the issue that User input (coming from many different sources and users) often contains the same long word. Maybe that's a super german thing to have lots of long words I have to deal with. This long word needs to be fully visible on small screens but none of the automated word-break solutions offered by css (https://justmarkup.com/articles/2015-07-31-dealing-with-long-words-in-css/) is clever or supported enough to be a good solution. So I...
Resources for working with the Youtube API
You can use the Youtube API to get data from youtube. Here are some resources and some things that are good to know.
You need to create an API key and each request will cost a certain amount of Request-Points (depending on the kind of query).
It may help to understand youtube's domain model before starting.
It's best to just try out your requests in the browser to see what you will get.
A request can look like this (note that you have to replace the playlis...
Bookmarklet to generate a Pivotal Tracker story from Zammad Ticket
This is a bookmarklet you can add to Chrome or Firefox which will allow you to create a story in Pivotal Tracker from a Zammad ticket. This might come in handy when creating stories for SWAT Teams.
But first you will have to set two variables in the script below:
-
pt_project_id
: the ID of the Pivotal Tracker Project you want to add stories to. This can be found as part of the URL of the project (https://www.pivotaltracker.com/n/projects/<pt_project_id>
) -
pt_token
: the Pivotal Tracker token used for authentication. Can be found in y...
Rails: Verify the CSRF token
Rails uses a CSRF token in forms and AJAX requests to verify a user request. Internally it compares the injected CSRF token of the form data with the CSRF token in the encrypted user session. To prevent SSL BREACH attacks, the CSRF token from the form data is masked.
To better debug issues, when these tokens do not match, it is useful to unmask the CSRF token from the form da...
Unicorn: How to force a single threaded boot in development
Unicorn allows you to specify the maximum number of workers. In development this could be useful if you use a debugger, but do not want to overflow the console with other request like from ActionCable. Then just set the maximum number of workers to 1
and the other requests have to wait.
UNICORN_WORKERS=1 rails server
Guidelines for Pull Requests and Code Reviews
Projects with more than one developer should always consider to enforce code review even for small changes to improves the overall code health of the system. Here are some guidelines that can help you to accomplish this task.
Github
How to write the perfect pull request
Google's Engineering Practices documentation
Modern Code Review: A Case Study at Google
Though...
A collection of useful design resources for developers
This collection contains some useful design resources for developers. Many of them were mentioned in the Refactoring UI tutorials.
Tutorials
Rails: Invoking a view helper from the console
There are a few ways to access view helpers from the Rails console. The easiest way is the helper
shortcut:
helper.translate 'i18n.string'
helper.your_helper_method
If the desired helper renders a view template, you need this setup:
view_paths = Rails::Application::Configuration.new(Rails.root).paths["app/views"]
av_helper = ActionView::Base.new(view_paths).extend YourHelperModule
av_helper.your_helper_method
Rails routing: Using constraints to avoid "Missing template" errors
You can use constraints in your routes.rb
to avoid getting ActionView::MissingTemplate
errors when wrong routes are called. Instead, the user will see a 404.
If you want multiple routes to use the same constraint you can use the block syntax:
constraints(format: 'html') do
resources :pages
resources :images
end
If you want constraints only on certain routes, you can do:
get '/users/account' => 'users#account', constraints: { format: 'html' }
Tip
You can also avoid this error type through [format con...
How to enable Chromedriver logging
When using Chrome for Selenium tests, the chromedriver
binary will be used to control Chrome. To debug problems that stem from Selenium's Chrome and/or Chromedriver, you might want to enable logging for the chromedriver itself. Here is how.
Option 1: Use Selenium::WebDriver::Service
In your test setup, you may already have something like Capybara::Selenium::Driver.new(@app, browser: :chrome, options: ...)
, especially when passing options like device emulation.
Similar to options
, simply add an extra key service
and pass an inst...
Bash script to list commits by Pivotal Tracker ID
The main benefit of our convention to prefix commits by their corresponding Pivotal Tracker ID is that we can easily detect commits that belong to the same story. You can either do that manually or use the bash script below by copying it somewhere to your .bashrc
.
# Usage: ptcommits 123456
function ptcommits {
if test "$1"
then
local PTID=$(echo "$1" | grep "[0-9]*" -o) # Allow URLs
git log --onel...