Next.js + Rails (API) + Mysql on Docker's Hello World!

Goal Hello. There were many articles about building a Docker environment for Nuxt.js and Rails, but since there was no article about Next.js, it is a record of building an environment by trial and error. I don't often post to Qiita, so I refer to @ at-946 for the article title and article structure.

--Reference article "Nuxt.js + Rails (API) on Docker Hello World!"

1. Docker preparation

The file structure to be prepared is as follows.

DirectoryStructure


/
|--front/
|    |--Dockerfile
|--back/
|    |--Dockerfile
|    |--Gemfile
|    |--Gemfile.lock #Empty file
|--docker-compose.yml

front/Dockerfile


From node:14-alpine

WORKDIR /usr/src/app

back/Dockerfile


FROM ruby:2.5

ENV LANG=C.UTF-8 \
  TZ=Asia/Tokyo

WORKDIR /app

RUN apt-get update -qq && \
  apt-get install -y nodejs default-mysql-client

COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install

back/Gemfile


source 'https://rubygems.org'
gem 'rails', '~> 6.0.3', '>= 6.0.3.2'

docker-compose.yml


version: "3"

services:
  db:
    container_name: database
    image: mysql:5.7
    command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
    environment:
      MYSQL_ROOT_PASSWORD: password
      MYSQL_DATABASE: sample
      MYSQL_USER: root
      MYSQL_PASSWORD: password
      TZ: Asia/Tokyo
    ports:
      - 3308:3306
    volumes:
      - ./database/my.cnf:/etc/mysql/conf.d/my.cnf
      - ./database/data:/var/lib/mysql
      - ./database/sql:/docker-entrypoint-initdb.d

  api:
    container_name: back
    tty: true
    depends_on:
      - db
    build:
      context: back/
      dockerfile: Dockerfile
    ports:
      - 3000:3000
    volumes:
      - ./back:/app
    command: rails server -b 0.0.0.0

  front:
    build:
      context: front/
      dockerfile: Dockerfile
    container_name: web
    volumes:
      - ./front/app:/usr/src/app
    command: 'yarn dev'
    ports:
      - "4001:3000"

Build the above files once they are ready.

$ docker-compose build

2. Let's make a Next.js app

$ docker-compose run --rm front yarn create next-app .

After waiting for a while, I think the Next.js app will be generated (should). Let's start it right away.

$ docker-compose up

Try accessing localhost: 4001. If all goes well, you should see Welcome to Next.js!.

スクリーンショット 2020-12-29 17.02.30.png

3. Build a Rails environment

Next is the Rails environment construction. RDB adopts MySQL. Rails puts it in API mode.

$ docker-compose run --rm api bundle exec rails new . --api -d mysql

Gemfile conflicts on the way, so be sure to overwrite it.

Overwrite /app/Gemfile? (enter "h" for help) [Ynaqdhm] Y

After creating the Rails app, let's match the database settings with the Mysql settings created with docker-compose.yml.

back/config/database.yml


# MySQL. Versions 5.5.8 and up are supported.
#
# Install the MySQL driver
#   gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
#   gem 'mysql2'
#
# And be sure to use new-style password hashing:
#   https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html
#
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password
  host: database

development:
  <<: *default
  database: sample

# 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: app_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="mysql2://myuser:mypass@localhost/somedatabase"
#
# You can use this database configuration with:
#
#   production:
#     url: <%= ENV['DATABASE_URL'] %>
#
production:
  <<: *default
  database: app_production
  username: app
  password: <%= ENV['APP_DATABASE_PASSWORD'] %>

Let's start it.

$ docker-compose up --build

Try accessing localhost: 3000. It is OK if the following screen is displayed.

スクリーンショット 2020-12-29 17.27.00.png

4. Create an API that returns JSON

Let's create an API on the Rails side so that it can work with the Next.js side.

$ docker-compose run --rm api bundle exec rails g scaffold post title:string

I think I was able to do it smoothly. We will create a table, so let's migrate.

$ docker-compose run --rm api bundle exec rake db:migrate

I can't return JSON because there is no data when I create the table. I am troubled···. Let's create test data. Rails has a handy feature called seed that captures the initial data.

back/db/seeds.rb


# This file should contain all the record creation needed to seed the database with its default values.
# The data can then be loaded with the rails db:seed command (or created alongside the database with db:setup).
#
# Examples:
#
#   movies = Movie.create([{ name: 'Star Wars' }, { name: 'Lord of the Rings' }])
#   Character.create(name: 'Luke', movie: movies.first)
Post.create!(
  [
    {
      title: 'There is a store near the office that sells baked sweet potatoes'
    },
    {
      title: 'There seems to be a front engineer who distributes roasted sweet potatoes'
    }
  ]
)

Oops, I've been angry with the test data. Please don't look at it. Now let's get the test data into the table.

$ docker-compose run --rm api bundle exec rake db:seed

Let's check it.

$ docker-compose up

Let's access localhost: 3000/posts. You can see that kind of data. It's a success.

スクリーンショット 2020-12-29 17.45.26.png

5. View the data with Next.js

Now, let's finally display the data acquired by the API on the Next.js side. I rewrote front/app/pages/index.js as follows. It simply displays the data acquired by the API.

front/app/pages/index.js


export default function Home(props) {
  return (
    <div>
      <h1>List of POST</h1>
      {props.posts.map((post) =>
        <p>{ post.title }</p>
      )}
    </div>
  )
}

export async function getStaticProps() {
  const response = await fetch("http://localhost:3000/posts", {method: "GET"});
  const json = await response.json();

  return {
    props: {
      posts: json
    },
  };
}

Let's access http: // localhost: 4001 ... that? ?? ?? Is it the curse of our front engineer? ??

スクリーンショット 2020-12-29 17.57.33.png

6. Rails side settings

localhost: 3000 doesn't seem to work on the Next.js side. Let's specify the host in the environment settings. (I'm not sure why) Matched to the container name in docker-compose.yml.

back/config/environments/development.rb


Rails.application.configure do
...
  config.hosts << "api"
end

7. Change the API URL in Next.js

Next, change the API URL on the Next.js side.

front/app/pages/index.js


export async function getStaticProps() {
  const response = await fetch("http://api:3000/posts", {method: "GET"});
・ ・ ・
}

Let's start docker again.

$ docker-compose up

Oh, it seems that it was finally displayed.

スクリーンショット 2020-12-29 18.08.08.png

Impressions

I'm tired of writing an article after a long time.

Recommended Posts

Next.js + Rails (API) + Mysql on Docker's Hello World!
Hello World on WebAssembly
Hello World on AWS Lambda + Java
Rails API
Hello World on Mac VS Code Java
Run Docker environment Rails MySQL on Heroku. devise and hiding the twitter API
Rails6 [API mode] + MySQL5.7 environment construction with Docker
Run JSP Hello World with Tomcat on Docker
[Rails MySQL] How to reset DB on heroku
Easy to display hello world with Rails + Docker
Tailwind on Rails
Read "Hello world"
Java, Hello, world!
Java Hello World
[Introduction] Display Android Studio Hello World on the emulator
Build Rails (API) x MySQL x Nuxt.js environment with Docker
[Ruby on Rails] From MySQL construction to database change