How to cache Ruby (GEM) dependencies

Setup & technical notes

Ruby GEMs are installed into a single directory by default. You can get the location of this directory with gem environment gemdir. If you want to change this directory you can set the $GEM_HOME environment variable, this will be picked up by gem install and it’ll install the GEMs to the location specified by $GEM_HOME.

Now that you know where the Ruby GEMs are stored you can easily cache the directory. As in any other #build-cache setup you need two steps:

  1. put the Cache:Pull step after the Git Clone step
  2. put the Cache:Push step to the very end of the Workflow
  3. You can now just select the Cache:Push step and add the Ruby GEM home directory to the Cache paths input.

Important: You can’t just add gem environment gemdir to the input as you can only reference Environment Variables in the inputs directly, and $GEM_HOME is not set by default on the Bitrise.io VMs.

There are two simple solutions for this issue:

  • Set GEM_HOME as an App Env Var to, let’s say, $HOME/.gem.
  • Add a Script step to your workflow and set the $GEM_HOME environment variable there

The second option is usually more error proof as you don’t change the location of gem home,
you just set the environment variable to the path where it’s located.

Example workflow

example:
  steps:
  - script:
      title: Set GEM_HOME env var
      inputs:
      - content: |-
          #!/bin/bash
          set -ev
          envman add --key GEM_HOME --value "$(gem environment gemdir)"
  - git-clone: {}
  - cache-pull: {}

  # ... Add your steps here.
  # You can `gem install` Ruby gems with Script steps here too,
  # just make sure it's between the `cache-pull` and `cache-push` steps.

  - cache-push:
      inputs:
      - cache_paths: |-
          $GEM_HOME

For more information about the Bitrise Build Cache see the DevCenter.

1 Like

Hi, sorry for comment in this old post, but i did exactly what’s in the “How To” and my cache still does not working with Gems, both Push and Pull steps works fine but when I try to run any command that uses one of my Gems it does not work, i’m get the error “no such file or directory”, can you help me to understand why this? Without cache works fine all Gems commands.

Hy there,

Could you send us a build’s url with this issue?
is the pod install still in the build?
how did you configure the cache push step? :thinking:

1 Like

Hi @fehersanyi-bitrise,
This is the build’s url: Bitrise - Mobile Continuous Integration and Delivery - iOS & Android Build Automation
My Bitrise workflow with cache:
danger_tests:

    steps:
    - script:
        inputs:
        - content: |-
            #!/bin/bash
            set -ev
            envman add --key GEM_HOME --value "$(gem environment gemdir)"
        title: Create GEM_HOME
    - activate-ssh-key@4.0.3:
        run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
    - git-clone: {}
    - cache-pull@2.0.1:
        inputs:
        - is_debug_mode: 'true'
    - certificate-and-profile-installer@1.10.1: {}
    - script@1.1.5:
        inputs:
        - content: |-
            #!/bin/bash --login -eo pipefail
            gem environment gemdir
            bundle install
        title: Install bundled gems
    - fastlane:
        inputs:
        - lane: "$FASTLANE_LANE"
        - update_fastlane: 'false'
        - work_dir: "$FASTLANE_WORK_DIR"
    - script@1.1.5:
        inputs:
        - content: |-
            #!/usr/bin/env bash
            bundle exec danger --verbose
        title: Run Danger
    - cache-push@2.0.5:
        inputs:
        - is_debug_mode: 'true'
        - cache_paths: "$GEM_HOME -> ./Gemfile.lock"
1 Like

I think the problem is that this

- cache-push@2.0.5:
        inputs:
        - is_debug_mode: 'true'
        - cache_paths: "$GEM_HOME -> ./Gemfile.lock"

lsat line in reality looks like this
- cache_paths: "gem environment gemdir -> ./Gemfile.lock"
so the path is not good :thinking:

So I think you should check with a script step first, what is this file where the gems are placed first and add that to the env var at the begining.

1 Like

Ok, I understand, I’ll try now set path manually and see if this work, thanks in advice.
Question: why when I download the site cache does it come with all folders correctly?

Hello again @fehersanyi-bitrise
Can you check this build please? https://app.bitrise.io/build/f18431af8a895027
I set the path manually on my Env Vars, and put one script step to validate folder.
In the log it appears to me with all folders with my gems, but when I execute any command of any gem, I receive that error.
Thanks in advance for help!

could you try using the cocoapod install step instead of the script? :thinking:
and please include your gemfile.lock in the repository :upside_down_face: