# Ruby

> A Ruby application serving its own HTTP through Puma — Rails, Sinatra, Hanami

A Ruby application serving its own HTTP through Puma — Rails, Sinatra, Hanami
or any other Rack application. Like Node and Python it is the web server as
well as the application, and it replaces PHP-FPM and Nginx rather than joining
them. In front of it is the platform's proxy, which terminates TLS and routes
the hostname.

The image is the official Ruby image on Debian, slim, with a compiler, the
PostgreSQL, MySQL, SQLite, YAML and FFI headers, and libvips for Active
Storage's image variants — so `pg`, `mysql2`, `psych` and the rest of a Rails
bundle build. Choose the version with `runtime.ruby` in
[`vallic.yaml`](configuration.md):

```yaml
version: 1
type: ruby

runtime:
  ruby: '4.0'

build:
  steps:
    - name: Gems
      run: bundle install
  cache:
    - vendor/bundle

port: 3000
```

**The bundle travels in the release.** Bundler installs into `vendor/bundle`
in the checkout, held to `Gemfile.lock`, without the `development` and `test`
groups, and the release is that checkout moved. Declare `vendor/bundle` under
`cache` and the next build installs only what the lock changed; gems the lock
no longer names are removed as it does. A lock written by another Bundler than
the image's is honoured: that version is installed into the bundle and used.

**Lock for Linux.** A `Gemfile.lock` made on a Mac names the Mac's platform
only, and an install held to the lock refuses to add another. Add it once:

```sh
bundle lock --add-platform x86_64-linux
```

With no `start`, the image runs `bundle exec puma -p $PORT` in the release,
which reads `config/puma.rb` where there is one. Puma listens on `PORT` —
`3000` unless `port` says otherwise — on every address. `WEB_CONCURRENCY`
(worker processes, one by default), `RAILS_MAX_THREADS` and `RAILS_LOG_LEVEL`
can be set on the service (see [Service settings](service-settings.md)).
`RAILS_ENV` and `RACK_ENV` are `production`, and Rails logs to the container's
output, which is where the platform reads it.

The image's `bundle`, `gem` and `rake` come before the release's `bin/` on
`PATH`, so the `bin/bundle` older Rails applications generated is never the one
run. The image's Ruby is the one used, whatever `.ruby-version` asks for: the
version is `runtime.ruby`.

The release is read-only. `storage/`, `log/` and `tmp/` are linked out of it to
directories that outlive every release (`VALLIC_PUBLIC_DIR` is `storage/`,
`VALLIC_PRIVATE_DIR` is `private/`), so Active Storage's uploads, a file cache
and SQLite's databases are kept. See [Rails](framework-rails.md) for the rest
of a Rails application.

## Versions

| Version | Status |
| --- | --- |
| `4.0` | Supported, and the default |
| `3.4` | Supported |

Pin the version, not the build: name `4.0` and the platform matches it to the
current build, so a security rebuild reaches you without anybody editing a
repository.

## What you can change

In [`vallic.yaml`](configuration.md) — what each one does is on [Service settings](service-settings.md):

```yaml
services:
  - ruby:
      version: '4.0'
      environment:
        WEB_CONCURRENCY: …
        RAILS_MAX_THREADS: …
        RAILS_LOG_LEVEL: …
```

Anything not on this list refuses the deploy, naming the variable — rather
than being accepted and quietly ignored.
