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 respond with 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 ...

Automatically validating dependency licenses with License Finder

"Open-source software (OSS) is great. Anyone can use virtually any open-source code in their projects."

Well, it depends. Licenses can make things difficult, especially when you are developing closed-source software. Since some OSS licenses even require the employing application to be open-sourced as well (looking at you, GPL), you cannot use such software in a closed-source project.

To be sure on this, we have developed a project-level integration of Pivotal's excellent [license_finder](https:/...

Shortcut for getting ids for an ActiveRecord scope

You can use .ids on an ActiveRecord scope to pluck all the ids of the relation:

# Modern Rails
User.where("users.name LIKE 'Foo Bar'").ids

# Rails 3.2+ equivalent
User.where("users.name LIKE 'Foo Bar'").pluck(:id)

# Edge rider equivalent for Rails 2+
User.where("users.name LIKE 'Foo Bar'").collect_ids(:id)

Testing ActiveRecord validations with RSpec

Validations should be covered by a model's spec.

This card shows how to test an individual validation. This is preferrable to save an entire record and see whether it is invalid.

Recipe for testing any validation

In general any validation test for an attribute :attribute_being_tested looks like this:

  1. Make a model instance (named record below)
  2. Run validations by saying record.validate
  3. Check if record.errors[:attribute_being_tested] contains the expected validation error
  4. Put the attribute into a valid state
  5. Run...

CSS variables aka CSS Custom Properties

CSS variables are very different from preprocessor variables. While preprocessors use variables to compile a static piece of CSS, CSS custom properties are a reactive (i.e. live) part of the styles. Think of them like usual CSS properties that cascade, but have:

  • A special syntax: CSS variables always start with a double-dash (--color)
  • No inherent meaning: Defining a CSS variable will not change any styles in itself
  • A special functionality: CSS variables can be used within the values of other properties, including CSS variables...

Carrierwave: Built-in RSpec matchers

CarrierWave comes with some RSpec matchers which will make testing more comfortable. Let's say you have an Uploader like this:

class MyUploader < CarrierWave::Uploader::Base
  include CarrierWave::MiniMagick

  # Create different versions of your uploaded files:
  version :small do
    process resize_to_fill: [100, 100]
  end
  
  version :medium do
    process resize_to_fit: [200, nil]
  end
  
  version :large do
    process resize_to_limit: [400, 400]
  end

end

Imagine you have a class Movie with an attribute poster. In ...

Output of ParallelTests::Cucumber::FailuresLogger was fixed in 4.9.1

Our projects with parallel_tests and cucumber used to have a patched failure logger as the one from parallel_tests was missing spaces which resulted in the output not being a valid rerun argument. With version 4.9.1 output of ParallelTests::Cucumber::FailuresLogger was fixed.

You can remove the patch (e.g. features/support/cucumber_failures_logger.rb) and switch the logger in config/cucumber.yml back to ParallelTests::Cucumber::FailuresLogger.

Thanks to Dominik for [the fix](https://github.com/grosser/parallel_tests/commit/...

Controlling smooth scrolling in browsers

It can be hard to understand what causes a browser scroll smoothly or instantly. CSS, JavaScript and the browser settings all have options to influence the scroll behavior. They all interact with each other and sometimes use the same words for different behavior.

CSS

Scrolling elements can use the scroll-behavior CSS property to express a preference between smooth and instant scrolling.

Preferring instant scrolling

CSS can prefer instant scrolling behavior:

html {
  scroll-behavior: auto; /* the default */
}

An `aut...

AppArmor in Linux

This note is a reminder that there is something called AppArmor that could cause weird errors ("File not found", "Can't open file or directory", ...) after configuration changes, e.g. when changing MySQL's data directory.

Remember to have a look at AppArmor's daemon configuration (usually at /etc/apparmor.d/) if you change daemon configuration and run into errors such as the one above.

Rails: How to get the ordered list of used middlewares

Rails middlewares are small code pieces that wrap requests to the application. The first middleware gets passed the request, invokes the next, and so on. Finally, the application is invoked, builds a response and passes it back to the last middleware. Each middleware now returns the response until the request is answered. Think of it like Russian Dolls, where each middleware is a doll and the application is the innermost item.

You can run rake middleware to get the ordered list of used middlewares in a Rails application:

$> rake midd...

PostgreSQL: Difference between text and varchar columns

TL;DR PostgreSQL handles Rails 4+ text and string columns the same. That said, there is still a semantic difference that might be used by your library's code.


PostgreSQL offers three character types for your columns:

  • character varying(n) (also called varchar or just string): Contents are limited to n characters, smaller contents are allowed.
  • character(n): All contents are padded with spaces to allocate exactly n characters.
  • text: There is no upper or lower character limit (except for the absolute maximum...

Extracting parts of forms into Unpoly modals/popups

Say you wrap your index view in a form to apply different filters like pagination or a search query. On submit, your index view changes when the filters are applied (through up-submit and up-target). Now you want to enable more data-specific filters using a separate "Filters" button that opens a popup to not overload your UI.

Filter bar:

Filter popup:

The problem is tha...

Updated: Unpoly + Nested attributes in Rails: A short overview of different approaches

With the new unpoly client side templates (available since 3.10) there's another way to substitute the ids of inserted nested attribute forms which I added to this card.

Changes to positional and keyword args in Ruby 3.0

Ruby 3.0 introduced a breaking change in how it treats keyword arguments.

There is an excellent blog post on the official Ruby blog going into the details. You should probably read that, but here is a slightly abbreviated version:

What changed

When the last argument of a method call is a Hash, Ruby < 3 automatically converted it to to Keyword Arguments. If you call a method in Ruby >= 3 that accepts keyword arguments, eithe...

CarrierWave: How to remove GIF animation

When accepting GIF images, you will also accept animated GIFs. Resizing them can be a time-consuming task and will block a Rails worker until the image is processed.

Save yourself that trouble, and simply tell ImageMagick to drop any frames but the first one.

Add the following to your uploader class:

process :remove_animation

private

def remove_animation
  if content_type == 'image/gif'
    manipulate! { |image| image.collapse! }
  end
end

You may also define that process for specific versions only (e.g. only for thum...

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...

How to apply transparency to any color with pure CSS

To apply transparency to an element, you can use opacity in CSS. However, sometimes you don't want to make the entire element transparent, only a color.
Using not-so-modern CSS, you can simply generate non-opaque versions of a color. This card describes how to do that.

Note that we're not talking about defining colors with transparency. This is about the case where you have a color but need a more transparent variant of it (e.g. for a border, background, etc.), and where your component does that without defining the transparent variant ...

How to invert currentColor with pure CSS

The currentColor CSS keyword references the current text color and can be used to apply an element's text color to other properties.
Using modern CSS, you can also use it to calculate colors from it. This card describes how to invert currentColor, but you can use this technique for other calculations as well.

How to invert currentColor

They key is CSS' hsl() function and from keyword for it:

--inverted-color: hsl(from ...

Selecting the nth element matching a selector

The :nth-child pseudo class is commonly used for targeting elements based on their position within a parent container, for example the third element in a list or every even-numbered item. However, :nth-child can do more.

In modern CSS specifications (Level 4), there’s an additional feature that lets you use :nth-child in combination with a list of css selectors. This way, you can ta...

The developer console can do more than you think!

You can do so much more than console.log(...)! See the attached link for a great breakdown of what the developer console can give you.

Some of my favorites:

console.log takes many arguments

E.g. console.log("Current string:", string, "Current number:", 12)

Your output can have hyperlinks to Javascript objects

E.g. console.log("Check out the current %o, it's great", location)

[Di...

JSON APIs: Default design for common features

When you build a JSON API you need to come up with a style to represent attributes, pagination, errors or including associated objects. Instead of reinventing the wheel, you may reuse successful API designs.

JSON API

JSON:API specifies common features found in most JSON APIs, like pagination, ordering and nested resources. The spec looks very similar to how one would build an API with Rails and uses similar patterns. Even if you don't plan on supporting the whole spec, it can still make sense to know how th...

Capybara: Preventing server errors from failing your test

When your Rails application server raises error, Capybara will fail your test when it clears the session after the last step. The effect is a test that passes all steps, but fails anyway.

Capybara's behavior will help you to detect and fix errors in your application code. However, sometimes your application will explode with an error outside your control. Two examples:

  • A JavaScript library references a source map in its build, but forgets to package the source map
  • CarrierWave cleans up an upload or cache file after the record was delet...