How to start CI build faster by loading Ruby gems from cache on Github Actions? You can start running your tests for a Ruby on Rails project quicker if you manage to set up all dependencies in a short amount of time. Caching can be helpful with that. Ruby gems needed for your project can be cached by Github Actions and thanks to that they can be loaded much faster when you run a new CI build.

Buildkite, CI, RSpec, testing, Ruby

You will learn how to configure Github Actions using:

  • actions/cache - it’s a popular solution to cache Ruby gems.
  • ruby/setup-ruby - it’s a solution to install a specific Ruby version and cache Ruby gems with bundler. Two features in one action.

actions/cache - just cache dependencies

Actions/cache is a popular solution that can be used to save data into the cache and restore it during the next CI build. It’s often used for Ruby on Rails projects that also use actions/setup-ruby for managing the Ruby version on Github Actions.

Let’s look at the Github Actions caching config example using actions/cache.

# .github/workflows/main.yml
name: Main
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2

      - uses: actions/cache@v2
        with:
          path: vendor/bundle
          key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile.lock') }}
          restore-keys: |
            ${{ runner.os }}-gems-

      - name: Bundle install
        env:
          RAILS_ENV: test
        run: |
          bundle config path vendor/bundle
          bundle install --jobs 4 --retry 3
  • You need to specify a directory path that will be cached. It’s vendor/bundle in our case.
  • You also generate a unique cache key based on the OS version and Gemfile.lock file. When you change the operating system version or you install a new gem and Gemfile.lock changes then as a result the new key value will be generated.
  • You need to configure the bundler to install all your Ruby gems to the directory vendor/bundle.
  • You can use bundler options:
    • --jobs 4 - install gems using parallel workers. This allows faster gems installation.
    • --retry 3 - makes 3 attempts to connect to Rubygems if there is a network issue (for instance temporary downtime of Rubygems.org)

If you would like to see the full YAML config for the Github Actions and Rails project you can take a look at some of our articles:

ruby/setup-ruby - install Ruby and cache gems

In the previous section, we mentioned the actions/setup-ruby is often used with Ruby on Rails projects. The actions/setup-ruby has been deprecated so it’s recommended to use ruby/setup-ruby action nowadays. It already has caching feature that you could use. Let’s see how.

# .github/workflows/main.yml
name: Main
on: [push, pull_request]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - uses: ruby/setup-ruby@v1
      with:
        # Not needed with a .ruby-version file
        ruby-version: 2.7
        # runs 'bundle install' and caches installed gems automatically
        bundler-cache: true

    # run RSpec tests
    - run: bundle exec rspec

As you can see using ruby/setup-ruby for managing the Ruby version and gems caching is much simpler. You just add an option bundler-cache: true and that’s it.

You can read in ruby/setup-ruby documentation:

“It is also possible to cache gems manually, but this is not recommended because it is verbose and very difficult to do correctly. There are many concerns which means using actions/cache is never enough for caching gems (e.g., incomplete cache key, cleaning old gems when restoring from another key, correctly hashing the lockfile if not checked in, OS versions, ABI compatibility for ruby-head, etc). So, please use bundler-cache: true instead…”

Summary

You saw 2 ways of caching Ruby gems on Github Actions. There are also other ways to make your CI build faster like running tests in parallel. You can learn more about test parallelisation here or simply check the Knapsack Pro homepage.