Allow Ruby version to be specified per app

Hi,

I’m working with a monorepo where two or more apps (all hosted on Render) sometimes have to use different versions of Ruby.

Unfortunately, Render guesses the Ruby version based on a .ruby-version file that we have to put in the root of our monorepo, but this means that I can’t use a different version of Ruby. I’ve tried setting variables like DEFAULT_RUBY_VERSION etc but these don’t work.

Is there a way to achieve what I’m trying? Do I have to do something like Specify NPM version? - #3 by sonny ?

Ideally, we’d have RUBY_VERSION supported like NODE_VERSION is here Specifying a Node Version | Render

Edit: I’ve just requested a feature here Specify Ruby version | Feature Requests | Render

Thanks!

1 Like

Hi @parndt, thank you for submitting that feature request, that is a great suggestion!

One possible workaround I can think of is to have multiple Gemfiles in the root of your project with different Ruby versions and respective names i.e. Gemfile-2.2.4, Gemfile-2.2.5 etc.

Then, create multiple build scripts i.e. bin/build-1.sh, bin/build-2.sh. In those scripts you can then specify which Gemfile to use with Bundler’s --gemfile flag

So bin/build-1.sh might look like this:

#!/usr/bin/env bash
# exit on error
set -o errexit

bundle install --gemfile="Gemfile-2.2.4"
bundle exec rake assets:precompile
bundle exec rake assets:clean
bundle exec rake db:migrate

Then in the settings for your Render app you would specify which build script to use for each respective app. Keep in mind I haven’t tried this myself but it might be a temporary solution!

1 Like

Hi Tyler,

Unfortunately not, what we see instead is:

Aug 12 08:54:38 AM  ==> Downloading cache...
Aug 12 08:54:48 AM  ==> Downloaded 121MB in 4s. Extraction took 4s.
Aug 12 08:54:56 AM  Updating rubygems-update
Aug 12 08:54:56 AM  Successfully installed rubygems-update-3.2.25
Aug 12 08:54:56 AM  Installing RubyGems 3.2.25
Aug 12 08:54:56 AM  ERROR:  While executing gem ... (Errno::EROFS)
Aug 12 08:54:56 AM      Read-only file system @ dir_s_mkdir - /usr/local/lib/ruby/site_ruby/2.6.0/rubygems
Aug 12 08:54:57 AM  ==> Running build command 'bundle install --gemfile="Gemfile-web"'...
Aug 12 08:54:57 AM  Your Ruby version is 2.6.5, but your Gemfile specified 3.0.2
Aug 12 08:54:57 AM  ==> Build failed 😞

Thanks,
Phil

1 Like

Hmm, do you still have the .ruby-version file? If you do, can you try removing that so it will force our code to look in the Gemfile for the version?

1 Like

Nope, unfortunately not:

Aug 12 10:54:24 AM  ==> Downloading cache...
Aug 12 10:54:28 AM  ==> Downloaded 33MB in 2s. Extraction took 1s.
Aug 12 10:54:31 AM  ==> Running build command './bin/build-web.sh'...
Aug 12 10:54:31 AM  Your Ruby version is 2.6.5, but your Gemfile specified 3.0.2
Aug 12 10:54:31 AM  ==> Build failed 😞

If I had to hazard a guess, I’d say it comes from this part of your build scripts:

DEFAULT_RUBY_VERSION=2.6.5

and further on:

local detected_version='';
 local rv="${RENDER_SRC_ROOT:-.}/.ruby-version";
 if [[ -f $rv ]]; then
 detected_version=$(head -1 "$rv");
 fi;
 local gemfile="${RENDER_SRC_ROOT:-.}/Gemfile";
 if [[ -z $detected_version && -f $gemfile ]]; then
 detected_version=$(version_from_gemfile "$gemfile");
 fi;
 if [[ -z $detected_version ]]; then
 detected_version=$DEFAULT_RUBY_VERSION;
 fi;

It first looks for a .ruby-version and then it looks for a file called exactly Gemfile. Here would be a great place to first look for a $RUBY_VERSION, right above trying the .ruby-version file:

local rv="${RENDER_SRC_ROOT:-.}/.ruby-version";

The first thing I tried was overriding DEFAULT_RUBY_VERSION with an environment variable with value of 3.0.2, as well as setting RUBY_VERSION to 3.0.2 and RUBY_MAJOR to 3.0 but it doesn’t seem to respect it, or maybe by then it is too late? My investigation stopped here because I can’t override RENDER_PRE_BUILD_CMD :innocent: and I think that it’s all happening before I can do anything about it.

I’m currently trying another approach where I take more control in the build and start scripts, and I’ll report back.

Of course it would be a lot easier to be able to set RUBY_VERSION and have that override all of the auto-detection.

Hope that helps!

1 Like

I got it working.

I created a build.sh and a start.sh for this sub-project called web in the monorepo:

build.sh:

#!/usr/bin/env bash
# exit on error
set -o errexit

export RUBY_VERSION=$(cat $RENDER_SRC_ROOT/web/.ruby-version)
export BUNDLE_GEMFILE=$RENDER_SRC_ROOT/web/Gemfile
set_ruby_env $(fetch_or_build "$RUBY_VERSION")
gem install bundler
gem update --system
bundle install

start.sh

#!/usr/bin/env bash
# exit on error
set -o errexit

export RUBY_VERSION=$(cat $RENDER_SRC_ROOT/web/.ruby-version)
export BUNDLE_GEMFILE=$RENDER_SRC_ROOT/web/Gemfile
source /home/render/ruby-env.sh
set_ruby_env "$RUBIES_ROOT/ruby-$RUBY_VERSION"

cd $RENDER_SRC_ROOT/web
bundle exec puma -C ./config/puma.rb

At least it works now, even if it is just a workaround.

Phil

1 Like

I have this same problem, did you execute the build.sh file under the build settings of the project settings tab?

1 Like

Where can you find the source code for the build script so that I can debug how to set the ruby version?

I put parndt’s build script into the build settings and saw it install ruby 3.1.0 perfectly fine, but then it still tried to use ruby 2.6 (which I think is EOL?)

I did get it to work with this build setting:

cd api &&
export RUBY_VERSION=3.1.0 && 
export BUNDLE_GEMFILE=$RENDER_SRC_ROOT/api/Gemfile &&
set_ruby_env $(fetch_or_build "3.1.0") &&
/opt/render/project/rubies/ruby-3.1.0/bin/gem update --system &&
/opt/render/project/rubies/ruby-3.1.0/bin/bundle config set --local deployment 'true'
/opt/render/project/rubies/ruby-3.1.0/bin/bundle install &&
bin/rails assets:precompile &&
bin/rails assets:clean

and a start command of:

cd api && /opt/render/project/rubies/ruby-3.1.0/bin/bundle exec rails server -p $PORT -e $RAILS_ENV

Yeah, I have it configured like this (for the project in the web directory):

I currently have three scripts, bin/render/env.sh, bin/render/build.sh, and bin/render/start.sh.
Here they are:

bin/render/env.sh:

#!/usr/bin/env bash

export RUBY_VERSION=$(cat $RENDER_SRC_ROOT/web/.ruby-version)
export BUNDLE_GEMFILE=$RENDER_SRC_ROOT/web/Gemfile
source /home/render/ruby-env.sh
set_ruby_env "$RUBIES_ROOT/ruby-$RUBY_VERSION"

bin/render/build.sh:

#!/usr/bin/env bash

# exit on error
set -o errexit

# Use the correct version of Ruby
source $RENDER_SRC_ROOT/web/bin/render/env.sh

gem install bundler --silent
gem update --system --silent --no-document
bundle install

npm install --prefix $RENDER_SRC_ROOT/web
npm run build --prefix $RENDER_SRC_ROOT/web

bin/render/start.sh:

#!/usr/bin/env bash

# exit on error
set -o errexit

# Use the correct version of Ruby
source $RENDER_SRC_ROOT/web/bin/render/env.sh

cd $RENDER_SRC_ROOT/web

bin/puma

bin/puma is just the binstub that is generated with bundle binstubs puma.

Hope that helps you and anyone else.

I’ve been trying to get my deploys working using this method but I keep getting them canceled with exit status 1.

Upon further work it seems that none of my deploys work at all. Logs are not even present. I even set up a log stream, no logs. Very strange.

Sure! If you’re dealing with multiple apps in a monorepo on Render and need different Ruby versions, it can be tricky because Render picks up the Ruby version from a single .ruby-version file in the root of your repo. Here are some ways to handle it:

  1. Use Docker: Create Dockerfiles for each app with the desired Ruby version specified. Render supports deploying Docker containers, giving you control over the environment.
  2. Environment Variables/Configuration: Set up each app to read the required Ruby version from environment variables or configuration files. Adjust the app’s behavior based on this information.
  3. Feature Request: Request Render to add native support for specifying Ruby versions, similar to how they support Node.js versions.
    https://community.render.com/t/specify-npm-version/944/ruby on rails

I hope this will help you.