© Brady Somerville, Adam Gamble, Cloves Carneiro Jr and Rida Al Barazi 2020
B. Somerville et al.Beginning Rails 6https://doi.org/10.1007/978-1-4842-5716-6_18

18. Deploying Your Rails Applications

Brady Somerville1 , Adam Gamble2, Cloves Carneiro Jr.3 and Rida Al Barazi4
(1)
Bowling Green, KY, USA
(2)
Gardendale, AL, USA
(3)
Hollywood, FL, USA
(4)
FONTHILL, ON, Canada
 

At some point, you may decide it’s time to share your Rails application with the world. Though Rails offers a first-class local development environment, it’s not feasible to host your public-facing web application from your development environment; besides potentially violating your residential Internet service’s terms of service, you’d have to deal with dynamic IP addresses, opening your firewall (and a host of potential security issues), and many more issues. Instead, when you’re ready to launch your application for public use, you’ll need to deploy your Rails application to a suitable hosting environment.

Options for hosting web applications have changed a lot over the years. Years ago, there were two main options—shared hosting or dedicated hosting. With shared hosting, you would be given limited access to a server used by other customers’ web applications as well. You would be able to upload files and perhaps configure some settings, but have limited (or no) access to the command line for advanced usage. Shared hosting was cheaper, but limited; it worked well for static HTML sites, or even web applications built in languages such as PHP which often just worked—as long as your application would work on the versions of the language (and other supporting services) that the shared hosting environment offered.

Dedicated hosting, on the other hand, gave application developers full control over their hosting environment; by leasing a physical server in a rack in some data center somewhere, you would then have (nearly) full control over the server. You could perform command-line actions as the root user, installing whatever software your hosting environment needed. While having full control sounds nice, it comes at a cost—in addition to the higher financial costs of dedicated hosting, the developers had to pay the higher maintenance costs of correctly configuring their system, keeping up-to-date with security patches, and more. These higher costs, though, were sometimes necessary to support web applications written in languages such as Java or which required supporting services not offered by shared hosting environments.

However, as virtualization technology improved, hosting providers began offering virtual private servers—a kind of hybrid of shared and dedicated hosting—which gave developers full control over a shared slice of a server. This brought the financial costs of dedicated hosting down, but didn’t address the higher maintenance costs of dedicated hosting.

Then, hosting providers began offering what became known as PAAS—Platform as a Service. Services like Heroku and AWS Elastic Beanstalk gave developers a way to deploy more sophisticated web applications without having to concern themselves with server configuration and maintenance, thus attempting to reduce both the financial and maintenance costs of using dedicated servers.

Why the long history lesson? It’s important to understand the variety of hosting services available and their strengths and weaknesses and to know which are appropriate for hosting your Rails application.

Rails applications are not suited for cheap, shared hosting plans as first described in this section. Why? For example, gems often need the ability to compile code during installation. Copying your compiled gems from your development environment to the hosting environment would most likely fail terribly. Also, with Rails applications, the web server (like Apache or Nginx) needs to be configured to communicate with the Rails server via a TCP port or socket—it can’t simply load the requested file from the directory, like PHP or Classic ASP. Most shared hosting plans simply don’t support this.

Rails applications would work great on "dedicated" hosting platforms—whether you’re leasing a physical server or paying for a virtualized server (like from the AWS EC2 service.) However, as mentioned before, you’re signing up for lots of server administration. While there is a vast amount of information available on the Internet to help you configure your hosting environment, not everyone has the interest or time to learn.

So that brings us to the PAAS option. For many developers, this is a great approach. While the financial cost of hosting on a PAAS may be slightly higher than hosting on a virtual server, the maintenance costs are much lower, allowing the application developer to focus on application development, rather than system administration.

In this chapter, we’ll illustrate deploying a Rails application to Heroku. There are many fine options, but Heroku is well known and respected for their ease of use and is a great way for us to get our blog application up for the whole world to see, with minimal effort.

Set Up an Account with Heroku

The first step in this process is to set up an account with Heroku. Don’t worry, Heroku offers a free account which doesn’t need a credit card. Point your browser to www.heroku.com, and you should see something like Figure 18-1.
../images/314622_4_En_18_Chapter/314622_4_En_18_Fig1_HTML.jpg
Figure 18-1

Setting up a Heroku account

Click the Sign Up link and enter an email address. Heroku will then send you an email with a confirmation link. Once you click that link, you’ll be asked for a password and password confirmation. You’re now the proud owner of a shiny new Heroku account. This will let you deploy Rails (and other) apps to your heart’s content.

Heroku has a piece of software that facilitates interacting with your Heroku apps on your computer. It’s called the Heroku Toolbelt (https://toolbelt.heroku.com/). Go to that URL and follow the instructions for installing the Heroku Toolbelt in your development environment. Once it’s been installed, you should be able to run the heroku command in your CLI and see usage information.

Preparing Your Git Repository

Now that we’ve set up a Heroku account and installed the command-line tools, we’ll need to make a couple of small changes to our app so we can deploy it. Heroku’s method of deployment is Git, a tool most developers are already using. If you are unfamiliar with Git, you can check out Appendix C to get up to speed.

Usually, we’d want to start using version control at the beginning of our project, for maximum benefit. Having a readily accessible history of all your code changes while you’re developing is incredibly useful. To keep this book’s focus on Rails, we waited until now (when we needed it) to introduce the idea.

Unless you have already set up a Git repository for our application, you’ll need to do so now. Go to the terminal, making sure you’re in the directory where our project is stored, and type the following command:
$ git init
Initialized empty Git repository in Initialized empty Git repository in /Users/brady/Sites/beginning-rails-6/.git/
This told Git that we want this directory to be a repository, meaning that Git will now keep track of the files you want it to. Let’s tell it to keep track of all the files in this directory and make an initial commit:
$ git add .
$ git commit –m 'Initial Commit'
master (root-commit) ea1c9dd] Initial Commit
 186 files changed, 11061 insertions(+)
 create mode 100644 .browserslistrc
 create mode 100644 .gitignore
...

Your output might be slightly different, but it should add all files to your Git repository. This means that Git is now keeping track of the files and will notice when you make changes. You can then either decide to commit those changes or get rid of them. Once you have committed changes, Git has built-in support for pushing those changes to a remote server. Likewise, it can pull the changes from a remote server to your local repository. This is why so many developers use a source control system like Git; it makes it so easy to collaborate. It also happens to be the way you deploy your application to Heroku.

Creating Your Heroku App

So let’s tell Heroku we are ready to create an app. The first step is to create the app on Heroku. You can do this on their web control panel, or you can do it from the command line. We prefer to use the command-line interface. You need to authenticate the Heroku Toolbelt you previously installed, but that’s a simple task. Once that is done, you can move straight into creating your application on Heroku:
$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/cli/browser/7921344c-4ce8-4fee-96c5-0938c1eb6f83
heroku: Waiting for login...

As prompted, press a key to open your browser to Heroku’s authentication page, and then click the "Log In" button. When successful, the web page will say you can close it, and the heroku login command will complete, showing "Logged in as" with your email address.

Now, we’re ready to create the Heroku instance for our application. We simply need to run the heroku create command from our terminal, while in our project’s directory:
$ heroku create
Creating app... done, ▯ evening-ocean-78121
https://evening-ocean-78121.herokuapp.com/ | https://git.heroku.com/evening-ocean-78121.git
Notice that it called the app evening-ocean-78121. If you don’t specify a name, Heroku will choose a random name for you. If you would like to specify a name, type it after the Heroku create line, like so:
$ heroku create beginning-rails-6-brady
Creating ▯ beginning-rails-6-brady... done
https://beginning-rails-6-brady.herokuapp.com/ | https://git.heroku.com/beginning-rails-6-brady.git

Since Heroku names must be unique, you obviously won’t be able to use beginning-rails-6-brady, but you can be creative and choose your own, like maybe chunky-bacon.

Installing PostgreSQL

To support deploying to Heroku, we’ll need to make one more change. We’ve been using SQLite as our database, but it’s not supported in Heroku. Why? SQLite stores its data in a file—and filesystems in Heroku are ephemeral, meaning they can suddenly be reset to their initial state. This may seem like an unfair limitation, but relying on the local filesystem in production blocks the ability to scale to running your application with more servers. Also, SQLite just isn’t suited for production usage; it’s fine for a few users at a time, but is not built to handle much more than that.

Instead, Heroku offers support for PostgreSQL—a much more robust database server suitable for production environments. While Rails makes it possible to use SQLite locally but PostgreSQL in production, Heroku strongly recommends switching to PostgreSQL locally. One reason is that even though Active Record does a great job at abstracting the differences and keeping the actual database being used easily swappable, it is possible to write database-specific code, leading to problems only found in the production environment.

Also, deployments to Heroku will fail if they detect the sqlite3 gem in our Gemfile.lock file. It’s possible to regenerate our Gemfile.lock file just before each deploy to omit the sqlite3 gem, but it would be a constant hassle and not worth it in the long run. So let’s bite the bullet and install PostgreSQL.

Visit www.postgresql.org/download/ and follow the instructions for your development platform to install PostgreSQL on your system. Some platforms have downloadable installers, while others have instructions for installing PostgreSQL via your system’s package manager.

Once successfully installed, you should be able to open a new command prompt and run psql—PostgreSQL’s command-line tool. You should see something like the following, though your output may vary:
$ psql -U postgres
psql (12.2)
Type "help" for help.
postgres=# select VERSION();
                                   version
---------------------------------------------------------------------------
 PostgreSQL 12.2 on x86_64-apple-darwin19.4.0, compiled by Apple clang version 11.0.3 (clang-1103.0.32.59), 64-bit
(1 row)
postgres=# exit

At this point, PostgreSQL is installed and working on your system. Now it’s time to configure our Rails application to use PostgreSQL instead of SQLite.

Switching to PostgreSQL

You may remember that in your application’s folder, there is a file named Gemfile. This file stores a list of all the “gems” your project uses. Gems are little pieces of code that are easy to pull into your project to add features. Rails itself is a gem, and when we started this project, a whole host of gems were pulled in. Along the way, we’ve added a gem or two ourselves.

To facilitate the easiest out-of-the-box environment for developers, Rails includes and uses the sqlite gem and configures the databases (in config/database.yml) to use SQLite by default.

So let’s change our application to use PostgreSQL instead. Let’s edit our Gemfile to match Listing 18-1.
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }
ruby '2.6.5'
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 6.0.2', '>= 6.0.2.1'
# Use PostgreSQL as the database for Active Record
gem 'pg'
# Use Puma as the app server
gem 'puma', '~> 4.1'
# ... rest of contents omitted ...
Listing 18-1

Changing Gemfile to Use PostgreSQL Instead of SQLite https://gist.github.com/nicedawg/7d2567221075d2ff12a5aa87f3eb57f0

Be sure to remove the line that starts with “gem ‘sqlite3’,” and save the Gemfile. Next, we’ll run bundle install to install the new gem on our machine and to generate a new Gemfile.lock (so that other environments will install the same version of our gems):
$ bundle install

When all goes well, you’ll see the list of installed gems scroll by, including our newly added pg gem. If there’s an error installing the pg gem, it may be that you’re missing a library needed for its installation. (For example, on Ubuntu, you may need to install the libpq-dev package.)

After successfully installing the pg gem, we need to let Git know that we want to commit the changes to the Gemfile and Gemfile.lock files:
$ git add Gemfile Gemfile.lock
$ git commit -m "Replace sqlite gem with pg"
[ch-18 2dcb4f5] Replace sqlite gem with pg
 2 files changed, 4 insertions(+), 4 deletions(-)
We’ve replaced the sqlite3 gem with the pg gem, but our switch to using PostgreSQL is not yet complete; we need to configure our application to use the right database adapter. Edit your config/database.yml so that it matches Listing 18-2.
default: &default
  adapter: postgresql
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  timeout: 5000
development:
  <<: *default
  database: beginning_rails_6_development
# 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: beginning_rails_6_test
production:
  <<: *default
  database: beginning_rails_6_production
Listing 18-2

Switching to PostgreSQL in config/database.yml https://gist.github.com/nicedawg/889466f0eb905eb867beae7156c2705d

We’re almost done! If you were to restart your Rails app now and try to load it in your browser, you’d see an error saying “database beginning_rails_6_development does not exist.” So let’s run the rails db:setup to recreate our databases in PostgreSQL and to use db/seeds.rb to add some records:
$ rails db:setup
Created database 'beginning_rails_6_development'
Created database 'beginning_rails_6_test'

Restart your Rails server, and click around in your app. Everything should still work the same as it did before. If you run into trouble that seems like it could be database related, running rails db:reset is an option, since we don’t have any data we care about. Installing PostgreSQL may be a little tricky, but switching your Rails app to use it is easy!

Deploying to Heroku

Now we’re ready to deploy our app! It’s as easy as one command, though be patient; it will take a few minutes:
$ git push heroku master
Enumerating objects: 1019, done.
Counting objects: 100% (1019/1019), done.
Delta compression using up to 8 threads
Compressing objects: 100% (609/609), done.
Writing objects: 100% (1019/1019), 254.30 KiB | 16.95 MiB/s, done.
Total 1019 (delta 573), reused 691 (delta 378), pack-reused 0
remote: Compressing source files... done.
remote: Building source:
remote:
remote:  !     Warning: Multiple default buildpacks reported the ability to handle this app. The first buildpack in the list below will be used.
remote:                         Detected buildpacks: Ruby,Node.js
remote:                         See https://devcenter.heroku.com/articles/buildpacks#buildpack-detect-order
remote: -----> Ruby app detected
remote: -----> Installing bundler 1.17.3
remote: -----> Removing BUNDLED WITH version in the Gemfile.lock
remote: -----> Compiling Ruby/Rails
remote: -----> Using Ruby version: ruby-2.6.5
remote: -----> Installing dependencies using bundler 1.17.3
remote:        Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment
remote:        The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
remote:        Fetching gem metadata from https://rubygems.org/............
remote:        Fetching rake 13.0.1
remote:        Installing rake 13.0.1
 ...
remote: -----> Launching...
remote:        Released v6
remote:        https://evening-ocean-78121.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/evening-ocean-78121.git
 * [new branch]      HEAD -> master
There is a lot of output from the command, and your output may differ, but at the end you will see something like
https://evening-ocean-78121.herokuapp.com/ deployed to Heroku
This means that the deployment worked! Go ahead and visit the URL to view your app in production (or run heroku open), but don’t get too excited, because it’s certainly an error page. “We’re sorry, but something went wrong.” How can we tell what went wrong? We can run the convenient heroku logs command:
$ heroku logs
Look carefully at the output. You’ll see an error that says something like "PG::UndefinedTable: ERROR: relation “articles” does not exist." We need to create our database tables! Unfortunately, we can’t simply run the db:setup or db:migrate command for two reasons: First, trying to create the database fails due to some limitations from Heroku, as they take care of creating the database their custom way. Second, one of our migrations (from Chapter 11) has some SQL in it which is specific to SQLite 3. Rather than modifying the migration file, which has risks not unlike traveling into the past and changing history, we can run this command to allow us to recreate the database from our db/schema.rb file, rather than building it back up from scratch using our migrations:
$  heroku run rails db:schema:load DISABLE_DATABASE_ENVIRONMENT_CHECK=1

Setting the "DISABLE_DATABASE_ENVIRONMENT_CHECK" environment variable was necessary because Rails thankfully tries to protect us from doing destructive things to our production database.

After successfully creating the database tables, we can view the blog running on Heroku. It looks good, except it’s rather empty. Let’s populate some records using the db:seed command:
$ heroku run rails db:seed
Looking at the output, things started out well; the command created a user and created some categories, but as soon as it tried to create an article, it failed. Reading the output closely, we see the following error:
Gem::LoadError: Error loading the 'redis' Action Cable pubsub adapter. Missing a gem it depends on? redis is not part of the bundle. Add it to your Gemfile.
Ah! By default, Rails configures Action Cable to use a redis adapter in the production environment. While Heroku does offer a free redis add-on for light usage, they require a valid credit card on file; though a completely reasonable request, we don’t want to require that of our readers, so we’ll change our app to use the async adapter for the production environment instead. (As mentioned in Chapter 15 earlier, this is not recommended for production environments, but is fine for this illustration.) Change your config/cable.yml so it matches Listing 18-3.
development:
  adapter: async
test:
  adapter: test
production:
  adapter: async
Listing 18-3

Using Action Cable’s async Adapter in Production—config/cable.yml https://gist.github.com/nicedawg/9be89c0d6a29a0dbc1cb3786f8b3346e

After saving the change, then let’s commit our changes to Git and redeploy:
$ git add config/cable.yml
$ git commit -m "Use async Action Cable adapter in production"
$ git push heroku master
Now that we’ve hopefully fixed our redis issue, let’s try to seed our database again. If we simply ran the same db:seed command as before, it would fail because our db/seeds.rb file is not idempotent; if it were idempotent, we could run it multiple times, and the overall effect would be as if it had run once. Rather than changing our db/seeds.rb file (which is a good idea—as db/seeds.rb is best when idempotent) or manually removing records, we’ll use a command we haven’t used yet:
$ heroku run rails db:seed:replant DISABLE_DATABASE_ENVIRONMENT_CHECK=1

Again, we had to add the DISABLE_DATABASE_ENVIRONMENT_CHECK environment variable to our command, because it’s destructive; it clears all the database records before it runs db:seed. You wouldn’t want to do this if your database had records you cared about, but we’re still getting started, so it’s fine.

Now that we have some seed data in our Heroku app, click around. Things should look mostly normal!

Perhaps you’d like to add another user. Our blog application doesn’t have a section to allow the creation of new users; we’d previously done that through the rails console command. Thankfully, Heroku made it easy to access your production rails console. Let’s add another user:
$ heroku run console
> Running console on ▯ evening-ocean-78121... up, run.4864 (Free)
Loading production environment (Rails 6.0.2.1)
irb(main):001:0> User.create(email: '[email protected]', password: 'hunter2', password_confirmation: 'hunter2')
=> #<User id: 4, email: "[email protected]", hashed_password: [FILTERED], created_at: "2020-04-25 23:29:45", updated_at: "2020-04-25 23:29:45", draft_article_token: "JQVnjHF5cXVW2VfJb5h5j4YW">

That’s It!

Feel free to take your newly deployed Rails application for a spin; if you find any problems, remember to use the heroku logs command to help troubleshoot. (For example, sending the "Email a Friend" form fails to send the email. If up for a challenge, use heroku logs to find the error, and use knowledge gained from this book to fix the problem. You can do it!)

There is one caveat; remember how earlier in this chapter, when talking about needing to replace SQLite, we mentioned that one reason was because the filesystem is ephemeral? Our application has another dependency on the local filesystem: Active Storage. For convenience, it’s configured to store uploaded files on the local filesystem. However, in Heroku, this means that your uploaded files may suddenly disappear. For real production usage, we’d want to configure our app to store uploaded files in a service such as AWS S3. Trying to cover that in this book would’ve been a bit of a detour; if interested, visit the following URL for more information: https://devcenter.heroku.com/articles/active-storage-on-heroku.

That’s all there is to deploying your app with Heroku! Anyone with a web browser now has access to your application. This deployment is suitable for most small apps and even larger applications if you decide. Heroku allows you to purchase extra “dynos” or servers to scale your application to support heavier loads. You can do this by visiting Heroku’s web console.

Sure, we hit a few bumps along the way, but it wasn’t that bad and gave us a chance to exercise our troubleshooting skills along the way.

Deploying to Heroku is only one of the many different ways you can deploy your Rails applications. One of the more popular, but more complex, solutions is called Capistrano (https://github.com/capistrano/capistrano). Capistrano gives you more control over your app’s deployment steps and is a good option for apps running in more complex environments than a PAAS. Capistrano deployment is out of the scope of this book, but knowing that other deployment solutions exist is important.

Whole books could be written on the topics of server configuration and application deployment, but hopefully this chapter provided you with a quick way to let the masses use your Rails applications with as little pain as possible.

Summary

In this chapter, we talked about various types of web hosting, understood a bit about the hosting needs for a Rails application, and discussed the benefits (and limitations) of using PAAS options (like Heroku).

Then, we created a Heroku account, created a Heroku app, and configured our project to be deployed to Heroku via Git. However, we ran into a few bumps—needing to switch our database to PostgreSQL, reconfiguring Action Cable to use the async adapter in production (which isn’t recommended, but easiest for now), and then re-seeding our database. But this gave us a chance to learn a bit more, and now you know how to view logs from Heroku and open the Rails console in Heroku.

What’s next? While this is the end of our tour of Rails 6, it’s only the beginning of your journey. While it’s true that there’s always more to learn, we hope we’ve provided you with the foundational knowledge you need to build the web applications of your dreams.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.17.128.129