3780 cards
Linked content

Clean your Rails routes: grouping

In Ruby on Rails, all the routes of a given application can be found within the config/routes.rb file.
You add more and more routes in this file as your project grows.

The problem here is that this file potentially becomes very complicated to manage over the time.
That’s why it’s important to find a way to order and maintain your routes.

See: Clean your Rails routes: grouping

Sometimes the routes.rb grows very fast and each line adds mo...


Project management best practices: Stories

We organize our daily work with stories in Pivotal Tracker.

Story format

A good story needs to be precise. It should be very clear what is part of a story, and what is not. If there are different expectations between the person who writes and who implements a story, there will be rejects.

To this end, we use a consistent format for stories that looks like this:

Story: Autocomplete

As a journalist, I want to have an autocomplete in the search bar, to have a more efficient way to find articles.

Acceptance criteria

Rails < 5: How to get after_commit callbacks fired in tests

If you use transactional_fixtures or the database_cleaner gem with strategy :transaction, after_commit callbacks will not be fired in your tests.

Rails 5

Rails 5 has a fix for this issue and no further action is needed.

Rails 3+

Add the gem test_after_commit to your test group in the Gemfile and you are done. You don't need to change the database strategy to deletion (which might...


Preloaded associations are filtered by conditions on the same table

When you eagerly load an association list using the :include option, and at the same time have a :condition on an included table, two things happen:

  1. Rails 2, 3, 4, 5 tries to load all involved records in a huge single query spanning multiple database tables.
  2. The preloaded association list is filtered by the :condition, even though you only wanted to use the :condition to filter the containing model.

The second case's behavior is mostly unexpected, because pre-loaded associations usually don't care about the circumstances unde...

Linked contentRepeats

Chrome Lighthouse

Chrome has a built-in utility to check performance and accessibility (and more) of your web app: Lighthouse.

Open the Develeoper Tools and go to the lighthouse tab:


Then you'll see some suggestions on how to improve your site.
This is cool, because you can even use it with non-public pages or your development environment (but be aware that some settings we're using for development, like not minifying JS and CSS files, might ruin your stats...


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,?]?

Selenium: How to debug the communication with the Webdriver API

Selenium allows you to log all requests to the Webdriver API. Therefore add the following line to e.g. features/support/selenium.rb:

Selenium::WebDriver.logger.level = :debug

If you want to see the output of the driver itself, here is an example on how to enable Chromedriver logging.

Example output

When you run a command like bundle exec cucumber --format=pretty features/some.feature you will see the API communication before the step is printed (here you see the log for the step And I press "Save").


Ruby: Appending lines to a file in sync

When writing some logs to a file, that don't use Ruby's logger utility, it is often useful to sync them. So other process can read the output just in time.

Example with enabled sync

log_path = '/tmp/some_log.log'

log_file = File.open(log_path, 'a+')
log_file.sync = true

log_file.puts('Some log message')
File.read(log_path) #=> "Some log message\n"

log_file.puts('Some other message')
File.read(log_path) #=> "Some log message\nSome other message\n"

Example ...

Linked content

Webpacker: Disable source maps

You can do this per environment, e.g. in config/webpack/test.js:

const environment = require('./environment')
const config = environment.toWebpackConfig()
config.devtool = 'none'
module.exports = config

Your Cronjobs should not rely on a perfect schedule

Due to network or hardware failures, it can happen that one of your cronjobs will not run at the time you specify in the schedule. Your code should be built in a way that it can be re-run at a later time (when the failure is resolved).

For example, if you are synchronizing data with another service once every day, your cronjob should not only synchronize changes from the last 24 hours. If you do this and a network failure will delay the execution of your job by 5 hours, you will only synchronize changes from hour 6-29, but forget change...

Linked contentRepeats

SVGO: SVG Optimizer

SVG files are often much larger than necessary, containing comments, metadata, hidden elements etc.

Optimize them with this tool.

Note that for a properly scaling SVG, you need to keep the viewBox attribute. There's an option --disable=removeViewBox for this.


Decide whether cronjobs should run on one or all servers

Understanding your type of cronjob

Some cronjobs must only run on a single server. E.g. when you run nightly batch operations on the database, it should probably run on a single server. Running it on multiple servers would likely result in deadlocks or corrupt data.

Some cronjobs must always run on all servers. E.g. starting a sidekiq process on reboot.

Configuring whenever

If not configured otherwise, cronjobs defined in whenever's `s...

Linked contentAuto-destruct in 22 days

Updated: Fixing flaky integration tests

Added these two sections:

Tool 6: Use a debugger

For debugging flaky issues, it might be helpful to halt after the failed step. This gives you the chance interact with the browser and better understand the root cause.

# Run an example with `DEBUG_CUCUMBER=true bundle exec bin/cucumber some.feature:10 --format=pretty` to stop at the
# end of a feature on a failure
After do |test_case|
  binding.pry if ENV['DEBUG_CUCUMBER'] && test_case.failed?

Tool 7: Rerun the flaky feature multiple times

for run in {1..20}; do...

Parallel cucumber: How to pass in cucumber arguments

Here is an example with the --tags option. You need to wrap them inside --cucumber-options option of parallel_cucumber.

DISPLAY=:17 bundle exec parallel_cucumber --cucumber-options '--tags @solo' features

See more details in the docs.

Auto-destruct in 28 days

Geordi: dumple can now compress dumps

geordi brings dumple to create database dumps. In version 4.1.0 you can now use the --compress flag to gzip dumps with dumple.

e.g. in a capistrano task:

namespace :db do
  desc 'Do a dump of the DB on the remote machine using dumple'
  task :dump do
    on primary :db do
      within current_path do
        execute :dumple, '--fail-gently', '--compress', fetch(:rails_env, 'production')

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

Useful Ruby Pathname method

If you have a Ruby Pathname, you can use the method :/ to append filepaths to it.

With this method, Ruby code can look like this:


Alternatively you can use the #join method, which feels less magic:

Rails.root.join('features', 'fixtures', 'picture.jpg')
This website uses short-lived cookies to improve usability.
Accept or learn more