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 [...
How to find out what is running on a port on a remote machine
By convention, common protocols use a defined port, like 80 for HTTP or 443 for HTTPS.
You can use nmap to find out what service is running behind a given port, and most often see some details about it. This can be helpful if servers don't offer the services you expect for some ports. If you'd like to see what ports are listing on your local machine, you might want to use ss instead of nmap.
Note that nmap's service discovery may trigger several requests.
Example
When using nmap, adding the -A switch will ...
How to organize large I18n dictionaries in Ruby on Rails
If you're suffering from a huge de.yml or similiar file, cry no more. Rails lets you freely organize your dictionary files in config/locales.
My organization works like this:
-
config/locales/rails.de.ymlmodified Rails boilerplate -
config/locales/faker.de.ymlmodified Faker boilerplate -
config/locales/models.de.ymlmodel names, attribute names, assignable_value labels - `config/locales/views.de.y...
Transfer records to restore database entries (with Marshal)
If you ever need to restore exact records from one database to another, Marshal might come in handy.
Marshal.dump is part of the ruby core and available in all ruby versions without the need to install anything. This serializes complete ruby objects including id, object_id and all internal state.
Marshal.load deserializes a string to an object. A deserialized object cannot be saved to database directly as the the dumped object was not marked dirty, thus rails does not see the need to save it, even if the object is not present in...
Modern HTTP Status codes for redirecting
Formerly 301 (Moved Permanently) and 302 (Found) were used for redirecting. Browsers did implement them in different ways, so since HTTP 1.1 there are some new status codes which allow for finer distinctions.
The interesting part is how non-GET requests are handled by the redirect. It is preferrable to use the newer status code to avoid unexpected behavior.
303 See Other
The response to the request can be found under anot...
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...
Migration from the Asset Pipeline to Webpacker
This is a short overview of things that are required to upgrade a project from the Asset Pipeline to Webpacker. Expect this upgrade to take a few days even the diff is quite small afterwards.
Preparations
1. Find all libraries that are bundled with the asset pipeline. You can check the application.js and the application.css for require and import statements. The source of a library is most often a gem or a vendor directory.
2. Find an working example for each library in the application and write it down.
3. Find out the ver...
How to debug file system access in a Rails application
It might sometimes be useful to check whether your Rails application accesses the file system unnecessarily, for example if your file system access is slow because it goes over the network.
The culprit might be a library like carrierwave that checks file existence or modification times, whereas your application could determine all this from your database.
Introducing strace
One option it to use strace for this, which logs all system calls performed by a process.
To do this, start your rails server using something like
DISA...
How to silence Puma for your feature tests
When RSpecs runs the first feature spec, you may see log output like this:
Capybara starting Puma...
* Version 6.5.0, codename: Sky's Version
* Min threads: 0, max threads: 4
* Listening on http://127.0.0.1:39949
You can disable this behavior by tweaking Capybara's Puma server in your spec/support/capybara.rb:
Capybara.server = :puma, { Silent: true }
Note
You don't need to configure this if you're using system tests with modern versions of Rails. They do [exactly the same](https://github.com/rails/rails/blob/ma...
Be very careful with 301 and 308 redirects
Browsers support different types of redirects.
Be very careful with these status codes:
301 Moved Permanently308 Permanent Redirect
Most browsers seem to cache these redirects forever, unless you set different Cache-Control headers. If you don't have any cache control headers, you can never change them without forcing users to empty their cache.
Note
By default Rails sends a ...
The TCF 2.0 (Tranparency and Consent Framework) standard, and what you should know about it
The Interactive Advertising Bureau (IAB) is a European marketing association which has introduced a standard how advertising can be served to users in line with the General Data Protection Regulation (GDPR). This standard is called the TCF 2.0 (Transparency and Consent Framework). If you want to integrate any kind of advertising into a website, chances are the advertising network will require your website to implement that standard. This is a very brief overview of what this means:
The basic idea in the TCF 2.0 ...
Concurrency issues with find-as-you-type boxes
Find-as-you-type boxes are usually built by observing changes in a text field, and querying the server via AJAX for search results or suggestions when the field has changed.
A common problem with this implementation is that there is no guarantee that AJAX responses are evaluated in the same order as the original requests. The effect for the user is that the search results are flashing back and forth while the user is typing the query, and when the user has stopped typing the last results don't always match the final query.
Workarounds
----...
Capistrano task to edit staging / production credentials
When using Rails credentials, you will edit the encrypted credentials for staging or production environments from time to time. To do that you need the secret key which should only live on the servers.
Do not download these key files to your local dev environment. They are sensitive and must not be stored on your machine.
Instead, put the attached capistrano task into lib/capistrano/tasks/ of your application. It expects environment specific keys to live in :shared_path/config/credentials/:stage.key. If you have a single master.key...
JavaScript: Comparing objects or arrays for equality (not reference)
JavaScript has no built-in functions to compare two objects or arrays for equality of their contained values.
If your project uses Lodash or Underscore.js, you can use _.isEqual():
_.isEqual([1, 2], [2, 3]) // => false
_.isEqual([1, 2], [1, 2]) // => true
If your project already uses Unpoly you may also use up.util.isEqual() in the same way:
up.util.isEqual([1, 2], [2, 3]) // => false
up.util.isEqual([1, 2], [1, 2]) // => true
If you are wri...
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 ...
Generating test images on the fly via JavaScript or Ruby
When you need test images, instead of using services like lorempixel or placehold.it you may generate test images yourself.
Here we build a simple SVG image and wrap it into a data: URI. All browsers support SVG, and you can easily adjust it yourself.
Simply set it as an image's src attribute.
JavaScript
Simple solution in modern JavaScript, e.g. for use in the client's browser:
function svgUri(text) {
let svg = `
<svg wid...
Better numeric inputs in desktop browsers
You want to use <input type="number"> fields in your applications.
However, your desktop users may encounter some weird quirks:
- Aside from allowing only digits and decimal separators, an "e" is also allowed (to allow scientific notation like "1e3").
- Non-technical users will be confused by this.
- Your server needs to understand that syntax. If it converts only digits (e.g.
to_iin Ruby) you'll end up with wrong values (like 1 instead o...
Popular mistakes when using nested forms
Here are some popular mistakes when using nested forms:
- You are using
fields_forinstead ofform.fields_for. - You forgot to use
accepts_nested_attributesin the containing model. Rails won't complain, but nothing will work. In particular,nested_form.objectwill benil. - The
:reject_ifoption lambda in youraccepts_nested_attributescall is defined incorrectly. Raise the attributes hash given to your:reject_iflambda to see if it looks like you expect. - If you are nesting forms into nested forms, each model involved ne...
When does Webpacker compile?
Webpack builds can take a long time, so we only want to compile when needed.
This card shows what will cause Webpacker (the Rails/Webpack integration) to compile your assets.
When you run a dev server
While development it is recommended to boot a webpack dev server using bin/webpack-dev-server.
The dev server compiles once when booted. When you access your page on localhost before the initial compilation, the page may load without assets.
The ...
ActiveRecord: String and text fields should always validate their length
If you have a :string or :text field, you should pair it with a model validation that restricts its length.
There are two motivations for this:
- In modern Rails, database types
:stringand:textno longer have a relevant size limit. Without a validation a malicious user can quickly exhaust the hard drive of your database server. - In legacy Rails (or database schemas migrated from legacy Rails), database types
:stringand:texthad a database-side length constraint. When the user enters a longer string, the ActiveRecord valida...
Use <input type="number"> for numeric form fields
Any form fields where users enter numbers should be an <input type="number">.
Numeric inputs have several benefits over <input type="text">:
- On mobile or tablet devices, number fields show a special virtual keyboard that shows mostly digit buttons.
- Decimal values will be formatted using the user's language settings.
For example, German users will see1,23for<input type="number" value="1.23">. - Values in the JavaScript API or when submitting forms to the server will always use a point as decimal separator (i.e.
"1.23"eve...
open-next-failure: An alias to speed up test debugging
Getting an entire test suite green can be a tedious task which involves frequent switches between the CLI that is running tests back to the IDE where its cause can be fixed.
The following bash aliases helped me speed up that process:
alias show-next-failure="bundle exec rspec --next-failure"
alias open-next-failure="show-next-failure || show-next-failure --format json | jq -r '.examples[0]' | jq '\"--line \" + (.line_number|tostring) + \" \" + .file_path' | xargs echo | xargs rubymine"
There is a lot going on above but the gist...
How Rails chooses error pages (404, 500, ...) for exceptions
When your controller action raises an unhandled exception, Rails will look at the exception's class and choose an appropriate HTTP status code and error page for the response.
For instance, an ActiveRecord::RecordNotFound will cause Rails to render a red "The page you were looking for doesn't exist" with a status code of "404" (not found).
The mapping from exception classes to error types is a hash in Rails.configuration.action_dispatch.rescue_responses. The...
Devise: Invalidating all sessions for a user
Background information about session storage in Rails
Rails has a default mechanism to store the session in the CookieStore. This is a cookie which holds the entire user session hash in the browser. This cookie is serialized, encoded with base64, and signed.
How Devise handles authentication
Devise uses this CookieStore. To track a users session, a salt is stored in the session ...