Setup Sidekiq and Redis

If you want Sidekiq to be able to talk to Redis on staging and production servers, you need to add the following to your configuration:

# config/initializers/sidekiq.rb
require 'sidekiq'

Sidekiq.configure_client do |config|
  config.redis = { url: REDIS_URL }
end

Sidekiq.configure_server do |config|
  config.redis = { url: REDIS_URL }
end

The following step may be skipped for new Sidekiq 6+, since it isn't recommended anymore to use a global redis client.

# config/initializers/redis.rb
require 'redis'
require_relativ...

Geordi 6.0.0 released

6.0.0 2021-06-02

Compatible changes

  • geordi commit will continue even if one of the given projects is inaccessible. It will only fail if no stories could be found at all.

Breaking changes

Aruba: Stubbing binaries

When testing your command line application with Aruba, you might need to stub out other binaries you don't want to be invoked by your test.

Aruba Doubles is a library that was built for this purpose. It is not actively maintained, but works with the little fix below.

Installation

Install the gem as instructed by its README, then put this Before block somewhere into features/support:

Before do
  Arub...

Capistrano 3: Running a command on all servers

This Capistrano task runs a command on all servers.

bundle exec cap production app:run cmd='zgrep -P "..." RAILS_ROOT/log/production.log'

Code

# lib/capistrano/tasks/app.rake

namespace :app do

  # Use e.g. to grep logs on all servers:
  #   b cap production app:run_cmd cmd='zgrep -P "..." RAILS_ROOT/log/production.log' 
  #
  # * Use RAILS_ROOT as a placeholder for the remote Rails root directory.
  # * Append ` || test $? =1;` to grep calls in order to avoid exit code 1 (= "nothing found")
  # * To be able to process ...

Mailcatcher: An alternative to inaction_mailer

Looks simpler than inaction_mailer:

gem install mailcatcher
mailcatcher

Setup Rails to send mails to 127.0.0.1:1025. Usually you want the following config in config/environments/development.rb and maybe in test.rb or cucumber.rb.

config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  :address => 'localhost',
  :port => 1025
}

Now you can see sent mails in your browser when opening http://127.0.0.1:1080

Note: In order to s...

Configuring Webpacker deployments with Capistrano

When deploying a Rails application that is using Webpacker and Capistrano, there are a few configuration tweaks that optimize the experience.

Using capistrano-rails

capistrano-rails is a Gem that adds Rails specifics to Capistrano, i.e. support for Bundler, assets, and migrations. While it is designed for Asset Pipeline (Sprockets) assets, it can easily be configured for Webpacker. This brings these features to the Webpacker world:

  • Automatic removal of expired assets
  • Manifest backups

Geordi 1.3 released

Changes:

  • Geordi is now (partially) tested with Cucumber. Yay!
  • geordi cucumber supports a new @solo tag. Scenarios tagged with @solo will be excluded from parallel runs, and run sequentially in a second run
  • Support for Capistrano 2 AND 3 (will deploy without :migrations on Capistrano 3)
  • Now requires a .firefox-version file to set up a test firefox. By default now uses the system Firefox/a test Chrome/whatever and doesn't print warnings any more.
  • geordi deploy --no-migrations (aliased -M): Deploy with `cap ...

Debug Ruby code

This is an awesome gadget in your toolbox, even if your test coverage is great.

  • gem install ruby-debug (Ruby 1.8) or gem install debugger (Ruby 1.9)
  • Start your server with script/server --debugger
  • Set a breakpoint by invoking debugger anywhere in your code
  • Open your application in the browser and run the code path that crosses the breakpoint
  • Once you reach the breakpoint, the page loading will seem to "hang".
  • Switch to the shell you started the server with. That shell will be running an irb session where you can step thr...

Interacting with a Microsoft Exchange server from Ruby

Microsoft Exchange service administrators can enable Exchange Web Services (EWS) which is a rather accessible XML API for interacting with Exchange. This allows you to read and send e-mails, create appointments, invite meeting attendees, track responses, manage to-do tasks, check user availability and all other sorts of things that are usually only accessible from Outlook.

You can implement an EWS by hand-rolling your XML (the [docs](http://msdn.microsoft.com/en-us/...

Protip: Clone large projects multiple times

Large projects usually have large test suites that can run for a long time.
This can be annoying as running tests blocks you from picking up the next story -- but it doesn't have to be that way!

Simply clone your project's repo twice (or even more often).

When your work on a feature branch is done, simply push that branch and check it out on your 2nd copy to run tests there.
You can pick up a new story and work on that on your "main" project directory.

If you do it right, you will even be able to run tests in both your 2nd copy and your m...

Using before(:context) / before(:all) in RSpec will cause you lots of trouble unless you know what you are doing

TL;DR Avoid before(:context) (formerly before(:all)), use before(:example) (formerly before(:each)) instead.

If you do use before(:context), you need to know what you are doing and take care of any cleanup yourself.

Why?

Understand this:

  • before(:context) is run when the context/describe block begins,
  • before(:context) is run outside of transactions, so data created here will bleed into other specs
  • before(:example) is run before each spec inside it,

Generally, you'll want a clean setup for each s...

Five years of "Today I Learned" from Josh Branchaud

The linked GitHub repository is a bit like our "dev" cards deck, but groomed from a single person (Josh Branchaud). It includes an extensive list of over 900 TILs on many topics that might be interesting for most of us. (e.g. Ruby, Rails, Git, Unix..)

Ruby

Here is an excerpt of all the Ruby TILs that were new to me. I encourage you to take your time to skim over the original list as well!

Mysql::Error: SAVEPOINT active_record_1 does not exist: ROLLBACK TO SAVEPOINT active_record_1 (ActiveRecord::StatementInvalid)

Possible Reason 1: parallel_tests - running more processes than features

If you run old versions of parallel_tests with more processes than you have Cucumber features, you will get errors like this in unexpected places:

This is a bug caused by multiple processes running the same features on the same database.

The bug is fixed in versions 0.6.18+.

Possib...

Case Study: Analyzing Web Font Performance

Table of contents of the linked article:

What are Web Fonts?

  • Advantages of Web Fonts
  • Disadvantages of Web Fonts
    • Fallback Fonts
    • CSS3 @font Declaration Example
    • Fallback Font Example
    • Render Blocking and Critical Rendering Path
    • FOIT

Optimizing Web Font Delivery Further

  • Prioritize Based On Browser Support
  • Choose Only Styles You Need
  • Character Sets
  • Host Fonts Locally or Prefetch
  • Store in LocalStorage with Base64 Encoding
  • Another Method

Web Font Pe...

Geordi 1.0 released

Geordi 1.0 features a command line application geordi, that holds most of Geordi's previous commands.

New features

  • command help and usage examples right within geordi (geordi help and geordi help <command>)

  • quick command access: type just the first few letters of a command, e.g. geordi rs or geordi dev[server]

  • command dependencies, e.g. geordi rspec invokes geordi bundle-install (which bundles only if needed)

  • no cluttered /usr/bin, but all commands in one handy tool

  • template for easily adding new...

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

Jasmine: Testing AJAX calls that manipulate the DOM

Here is a Javascript function reloadUsers() that fetches a HTML snippet from the server using AJAX and replaces the current .users container in the DOM:

window.reloadUsers = ->
  $.get('/users').then (html) ->
    $('.users').html(html)

Testing this simple function poses a number of challenges:

  • It only works if there is a <div class="users">...</div> container in the current DOM. Obviously the Jasmine spec runner has no such container.
  • The code requests /users and we want to prevent network interaction in our uni...

Always store your Paperclip attachments in a separate folder per environment

tl;dr: Always have your attachment path start with :rails_root/storage/#{Rails.env}#{ENV['RAILS_TEST_NUMBER']}/.


The directory where you save your Paperclip attachments should not look like this:

storage/photos/1/...
storage/photos/2/...
storage/photos/3/...
storage/attachments/1/...
storage/attachments/2/...

The problem with this is that multiple environments (at least development and test) will share the same directory structure. This will cause you pain eventually. Files will get overwritten and...

Using Spring and parallel_tests in your Rails application

You want Spring for super-fast binstubs like bin/rails or bin/rspec which avoid Rails boot time.
You want parallel_tests to speed up full test runs of large test suites.

Unfortunately, you do not want parallel_tests to use your Spring binstubs as those parallelized tests will share data and/or loose some information. There are some issues about this on GitHub and there is a suggested [workaround](https:...

Good real world example for form models / presenters in Rails

We have often felt the pain where our models need to serve too many masters. E.g. we are adding a lot of logic and callbacks for a particular form screen, but then the model becomes a pain in tests, where all those callbacks just get in the way. Or we have different forms for the same model but they need to behave very differently (e.g. admin user form vs. public sign up form).

There are many approaches that promise help. They have many names: DCI, presenters, exhibits, form models, view models, etc.

Unfortunately most of these approaches ...

Ruby: Comparing a string or regex with another string

In Rubocop you might notice the cop Style/CaseEquality for e.g. this example:

def foo(expected, actual)
  expected === actual
end

In case expected is a Regex, it suggests to change it to the following pattern:

def foo(expected, actual)
  expected.match?(actual)
end

In case expected is a Regex or a String, you need to keep ===. Otherwise the actual expression is always converted to a regular expression.

# For expected === actual
foo('Test(s)', 'Test(s)') #=> true

# For expected.match?(actual)
foo('Test(...

Rspec 3: what to do when `describe` is undefined

When tests might not run with skipping RSpec in the RSpec.describe failing with the error undefined method 'describe' for main:Object this card will help you out!

In RSpec 3 the DSL like describe is exposed globally by default. Therefore it is not necessary to write Rspec.describe.

However, there is a config option to disable this beavior, which also disables the old should-syntax:

RSpec.configure do |config|
  config.disable_monkey_patching!...

Ruby 1.9 or Ruby 2.0 do not allow using shortcut blocks for private methods

Consider this class:

class Foo

  private
  
  def test
    puts "Hello"
  end
  
end

While you can say create a block to call that method (using ampersand and colon) on Ruby 1.8, ...

1.8.7 > Foo.new.tap(&:test)
Hello
=> #<Foo:0x1e253c8> 

... you cannot do that on Ruby 1.9 or 2.0:

1.9.3 > Foo.new.tap(&:test)
NoMethodError: private method `test' called for #<Foo:0x00000001e8c258>

^
2.0.0 > Foo.new.tap(&:test)
NoMethodError: private method `test' called for #<Foo:0x000000027bc738...

esbuild: Make your Rails application show build errors

Building application assets with esbuild is the new way to do it, and it's great, especially in combination with Sprockets (or Propshaft on Rails 7).
You might be missing some convenience features, though.

Here we cover one specific issue:
Once you have started your development Rails server and esbuild with the --watch option (if you used jsbundling-rails to set up, you probably use bin/dev), esbuild will recompile your assets upon change, but build errors will only be printed to the terminal. Your application won't complain about them ...