Rails API & Angular Number Generator
I hacked my way through setting up Angular services in my last two articles:
The goal is to understand how to get a simple Angular application to connect to web server. In this article, I will setup a Rails server to be the server endpoint for the Angular app.
Requirements
- Install Docker Community Edition
- Docker image for rails
$ docker pull andrewrgr/rails-init-api-rgr
- docker image for angular
$ docker pull andrewrgr/angular-rgr
- NumberGeneratorApp source code
$ git clone https://github.com/a-leung/angular-services
The Angular app, NumberGeneratorApp, will have one slight modification and then we will build the Rails server to support the Angular app.
Modifying Angular app
In the second article, the app was using the HTTP client to read from a JSON response from a file. This time, we will make just one change to that Angular app:
In the src/app/number-generator.service.ts
file, change:
private _HTTPFileURL = 'assets/result.json';
to:
private _HTTPFileURL = 'http://localhost:3000/number';
Yes, this will be the only change needed in the Angular app.
Create Rails API server
Let’s create a new Ruby on Rails API app using the Docker image with the command:
$ docker run --mount type=bind,source=$(pwd),target=/rails_app andrewrgr/rails-init-api-rgr rails new number_generator_app --api --skip-coffee --skip-spring --skip-sprockets --skip-test
api | Have the Rails server run in API mode only. |
skip-coffee | Do not include CoffeeScript, just use JavaScript. |
skip-spring | Do not include the Spring fast loader since this app will run in a Docker container. |
skip-sprockets | Do not include Sprokets, we just want to be in API mode only. |
skip-test | Do not include MiniTest, no testing for now, let’s get things working! |
Add Endpoint
In a new Ruby on Rails app, there is only the /
endpoint, which
shows the default “Welcome to Rails” page.
We need another endpoint specifically for our Angular app, so we will
create it by adding a new controller called: number_generator
with
command:
$ docker run --mount type=bind,source=$(pwd),target=/rails_app andrewrgr/rails-init-api-rgr rails generate controller number_generator
This command creates a new file at:
app/controllers/number_generator.rb
. Modify the file contents to be:
class NumberGeneratorController < ApplicationController
def number
render json: { value: 42000 }
end
end
This will now return a JSON response to an endpoint, to connect this
function to an endpoint, we have to modify the config/routes.rb
file.
Configure Routes
To connect a Ruby on Rails’ server endpoint, so any requeests to
/number
will call the method number
of the
NumberGeneratorController
, we have to modify the contents of the
config/routes.rb
file to be:
Rails.application.routes.draw do
get '/number', to: 'number_generator#number'
end
This connects any brower request: localhost:3000/number
to run the
number
method in the NumberGeneratorController
.
Test Configuration
Let’s test out the application by running it:
$ docker run --mount type=bind,source=$(pwd),target=/rails_app -p 3000:3000 andrewrgr/rails-init-api-rgr rails s
Open a browser and goto: http://localhost:3000/number
, the image
will be:
Test curl
We can use another tool to test the server configuration is UNIX
utility: curl
, it’s a command line program that makes HTTP requests.
The command and output:
$ curl localhost:3000/number
{"value":42000}$
Connect Angular
With the Ruby on Rails app ready to accept requests at:
http://localhost:3000/number
, let’s have the Angular app connect to
it.
Start the Angular server with:
$ docker run --mount type=bind,source="$(pwd)",target=/angular -p 4200:4200 andrewrgr/angular-rgr ng serve
If the Ruby on Rails is not running, start it with:
$docker run --mount type=bind,source=$(pwd),target=/rails_app -p 3000:3000 andrewrgr/rails-init-api-rgr rails s
And open a browser to: localhost:4200
and the page should be:
What’s wrong? There’s no output. Looking at the browser’s console, we see:
Hmm… this is interesting. Looking at the console of the Ruby on Rails server, there is nothing… hmm…?
Configuring CORS
I realized that Ruby on Rails accepts any web request, but to prevent another website from using unauthorized resources, CORS was setup for webservers to prevent abuse.
I found the solution by configuring CORS, modify two files:
In the Gemfile
, uncomment:
gem 'rack-cors'
In config/initializers/cors.rb
file, uncomment and modify the file
to be:
Rails.application.config.middleware.insert_before 0, Rack::Cors do
allow do
origins '*',
resource '*',
headers: :any,
methods: %i(get post put patch delete options head)
end
end
Restart the server
Let’s restart the Ruby on Rails NumberGenerator server:
$ docker run --mount type=bind,source=$(pwd),target=/rails_app -p 3000:3000 andrewrgr/rails-init-api-rgr rails s
Test with CORS update
Once again, if the Angular app is not running, start the Angular app with:
$ docker run --mount type=bind,source="$(pwd)",target=/angular -p 4200:4200 andrewrgr/angular-rgr ng serve
Start the Ruby on Rails server with:
$ docker run --mount type=bind,source=$(pwd),target=/rails_app -p 3000:3000 andrewrgr/rails-init-api-rgr rails s
And open a browser to: localhost:4200
and the page should be:
Yay!
Conclusion
Connecting a single page app based on Angular to a Ruby on Rails API server is pretty easy with all components in place.
The Ruby on Rails server needs to have CORS setting so any site can access it. In the article, I configured the Ruby on Rails server to be an API only server, but this is entirely optional.
With the properly configured Angular application, being able to connect to a web server required a single line change, which I think is sweet.