Enumerators in Ruby
Starting with Ruby 1.9, most #each
methods can be called without a block, and will return an enumerator. This is what allows you to do things like
['foo', 'bar', 'baz'].each.with_index.collect { |name, index| name * index }
# -> ["", "bar", "bazbaz"]
If you write your own each
method, it is useful to follow the same practice, i.e. write a method that
- calls a given block for all entries
- returns an enumerator, if no block is given
How to write a canonical each
method
To write a m...
ActiveSupport includes Timecop-like helpers
ActiveSupport (since 4.1) includes test helpers to manipulate time, just like the Timecop gem:
-
To freeze the current time, use
freeze_time
(ActiveSupport 5.2+):freeze_time
-
To travel to a specific moment in time, use
travel_to
:travel_to 1.hour.from_now
Important
When freezing time with
#travel_to
, time will be frozen (like withfreeze_time
). This means that your application can't detect passage of time by usingTime.now
. -
To travel a re...
Heads up: pg_restore --clean keeps existing tables
When restoring a PostgreSQL dump using pg_restore
, you usually add the --clean
flag to remove any existing data from tables.
Note that this only removes data from tables that are part of the dump and will not remove any extra tables. You need to do that yourself.
When is this relevant?
As an example: You want to load a staging dump into your development machine. On your development machine, you have run migrations that introduced more tables which do not yet exist on staging. pg_restore
with --clean
will loa...
Rails 8 introduces `params.expect`
The new params.expect
method in Rails 8 improves parameter filtering, addressing issues with malformed input and enhancing security. It provides a cleaner, more explicit way to enforce the structure and types of incoming parameters.
What changed
-
Replaces
require
andpermit
: Combines both methods for concise parameter validation. - Explicit Array Handling: Requires double array syntax to define arrays of hashes, improving clarity.
- Enhanced Validation: Ensures expected parameter structure, rejecting malformed input wi...
Specify Gemfile for bundle
Bundler allows you to specify the name of the Gemfile you want to bundle with the BUNDLE_GEMFILE
environment variable.
BUNDLE_GEMFILE=Gemfile.rails.7.2 bundle
By default, bundler will look for a file called Gemfile
in your project, but there may be cases where you want to have multiple Gemfiles in your project, which cannot all be named Gemfile
. Let's say for example, you maintain a gem and want to run automated tests against multiple rails versions. When you need to bundle one of your secondary Gemfiles, the solution above ...
Rails console tricks
Also see the list of IRB commands.
Switching the context
Changes the "default receiver" of expressions. Can be used to simulate a "debugger situation" where you are "inside" an object. This is especially handy when needing to call private methods – just invoke them, no need to use send
.
- Switch to an object:
chws $object
- Reset to
main
:chws
- Show current context:
cwws
(usually shown in IRB prompt)
[Technical details](https://technology.doximity.com/articles/the-hidden-gems-of-r...
Does <html> or <body> scroll the page?
TL;DR: All modern browsers default to using the <html>
element as the main document viewport. In CSS, prefer to set overflow
properties to html
(or :root
).
Scrolling the main viewport with JavaScript
The browser's main document viewport is also scrollable by default. The element that corresponds to the main viewport is either <html>
(document.documentElement
) or <body>
(document.body
). Which one depends on the browser.
When you want to update the current `sc...
Cucumber features as documentation
Cucumber allows for prose in features and scenarios. Example:
Feature: Cancel account
There are several ways to cancel a user account. Admins need to
do it in complex cases, but normally, users can do it themselves.
Scenario: User cancels his own account
Users should be able to cancel an account themselves, so the
admins do not need to do it.
Given a user account for "willy@astor.de"
When I sign in as "willy@astor.de"
And I follow "Cancel account"
Then I should see "Account canceled"...
An auto-mapper for ARIA labels and BEM classes in Cucumber selectors
Spreewald comes with a selector_for
helper that matches an English term like the user's profile
into a CSS selector. This is useful for steps that refer to a particular section of the page, like the following:
Then I should see "Bruce" within the user's profile
^^^^^^^^^^^^^^^^^^
If you're too lazy to manually translate English to a CSS selector by adding a line to features/env/selectors.rb
, we already have an [auto-mapper to translate English into ...
Disable automatic code suggestions in RubyMine
To disable the mostly useless automatic suggestion popups in RubyMine, go to File / Settings, then to Editor / General / Code Completion and uncheck Auto-display code completion.
You can still open the popup by pressing CTRL + Space
. And you probably want to use Context-dependent word expansion instead, anyway.
Why am I getting different results working with SVG files and ImageMagick?
When you are working with SVG files and ImageMagick you can get different results on different machines depending on which additional packages you have installed.
From: http://www.imagemagick.org/script/formats.php
ImageMagick utilizes inkscape if its in your execution path otherwise RSVG. If neither are available, ImageMagick reverts to its internal SVG renderer.
Git: How to stage hunks with a single key press
In interactive commands, Git allows the user to provide one-letter input with a single key without hitting enter (docs).
# Enabled this feature globally
git config --global interactive.singlekey true
# Or enable this feature locally for a single repository
git config interactive.singlekey true
This allows you to hit "y
" instead of "y + ENTER
" to move to the next hunk.
Stage this hunk [y,n,q,a,d,s,e,?]?
Building web applications: Beyond the happy path
When building a web application, one is tempted to claim it "done" too early. Make sure you check this list.
Different screen sizes and browsers
Desktops, tablets and mobile devices have all different screen resolutions. Does your design work on each of them?
- Choose which browsers to support. Make sure the page looks OK, is usable and working in these browsers.
- Use @media queries to build a responsive design
- If you do not suppo...
How to use html_safe correctly
By default, Rails views escape HTML in any strings you insert. If you want to insert HTML verbatim, you need to call #html_safe
. However, #html_safe
does not "unescape" a string. It merely marks a string as safe for unescaped insertion.
How html_safe works
Calling html_safe
on a String
returns a new object that looks and acts like a String
, but actually is a ActiveSupport::SafeBuffer
:
"foo".length
# => 3
"foo".class
# => String
"foo".html_safe.length
# => 3
"foo".html_safe.class
# => ActiveSupport::S...
Rails I18n fallback locales
When you need to create a locale for a language variant (like Austrian for German), you probably don't want to duplicate your entire de.yml
file only to change a few minor exceptions for our Austrian friends.
Luckily, the I18n gem used by Rails has a fallback feature where you can make one locale file fall back to another if no translation is available.
In the example above you would have a config/locales/de_DE.yml
:
de_DE:
# hundreds of translations here
... and another...
Unpoly: Showing the better_errors page when Rails raises an error
When an AJAX request raises an exception on the server, Rails will show a minimal error page with only basic information. Because all Unpoly updates work using AJAX requests, you won't get the more detailled better_errors page with the interactive REPL.
Below is an event listener that automatically repeats the request as a full-page load if your development error shows an error page. This means you get...
Sidekiq: Problems and Troubleshooting
When using Sidekiq in your application, you must write thread-safe code.
This wiki page also lists gems that are known to be unsafe on threaded applications.
When adding a gem that will also be used by a Sidekiq worker, make sure to confirm it's thread-safe.
Caution when using the || operator to set defaults
I often see the use of ||
to set a default value for a variable that might be nil
, null
or undefined
.
x = x || 'default-value'
This pattern should be avoided in all languages.
While using ||
works as intended when x
is null or an actual object, it also sets the default value for other falsy values, such as false
. false
is a non-blank value that you never want to override with a default.
To make it worse, languages like JavaScript or Perl have [many more fal...
Caching in Rails < 6.1 may down parts of your application when using public cache control
TL;DR When using Cache-Control
on a Rails application, make sure the Vary: Accept
header is set.
Proxy caching is a good feature to serve your publicly visible application content faster and reduce load on your servers. It is e.g. available in nginx, but also affects proxies delivered by ISPs.
Unfortunately, there is a little problem in Rails < 6.1 when delivering responses for different MIME-types. Say you have an arbitrary route in your Rails application that is able to respond with regular HTML and JSON. By sending the specific ...
Reverse lookup a fixture name by its id and table name
To reverse lookup a fixture by its table name and id, use the following approach on ActiveRecord::FixtureSet
:
table = 'users' # Specify the fixture table name
id = 123122 # Specify the ID to look for
# Find the fixture that matches the given ID
ActiveRecord::FixtureSet.all_loaded_fixtures[table].fixtures.find { |key, value| value['id'] == id }
Result Example:
[
"one", # Fixture name
#<ActiveRecord::Fixture:0x00007e79990234c8>, # ActiveRecord::Fixture object
@fixture= { ... }, # The raw fixtu...
Updated: How to allow testing beforeunload confirmation dialogs with modern ChromeDrivers
Updated for selenium-webdriver 4.27 which requires options.add_option(:page_load_strategy, 'none')
.
NPM: How to verify that your package-lock.json fulfills dependencies of package.json
Your package-lock.json
should always match and resolve all packages from your package.json
.
Coming from Yarn, I was looking for an option like Yarn's --frozen-lockfile
which validates that. Here is what seems to be the way to do it.
Using npm clean-install
Running npm clean-install
instead of npm install
will actually validate that your package-lock.json
matches your package.json
.
If your package-lock.json
cannot be fulfilled, npm install
would install other versions while npm clean-install
will complain.
You can ...
Rails: Looking up constants by their name string
TL;DR: Rails ships two methods to convert strings to constants, constantize
and safe_constantize
. Neither is safe for untrusted user input. Before you call either method you must validate the input string against an allowlist. The only difference between the two methods is that unresolvable constants raise an error with constantize
, but return nil
with safe_constantize
. If you validate the input string against an allowlist, an error should never happen.
Preventing Dangerous Lookups
Suppose an application uses eit...
How to disable logging for ActiveStorage's Disk Service routes
In development, we store files using ActiveStorage's disk
service. This means that stored files are served by your Rails application, and every request to a file results in (at least!) one non-trivial log entry which can be annoying. Here is how to disable those log entries.
Example
Here is an example of what loading a single <img>
in an example application writes to the Rails log.
Started GET "/rails/active_storage/blobs/redirect/..." for ::1 at ...
Processing by ActiveStorage::Blobs::RedirectController#show as SVG
Parameter...