It’s time to continue with our foray into Rails API app with Vue.js frontend! In Part 0 we discussed what technology we’ll be using and why - I highly recommend you read through it if you haven’t already. Now it’s time to get our Rails on.
This is an onging series of articles. It’s highly recommended you start with part 0!
Installing the right version of Rails
Since we’ve decided to use Rails 5.1, that’s what we should get. If you don’t have it already,
gem install rails -v '~> 5.1'
should do the trick.
Setting up a Rails API app
Let’s look at the command first and pick it apart later:
rails new bookstore-backend -T --skip-spring -C -M -d postgresql --api
Whew! That’s a mouthful. Let’s see about all those switches.
-T
amounts to skipping the builtin testing framework. We’ll test our API with something other than MiniTest, so let’s drop it for now.--skip-spring
removes Spring from our application; that’s a personal preference. If you don’t know what Spring does and whether you should remove it, I urge you to find out and decide for yourself.-C
skips Action Cable. No web socket communication for us!-M
skips Action Mailer, which wouldn’t be of any use to us.-d postgresql
of course sets us up for the PostgreSQL database.--api
- now we’re talking! This runs the Rails generator in the API mode, which sets us up for reading and writing JSON instead of pumping out HTML.
Now we can run tree
on this new app, and… wow! When you compare that to a regular Rails app, this is really barebones. But we can trim this up a bit more:
- An
app/jobs
directory was generated for us. We know that there will be no jobs in this application for the foreseeable future, so we can drop that. - There are four initializers that are commented out by default:
backtrace_silencers.rb
,application_controller_renderer.rb
,inflections.rb
andmime_types.rb
. We may as well remove those.
One of the initializers will come in handy, though: cors.rb
. We can uncomment what is already there and modify it to accept all origins:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins ENV.fetch('ALLOWED_ORIGINS') { '*' }
resource '*',
headers: :any,
methods: [:get, :post, :put, :patch, :delete, :options, :head]
end
end
This will make us happy campers in development, and allows us to set it properly for production - when we will know where our front-end lives. As a side note, simply allowing *
would also be fine if we were going to call our API from e.g. a mobile application.
To use this, we need to uncomment rack-cors
in the Gemfile.
Setting up the database
As we’ve said in Part 0, we’ll use Docker to isolate our services in development. The easiest way to do this is by far with Docker. Messing around with images by themselves can be a bit cumbersome though, so we’ll use docker-compose
for that. If you don’t have Docker installed yet, now is a great time to click that link and get it.
When we have docker-compose
ready, we can just drop a file called docker-compose.yml
in the root of our application, set up like this:
postgresql:
image: postgres:9.6
ports:
- 5432:5432
environment:
- PGDATA=/postgresql
- PG_PASSWORD=our-awesome-bookstore-app
volumes:
- ./tmp/data/postgresql:/postgresql
This will set up a container with PostgreSQL 9.6, connect it’s port 5432 to our localhost and set up a password on the database. We can run it using docker-compose up
in the front, or docker-compose start
as a daemon. Don’t forget to stop it when you’re done! I keep forgetting, so I prefer to run mine in the foreground.
Now we just need to point our Rails app to this instance of PostgreSQL in development and test environments. Our database.yml
may look something like this:
default: &default
adapter: postgresql
encoding: unicode
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
development: &development
<<: *default
database: bookstore-backend_development
username: postgres
password: our-awesome-bookstore-app
host: localhost
test:
<<: *development
database: bookstore-backend_test
production:
url: <%= ENV['DATABASE_URL'] %>
You might notice some peculiarities. For example, we’ve created an alias &development
and are running our test
environment off of it. That makes sense, since the only thing we want to differ for the tests is the database they use - they should still hit Docker. Also, we’ve already set up a production environment and made it use DATABASE_URL
. This is how we’ll set it up on Heroku.
As a side note - almost everyone has probably at some (early) point in their career committed credentials to a repository. Most of us probably got chewed out for it. So why are we comfortable doing this for our development and test environments? Simple - the database only exists on our machine and doesn’t talk to the outside world. Of course we would never put production creds in a repo.
All right, let’s hit it:
bundle install
bundle exec rails db:create
bundle exec rails db:migrate
bundle exec bin/setup
Note that in Rails 5 we went to using the rails
CLI tool rather than Rake. After several years of using rake
, this will probably keep tripping me up for a little while longer :)
If everything went well, our database should be set up!
It might seem like we don’t have all that much - but what we have is a very powerful environment to model reality in. We will do exactly that in part 2.
Top image credit: https://www.pexels.com/photo/industry-rails-train-path-481150/ (CC0 Public Domain)