Rails: Report CSP Violations to Sentry
You can report CSP violations to Sentry.
Within config/initializers/content_security_policy.rb
:
Rails.application.configure do
config.content_security_policy do |policy|
# Settings for the policy
policy.report_uri 'https://ooo4444bbb.ingest.de.sentry.io/api/ooo4444bbb/security/?sentry_key=ooo4444bbb'
end
end
Replace the actual report_uri
with the one from your project settings under [https://makandra-eu.sentry.io/settings/projects//security-headers/](https://makandra-eu.sentry.io/settings/projects/m...
Simple gem for CLI UIs
If you want to build a small CLI application, that supports more advanced inputs than gets
, I recommend using the cli-ui gem. It's a small dependency-free library that provides basic building blocks, like an interactive prompt:
require "cli/ui"
CLI::UI::StdoutRouter.enable
puts CLI::UI.fmt "a small {{red:demo}}"
# supports h, j, k, l, arrows and even filtering
CLI::UI::Prompt.ask("Choose a plan:", options: ["small", "medium", "large"])
or a simple progress bar for long running scrip...
Gatekeeping: Guide for developer
If your project manager wants to do gatekeeping on a project, as a developer you need to follow the following guidelines (e.g. by using something like this issue checklist template).
In order to reduce the number of rejects we get from clients, we want to review all code written before it goes to the staging server.
Note: This process is tailored to our specific needs and tools at makandra. While it will certainly not apply to all (especially larger tea...
Cancelling the ActiveRecord callback chain
What | Rails version | Within before_*
|
Within after_*
|
---|---|---|---|
Cancel later callbacks | Rails 1-4 | return false |
return false |
Cancel later callbacks | Rails 5+ | throw :abort |
throw :abort |
Rollback the transaction | Rails 1-4 | return false |
raise ActiveRecord::Rollback |
Rollback the transaction | Rails 5+ | `thr... |
RSpec: How to define classes for specs
RSpec allows defining methods inside describe
/context
blocks which will only exist inside them.
However, classes (or any constants, for that matter) will not be affected by this. If you define them in your specs, they will exist globally. This is because of how RSpec works (short story: instance_eval
).
describe Notifier do
class TestRecord
# ...
end
let(:record) { TestRecord.new }
it { ... }
end
# TestRecord will exist here, outside of the spec!
This will come bite you at least when you try to define a ...
Adding comments to ambiguous database columns
The DB schema is the most important source of truth for your application and should be very self-explanatory. If determining the true meaning of a DB column requires historical research in your issue tracker or reverse engineering of your source code you might consider adding a comment.
Both PostgreSQL and MySQL support comments in the DB schema:
- For new columns: https://guides.rubyonrails.org/active_record_migrations.html#comments
- Changing the comment for existin...
Style Guide for Git commit messages
- Separate subject from body with a blank line
- Limit the subject line to 50 characters (max. 72), include reference (unique story ID) to requirements tracker (Linear in our case)
- Capitalize the subject line
- Do not end the subject line with a period
- Use the imperative mood in the subject line
- Wrap the body at 72 characters
- Use the body to explain what and why vs. how.
Tip
As an alternative, use a commit message that refers to a GitHub issue (
fixes #321
) or [story ID](https://makandracards.com/makandra/620718-b...
Taking screenshots in Capybara
Capybara-screenshot can automatically save screenshots and the HTML for failed Capybara tests in Cucumber, RSpec or Minitest.
Requires Capybara-Webkit, Selenium or poltergeist for making screenshots. Screenshots are saved into $APPLICATION_ROOT/tmp/capybara
.
Manually saving a page
Additionally you can trigger the same behavior manually from the test using Capybara::Session#save_and_open_page and [...
Chrome DevTools: Treasure (Overview)
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.
Analysing
Breakpoints
- [Breakpoints on HTML Elements](https://makandracards.com/makandra/517982-chrome-devtools...
JavaScript: Sharing content with the native share dialog
Mobile Chrome and Safari support the "web share API" which allow you to use the native share functionality of an Android or iOS phone. Some desktop OSs like Windows or MacOS also support native share dialogs. See Can I Use for a detailed support matrix.
When clicking a share button using this API, the browser will automatically show all installed applications that support content sharing, such as Whatsapp, Facebook, Twitter, e-mail etc.
The API is extremely simple to use:
if ...
RSpec: Inferring spec type from file location
RSpec Rails can automatically mix in different behaviors to your tests based on their type
tag, for example enabling you to call get
and
post
in specs with the tag type: :request
.
Alternatively you can skip these tags by setting the config config.infer_spec_type_from_file_location!
in the spec_helper.rb
. This will automatically choose the right type context based on the file location of the test.
For instan...
How to: Self-hosted fonts via NPM packages
We usually ship applications that self-host webfonts to comply with GDPR.
Many popular web fonts are available as NPM packages provided by Fontsource.
We recommend using those instead of downloading and bundling font files yourself. (See below for a list of benefits.)
Usage
- Go to fontsource.org and search for the font you want to add (or a font that suits your application).
- Click the font card to vie...
Git: Removing feature branches on merge
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....
Common mistakes when storing file uploads with Rails
1. Saving files to a directory that is not shared between deploys or servers
If you save your uploads to a made up directory like "RAILS_ROOT/uploads"
, this directory goes away after every deploy (since every release gets a new). Also this directory is not shared between multiple application servers, so your uploads are randomly saved to one local filesystem or another. Fixing this afterwards is a lot of fun.
Only two folders are, by default, shared between our application servers and deployments: "RAILS_ROOT/storage"
and `"RAILS...
Better performance insights with gem `rails_performance`
Even if you don't make any beginner mistakes like N+1 queries or missing DB indices, some requests can have bad performance. Without good performance metrics, you probably won't notice this until it's too late.
We investigated multiple gems and found that rails_performance
(https://github.com/igorkasyanchuk/rails_performance) provides a lot of valuable information with very little setup cost. It only needs Redis which we use in the majority of our applications anyw...
CarrierWave: Default Configuration and Suggested Changes
CarrierWave comes with a set of default configuration options which make sense in most cases. However, you should review these defaults and adjust for your project wherever necessary.
You will also find suggestions on what to change below.
Understanding the default configuration
Here is the current default config for version 2:
config.permissions = 0644
config.directory_permissions = 0755
config.storage_engines = {
:f...
Supporting multiple SAML IdPs within a single Rails application
The linked article shows how to configure omniauth-multi-provider
to support multiple SAML identity providers for a single Rails app:
To solve this, the omniauth-multi-provider gem acts as a dynamic wrapper around OmniAuth. It enables your application to load the correct IdP configuration at runtime—based on the tenant—allowing for flexible and secure SSO authentication across multiple organisations.
Selenium: Fix Chrome's "Unsafe Password" Warning
tl;dr
Set
profile.password_manager_leak_detection
tofalse
in your Selenium Chrome options to disable password leak detection and suppress the warning.
Problem
When running Selenium tests with recent versions of Chrome and Chromedriver (e.g., version 136+), entering “unsafe” (weak or reused) passwords in forms triggers a browser warning:
"This password has appeared in a data breach…"
This alert can break automated test runs, especially in CI/CD pipelines.
Solution
You can **disable Chrome’s password leak ...
Using Passenger Standalone for development
For our production servers we use Passenger as a Ruby application server. While it is possible to use Passenger for development as an Apache module, the installation process is not for the faint of heart.
Luckily Passenger also comes as a standalone binary which requires zero configuration.
You can Passenger Standalone as a replacement for Webrick or Thin if you'd like to:
- Use SSL certificates locally
- Get performance behavior that is closer to ...
How to make changes to a Ruby gem (as a Rails developer)
At makandra, we've built a few gems over the years. Some of these are quite popular: spreewald (> 1M downloads), active_type (> 1M downloads), and geordi (> 200k downloads)
Developing a Ruby gem is different from developing Rails applications, with the biggest difference: there is no Rails. This means:
- no defined structure (neither for code nor directories)
- no autoloading of classes, i.e. you need to
require
all files yourself - no
active_support
niceties
Also, their scope...
Using the alt attribute and the figcaption element in HTML
While both the alt attribute and the figcaption element provide a way to describe images, the way we write for them is different:
- alt descriptions should be functional
- figcaption descriptions should be editorial or illustrative
Using FactoryBot in Development
If you need dummy data to play around with in development, it's often faster to reuse your existing factories instead of using the UI or creating records in the Rails console. This approach saves time and gives you useful defaults and associations right out of the box.
You can use FactoryBot directly in the Rails console like this:
require 'factory_bot_rails' # Not needed if the factory_bot_rails gem is in the :development group
FactoryBot.create(:user)
You can also apply traits or override attributes:
FactoryBot.create...
Web performance snippets: little scripts that return performance metrics
Use these snippets when you want to measure yourself.
Currently available:
Core Web Vitals
Largest Contentful Paint (LCP)
Largest Contentful Paint Sub-Parts (LCP)
Quick BPP (image entropy) check
Cumulative Layout Shift (CLS)
Loading
Time To First Byte
Scripts Loading
Resources hints
Find Above The Fold Lazy Loaded Images
Find non Lazy Loaded Images outside of the viewport
Find render-blocking resources
Image Info
Fonts Preloaded, Loaded, and Used Above The Fold
First And Third Party Script Info
First And Third Party Script Timings
I...
Capybara: Waiting for pending AJAX requests after a test
When ending a Selenium test Capybara resets the browser state by closing the tab, clearing cookies, localStorage
, etc.
It may be a good idea to wait for all in-flight AJAX requests to finish before ending a scenario:
- You may have client-side JavaScript that freaks out when the tab closure kills their pending requests. If that JavaScript opens an error alert or spams errors to the console, your test may fail after the last step.
- With unlucky timing the server may receive an AJAX request as the browser tab closes, causing a connection ...