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:
- Make a model instance (named
record
below) - Run validations by saying
record.validate
- Check if
record.errors[:attribute_being_tested]
contains the expected validation error - Put the attribute into a valid state
- 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 calledvarchar
or juststring
): 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...