Deploying Your Rails 6 App
Tags: rails, ruby, devops, tutorial
Published: 2020-07-24 18:21:57


This article was originally published at: https://render.com/docs/deploy-rails. It's recommended to read the linked version with improved syntax highlighting.

This guide will demonstrate how you can set up a local [Ruby on Rails 6](https://rubyonrails.org/) environment, create a simple view, and deploy it to Render. The application will be configured to use a Render PostgreSQL [database](https://render.com/docs/databases).

The repository used for this demo can be found [here](https://github.com/render-examples/rails6) and the sample app can be viewed [here](https://rails.onrender.com).

## Create a Ruby on Rails Project

In this step, we will set up a local development environment with a basic project structure.

<warning-block>We will be calling this example project `myrailssite`. You can replace this with a name of your choosing.</warning-block>

### Install Rails

To install Ruby on Rails on your machine, use the `gem install` command. Be sure you have the [required dependencies](https://guides.rubyonrails.org/getting_started.html#creating-a-new-rails-project-installing-rails) installed (Ruby, Node.js and Yarn 1.x).
We are using Rails 6 in this tutorial, so verify that you have the correct version installed:

```shell{1}
$ gem install rails
$ rails --version
Rails 6.0.3.2
```

### Create a New Project

1. In your terminal, navigate to the directory where you will be creating your project. Then, run the following commands to generate a new project:

     ```shell
     $ rails new myrailssite --database=postgresql
     ```

     <info-block>You can make use of arguments to customize the generated project. Enter `rails new -h` for further details.</info-block>

2. Create a local database for your application:

     ```shell{1}
     $ rails db:create
     Created database 'myrailssite_development'
     Created database 'myrailssite_test'
     ```

<br>
This should create a fully functional basis for you new Rails application! To verify, you can start the development server:

```shell
$ rails server
```

To see your application in action, open a browser window and navigate to http://localhost:3000. You should see the Rails default information page:

![Rails Successful Installation](https://render.com/static/3740a4bd446dae336ba55ee4bc71b390/b2aca/welcome.webp)

## Create the Hello World Landing Page

In this section, you will create a simple Rails application with a static view using Ruby on Rails. If you plan to deploy your sample Rails project on Render, skip to [Update Your App For Render](#update-your-app-for-render) and deploy an empty project.

<info-block>Checkout the official  [Getting Started with Rails](https://guides.rubyonrails.org/getting_started.html) guide for further reading on how to create Rails applications.</info-block>

### Create Your First Page

1. In order to create a new Rails controller, you need to run the _controller generator_. Set the controller's name to `Render` and set up an action named `index` using the following command:

     ```shell
     $ rails g controller Render index
     ```

    The generator will create several files in your project:

     ```
     create  app/controllers/render_controller.rb
      route  get 'render/index'
     invoke  erb
     create    app/views/render
     create    app/views/render/index.html.erb
     invoke  test_unit
     create    test/controllers/render_controller_test.rb
     invoke  helper
     create    app/helpers/render_helper.rb
     invoke    test_unit
     invoke  assets
     invoke    scss
     create      app/assets/stylesheets/render.scss
     ```

2\. Open the `config/routes.rb` file and add the following line:

```
Rails.application.routes.draw do
 get 'render/index'

 # For more details on this file's DSL, see https://guides.rubyonrails.org/routing.html
 root 'render#index'
```

   This file will tell Rails that you want your `render/index` action to be accessible from the root URL of your application.

3\. Open the `app/views/render/index.html.erb` file and replace its contents with:

```
<main class="container">
  <div class="row text-center justify-content-center">
    <div class="col">
      <h1 class="display-4">Hello World!</h1>
    </div>
  </div>
</main>
```

### Add Third-Party CSS

In this step you will integrate [Bootstrap](https://getbootstrap.com/) into your application for easy styling.

1. In order to install Bootstrap, run the following command in your terminal:

     ```shell
     $ yarn add bootstrap
     ```

2. Rename your `app/assets/stylesheets/application.css` to `app/assets/stylesheets/application.scss`:

     ```shell
     $ mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss
     ```

3. Open `app/assets/stylesheets/application.scss` and replace its contents with:

     ```scss{8-11}
     /*
      * This is a manifest file that'll be compiled into application.css, which will include all the files
      * listed below.
      *
      * Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
      * vendor/assets/stylesheets directory can be referenced here using a relative path.
      */

     @import "bootstrap/scss/bootstrap";

     @import "**/*";
     ```

     
So far, we imported Bootstrap into our CSS pack. This means Bootstrap will now be a part of the stylesheets served with our application.

Then, we replaced the existing `require_*` Rails directives with a plain SASS [`@import` rule](https://sass-lang.com/documentation/at-rules/import).

Both methods import all stylesheets from the `app/assets/styleshets` directory and its subdirectories. However, the use of the `@import` rule allows the imported stylesheets to access the SASS variables defined by Bootstrap.
     
4\. Open `app/views/layouts/application.html.erb` and add the following modifications to the heading:

```
<!DOCTYPE html>
<html lang="<%= I18n.locale %>">
  <head>
   <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <title>Hello Rails on Render!</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
  ...
</html>
```

### Add an Image Asset

1. In order to add an asset to your project, download this banner and save it as `app/assets/images/render.png`:

   ![render.png](https://render.com/images/render-banner.png)

2\. In your layout, in `app/views/layouts/application.html.erb`, reference the downloaded image:

   ```erb{3-7}
   ...
   <body>
      <header class="container mt-4 mb-4">
        <a href="https://render.com">
          <%= image_tag 'render.png', class: 'mw-100' %>
        </a>
      </header>
      <%= yield %>
   </body>
   </html>
   ```

You can now verify that your app is working using the following command:

```shell
$ rails server
```

![Rails Hello World](https://render.com/static/b5195e60f407c6baec116f98f60c27b0/d3e6f/hello-world.webp)

## Update Your App For Render

In order for your Rails project to be ready for production, you will need to make a few adjustments. If you haven't already, you will be required update your project to use a [Render PostgreSQL database](https://render.com/docs/databases)) instead of a SQLite database.

### Modify Existing Rails Project for PostgreSQL

<info-block>This is only required if the application was created without specifying `--database=postgresql`.</info-block>

1. In your `Gemfile` change the requirement for the existing database driver:

     from:

     ```ruby
     gem 'sqlite3'
     ```

     to:

     ```ruby
     gem 'pg'
     ```

2. Install your new dependencies using the following command. This will also update your `Gemfile.lock`:

     ```shell
     $ bundle install
     ```

3. Open `config/database.yml` and update it to use the `postgresql` database adapter.:

     ```yaml{18,32,35,40,44}
     # PostgreSQL. Versions 9.3 and up are supported.
     #
     # Install the pg driver:
     #   gem install pg
     # On macOS with Homebrew:
     #   gem install pg -- --with-pg-config=/usr/local/bin/pg_config
     # On macOS with MacPorts:
     #   gem install pg -- --with-pg-config=/opt/local/lib/postgresql84/bin/pg_config
     # On Windows:
     #   gem install pg
     #       Choose the win32 build.
     #       Install PostgreSQL and put its /bin directory on your path.
     #
     # Configure Using Gemfile
     # gem 'pg'
     #
     default: &default
       adapter: postgresql
       encoding: unicode
       # For details on connection pooling, see Rails configuration guide
       # https://guides.rubyonrails.org/configuring.html#database-pooling
       pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>

     development:
       <<: *default
       database: myrailssite_development

       # The specified database role being used to connect to postgres.
       # To create additional roles in postgres see `$ createuser --help`.
       # When left blank, postgres will use the default role. This is
       # the same name as the operating system user that initialized the database.
       #username: myrailssite

       # The password associated with the postgres role (username).
       #password:

       # Connect on a TCP socket. Omitted by default since the client uses a
       # domain socket that doesn't need configuration. Windows does not have
       # domain sockets, so uncomment these lines.
       #host: localhost

       # The TCP port the server listens on. Defaults to 5432.
       # If your server runs on a different port number, change accordingly.
       #port: 5432

       # Schema search path. The server defaults to $user,public
       #schema_search_path: myapp,sharedapp,public

       # Minimum log levels, in increasing order:
       #   debug5, debug4, debug3, debug2, debug1,
       #   log, notice, warning, error, fatal, and panic
       # Defaults to warning.
       #min_messages: notice

     # Warning: The database defined as "test" will be erased and
     # re-generated from your development database when you run "rake".
     # Do not set this db to the same as development or production.
     test:
       <<: *default
       database: myrailssite_test

     # As with config/credentials.yml, you never want to store sensitive information,
     # like your database password, in your source code. If your source code is
     # ever seen by anyone, they now have access to your database.
     #
     # Instead, provide the password as a unix environment variable when you boot
     # the app. Read https://guides.rubyonrails.org/configuring.html#configuring-a-database
     # for a full rundown on how to provide these environment variables in a
     # production deployment.
     #
     # On Heroku and other platform providers, you may have a full connection URL
     # available as an environment variable. For example:
     #
     #   DATABASE_URL="postgres://myuser:mypass@localhost/somedatabase"
     #
     # You can use this database configuration with:
     #
     #   production:
     #     url: <%= ENV['DATABASE_URL'] %>
     #
     production:
       <<: *default
       database: myrailssite_production
       username: myrailssite
       password: <%= ENV['MYRAILSSITE_DATABASE_PASSWORD'] %>
     ```

### Go Production-Ready

Before deploying any serious application in production, some minor tweaks are required.

1. Open `config/database.yml` and find the `production` section. Modify it to gather the database configuration from the `DATABASE_URL` environment variable:

   ```yml
   production:
      <<: *default
      url: <%= ENV['DATABASE_URL'] %>
   ```

2\. Open `config/puma.rb` and uncomment and add the highlighted lines:

     
     # Puma can serve each request in a thread from an internal thread pool.
     # The `threads` method setting takes two numbers: a minimum and maximum.
     # Any libraries that use thread pools should be configured to match
     # the maximum value specified for Puma. Default is set to 5 threads for minimum
     # and maximum; this matches the default thread size of Active Record.
     #
     max_threads_count = ENV.fetch("RAILS_MAX_THREADS") { 5 }
     min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count }
     threads min_threads_count, max_threads_count

     # Specifies the `port` that Puma will listen on to receive requests; default is 3000.
     #
     port        ENV.fetch("PORT") { 3000 }

     # Specifies the `environment` that Puma will run in.
     #
     environment ENV.fetch("RAILS_ENV") { "development" }

     # Specifies the `pidfile` that Puma will use.
     pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }

     # Specifies the number of `workers` to boot in clustered mode.
     # Workers are forked web server processes. If using threads and workers together
     # the concurrency of the application would be max `threads` * `workers`.
     # Workers do not work on JRuby or Windows (both of which do not support
     # processes).
     #
     workers ENV.fetch("WEB_CONCURRENCY") { 4 }

     # Use the `preload_app!` method when specifying a `workers` number.
     # This directive tells Puma to first boot the application and load code
     # before forking the application. This takes advantage of Copy On Write
     # process behavior so workers use less memory.
     #
     preload_app!

     # Allow puma to be restarted by `rails restart` command.
     plugin :tmp_restart
     

3\. Open `config/environments/production.rb` and enable the public file server when the `RENDER` environment variable is present (which [always is](https://render.com/docs/environment-variables) on Render):

     
     # Disable serving static files from the `/public` folder by default since
     # Apache or NGINX already handles this.
     config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present? || ENV['RENDER'].present?
     

### Create a Build Script

You will need to run a series of commands to build your app. This can be done using a build script. Create a script called `bin/render-build.sh` at the root of your repository:

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

bundle install
bundle exec rake assets:precompile
bundle exec rake assets:clean
bundle exec rake db:migrate
```

Make sure the script is executable before checking it into Git:

```bash
$ chmod a+x bin/render-build.sh
```

We will configure Render to call this script on every push to the Git repository.

Commit all changes and push them to your GitHub repository. Now your application is ready to be deployed on Render!

## Deploy to Render

There are two ways to deploy your application on Render, either by [declaring your services within your repository](https://render.com/docs/infrastructure-as-code) in a `render.yaml` file, or by manually setting up your services using the dashboard. In the following steps, we will walk you through both options.

### Use `render.yaml` to Deploy

1. Create a file named `render.yaml` at the root of your directory with the following content. The file will include information about your Rails **Web Service** and the [**Database**](https://render.com/docs/databases) that is used by your application. Don't forget to commit and push it to your remote repository.

   ```yaml
   databases:
      - name: myrailssite
        databaseName: myrailssite
        user: myrailssite

   services:
      - type: web
        name: myrailssite
        env: ruby
        buildCommand: "./bin/render-build.sh"
        startCommand: "bundle exec puma -C config/puma.rb"
        envVars:
          - key: DATABASE_URL
            fromDatabase:
              name: myrailssite
              property: connectionString
          - key: RAILS_MASTER_KEY
            sync: false
   ```

2\. On the Render Dashboard, go to the [YAML](https://dashboard.render.com/iacs) page and click the `New From YAML` button. Select your repository (after giving Render the permission to access it, if you haven't already).

3\. In the deploy window, set the value of the `RAILS_MASTER_KEY` to the contents of your `config/master.key` file. Then click `Approve`.

That's it! Your app will be live on your `.onrender.com` URL as soon as the build finishes.

### Deploy Manually

If you don't wish to deploy your Rails app through YAML deploys, you can follow these steps for a manual deploy.

1. Create a new [PostgreSQL database](https://render.com/docs/databases) on Render. Note your database **internal connection string**; you will need it later.

1. Create a new **Web Service**, pointing it to your application repository (make sure Render has a permission to access it).

1. Select `Ruby` for the environment and set the following properties:

| Property | Value |
| -------- | ----- |
| **Build Command** | `./bin/render-build.sh` |
| **Start Command** | `bundle exec puma -C config/puma.rb` |

4\. Add the following environment variables under the **Advanced** section:

| Key | Value |
| --- | ----- |
| `DATABASE_URL` | The **internal connection string** for the database you created above |
| `RAILS_MASTER_KEY` | Paste contents of the `config/master.key` file |

That's it! You can now finalize your service deployment. It will be live on your `.onrender.com` URL as soon as the build finishes.

## Additional Notes

By default, Render uses the latest LTS version of Ruby. You can also modify the version of Ruby used by specifying it in `.ruby-version` at the root of your project, or in your `Gemfile` like this:

```ruby
ruby '2.7.1'
```