[Ruby] Build a development environment to create a Ruby on Jets + React app with Docker

3 minute read

Overview

This is the procedure for building a development environment for creating Ruby on Jets (API) and React apps. Ruby on Jets is created for API only. DB uses MySQL. React uses Typescript. Docker uses Docker for Mac.

When I open the page locally, I get the user information stored in the DB from the API and display it. We haven’t even deployed to AWS.

file organization

reactjets/
├ api/
│ ├ ...
├ front/
│ ├ ...
├ docker/
│ ├ api/
│ │ ├ Dockerfile
│ ├ front/
│ │ ├ Dockerfile
│ ├ mysql/
│ │ ├ conf.d
│ │ │ ├ my.cnf
│ ├ docker-compose.yml

Docker environment construction

Create Dockerfile (2 types), Gemfile, Gemfile.lock, my.cnf, docker-compose.yml

docker/front/Dockerfile


FROM node:12.18

docker/api/Dockerfile


FROM ruby:2.5.8

WORKDIR /api
COPY api /api
RUN bundle install

api/Gemfile


source'https://rubygems.org'
gem'jets'

Gemfile.lock creates an empty file

api/Gemfile.lock


touch Gemfile.lock

:docker/mysql/conf.d/my.cnf


[mysqld]
character-set-server=utf8mb4
explicit-defaults-for-timestamp=1

[client]
default-character-set=utf8mb4

docker/docker-compose.yml


version: '3'

services:
  front:
    build:
      context: ../
      dockerfile: docker/front/Dockerfile
    volumes:
  #: The left part matches with your environment
      -~/Dev/reactjets/front:/front
    ports:
      -"8000:3000"
    stdin_open: true

  api:
    build:
      context: ../
      dockerfile: docker/api/Dockerfile
    command: bash -c "bundle exec jets server --port 3000 --host 0.0.0.0"
    volumes:
  #: The left part matches with your environment
      -~/Dev/reactjets/api:/api
    ports:
      -"3000:3000"
    depends_on:
      -db

  db:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: app
      MYSQL_USER: docker
      MYSQL_PASSWORD: docker
      TZ:'Asia/Tokyo'
    ports:
      -3306:3306
    volumes:
      -./mysql/conf.d:/etc/mysql/conf.d

docker-compose build

$ docker-compose build

Jets app creation

$ docker-compose run api jets new .--mode api --database=mysql
  • If Overwrite /api/Gemfile? (enter “h” for help) [Ynaqdhm] appears, Y

Confirm that jets application is created under api Add environment variables to .env.development for DB connection

:.env.development


DB_HOST=db
DB_NAME=app
DB_USER=docker
DB_PASS=docker

React app creation

$ docker-compose run --rm front sh -c'yarn create react-app front --template typescript'

Confirm that react application is created under front

Start-up

$ docker-compose up --build

start react

$ docker exec -it docker_front_1 bash

# cd front
# yarn start

Confirm that the screen is displayed Ruby on Jets: http://localhost:3000 React: http://localhost:8000 Screenshots 2020-06-27 10.42.37.pngScreenshot 2020-06-27 17.56.45.png

api created

create user with scaffold

$ docker exec -it docker_api_1 bash

# jets generate scaffold user name:string age:integer
# jets db:create db:migrate
  • If you get access denied etc. in jets db:create db:migrate, check the permission setting of the user on mysql side.
GRANT ALL ON *.* to docker@'%';

Since the users table has been created, you can INSERT two items directly. When you access http://localhost:3000/users, you can see that the following data is returned.

[{"id":1,"name":"mikami","age":26,"created_at":"2020-06-27T18:57:44.000Z","updated_at":"2020-06-27T18: 57:44.000Z"},{"id":2,"name":"tomoyuki","age":32,"created_at":"2020-06-27T18:57:44.000Z","updated_at":" 2020-06-27T18:57:44.000Z"}]

Communication between # front and api

front side

axios installation

$ docker exec -it docker_front_1 bash

# cd front
# yarn add axios

Edit App.tsx

App.tsx


import React from'react';
import axios from'axios';
import'./App.css';

class App extends React.Component<any, any> {
  constructor(props: any) {
    super(props);
    this.state = {
      users: []
    }
  }

  componentDidMount() {
    axios.get('http://localhost:3000/users')
      .then((result) => {
        this.setState({ users: result.data });
      })
  }

  render() {
    return (
      <div className="App">
        <h1>Users</h1>
        <div>
          {this.state.users.map((v: any) => {
            return (
              <div key={v.id}>
                <p>id: {v.id}</p>
                <p>name: {v.name}</p>
                <p>age: {v.age}</p>
              </div>
            )
          })}
        </div>
      </div>
    )
  }
}

export default App;

As it is not possible to communicate with CORS as it is, set CORS on api side

api side

Uncomment the following

application.rb


config.cors = true # for'*'' # defaults to false

Confirmation

Reboot

$ docker-compose stop
$ docker-compose start
$ docker exec -it docker_front_1 bash

# cd front
# yarn start

If you access http://localhost:8000/ and the following is displayed, communication is ok Screenshot 2020-06-27 19.25.09.png

WIP

Deployment procedure on AWS

Ruby on Jets deployhttps://qiita.com/kskinaba/items/9c570093ed912f8f1681 この通りにやる

Ruby 2.5系じゃないとだめらしい…

Deploying to Lambda api-dev environment...
/usr/local/bundle/gems/memoist-0.16.2/lib/memoist.rb:213: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
/usr/local/bundle/gems/jets-2.3.16/lib/jets/lambda/dsl.rb:319: warning: The called method `_unmemoized_find_all_tasks' is defined here
Building CloudFormation templates.
Generated CloudFormation templates at /tmp/jets/api/templates
Deploying CloudFormation stack with jets app!
Waiting for stack to complete
02:25:31AM CREATE_IN_PROGRESS AWS::CloudFormation::Stack api-dev User Initiated
02:25:34AM CREATE_IN_PROGRESS AWS::S3::Bucket S3Bucket
02:25:35AM CREATE_IN_PROGRESS AWS::S3::Bucket S3Bucket Resource creation Initiated
02:25:56AM CREATE_COMPLETE AWS::S3::Bucket S3Bucket
02:25:58AM CREATE_COMPLETE AWS::CloudFormation::Stack api-dev
Stack success status: CREATE_COMPLETE
Time took for stack deployment: 28s.
You are using Ruby version 2.7.1 which is not supported by Jets.
Jets uses Ruby 2.5.3.  You should use a variant of Ruby 2.5.x