前置き
前回の記事に引き続き、今回もRubyでAPIを作成していきます。
Docker Desktop,SequelAce, Rubyがインストールされている方は同じように作ることができます。
参考記事:
今回は前回よりも少しだけ難易度をあげて、
①ローカルにMySQLコンテナを作る。(アクセスできることを確認する)
↓
②ローカルでAPIを作る。(DBに値を登録する。)
↓
③コンテナ内のDBを参照してみる。
といった流れで進めようと思います。
①ローカルにMySQLコンテナを作ってアクセスしてみる。
まずは今回作成する一連のファイルを配置するためにディレクトリを切っていきます。
$ mkdir API_sample
作成したディレクトリに移動します。
$ cd API_sample
このディレクトリ直下にdocker-compose.ymlファイルを作成します。
$ touch docker-compose.yml
version: '3.8'
services:
mysql:
image: mysql:8.0
volumes:
- ./tmp/mysql:/var/lib/mysql
ports:
- 3306:3306
environment:
- MYSQL_ROOT_PASSWORD=********
version: '3.8'はdocker-compose.ymlの書式のバージョンを指定しています。
services:の部分に起動させるコンテナを記述します。
今回はDBのコンテナだけを起動するため、このような記述になっています。
tmp/mysqlディレクトリをコンテナ内の/var/lib/mysqlディレクトリとするように指定しています。(後述)
コンテナ内部にはMySQLの8.0verを作成し、3306ポートから接続しますという意味になります。
パスワードは今回生意気にもマスクしてみます。笑
またMySQLのデータを格納しておくためのディレクトリも作成しておきます。
$ mkdir tmp/mysql
下記のコマンドで、実際にMySQLに接続してみます。
$ mysql -h 127.0.0.1 -u root -p
無事MySQLに接続することができました。
きちんとDBが作成されていることがわかります。
Gemfileとdatabase.ymlを書き換えて、rails⇨コンテナ内のMySQLに接続できるようにする。
デフォルトではsqlite3を利用する設定になっているため、MySQLを使うように設定しなおします。
gem 'sqlite3', '~> 1.4' # この行を削除
gem 'mysql2' # この行を追加
config/database.ymlを書き換えます。
default: &default
adapter: mysql2
encoding: utf8mb4
charset: utf8mb4
collation: utf8mb4_bin
host: <%= ENV['MYSQL_HOST'] || '127.0.0.1' %>
port: <%= ENV['MYSQL_PORT'] || 3306 %>
username: <%= ENV['MYSQL_USER'] || 'API_user' %>
password: <%= ENV['MYSQL_PASSWORD'] || '*********' %>
database: API_dev
development:
<<: *default
test:
<<: *default
database: API_test
production:
<<: *default
database: API
これでrails⇨MySQLコンテナに接続できます。
dbにsetup_for_dev.sqlというファイルを作成して以下のように記述します。
CREATE USER IF NOT EXISTS API_user IDENTIFIED BY '********';
CREATE DATABASE IF NOT EXISTS API_dev DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
GRANT ALL PRIVILEGES on API_dev.* to API_user;
CREATE DATABASE IF NOT EXISTS API_test DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
GRANT ALL PRIVILEGES on API_test.* to API_user;
mysqlコマンドでファイルを読み込んで実行します。
$ mysql -h 127.0.0.1 -u root -p < ./db/setup_for_dev.sql
Enter password:
MySQLにuserとDBを作成し,権限付与を実行することができました。
②ローカルにAPIを作る。(値を登録する。)
modelを作成します。
$ rails g model Category id:bigint name:string
参考記事にしたがってideaモデルを作成します。
$ rails g model Idea id:bigint category_id:bigint body:text
modelを作成したら、マイグレーションを実行します。下記のような文言が表示されたら成功しています。
$ rails db:migrate
$ rails db:migrate
== 20220424104105 CreateCategories: migrating =================================
-- create_table(:categories)
-> 0.0536s
== 20220424104105 CreateCategories: migrated (0.0537s) ========================
== 20220424104517 CreateIdeas: migrating ======================================
-- create_table(:ideas)
-> 0.0378s
== 20220424104517 CreateIdeas: migrated (0.0378s) =============================
modelの定義をしていきます。
class Category < ApplicationRecord
has_many :ideas
end
class Idea < ApplicationRecord
belongs_to :category
end
次にコントローラーを作成していきます。
$ rails g controller categories
$ rails g controller ideas
続いてルーティングを書いていきます。
Rails.application.routes.draw do
resources :categories, only: [:index, :create]
resources :ideas, only: [:index, :create]
end
次にコントローラーを作成します。
class CategoriesController < ApplicationController
def index
categories = Category.all
render json: categories, each_serializer: CategorySerializer, include: [:ideas]
end
def create
category = Category.new(category_params)
if catgory.save
render json: { status: 'SUCCESS', data: category }
else
render json: { status: 'ERROR', data: category.errors }
end
end
private
def category_params
params.require(:category).permit(:name)
end
end
一覧を取得し、新たに作成するアクションを定義します。
もう一つも作成し、
class IdeasController < ApplicationController
def index
ideas = Idea.all
render json: ideas, each_serializer: IdeaSerializer, include: [:category]
end
def create
category = Category.new(category_params)
idea = Idea.new(idea_params)
if Category.exists?(name: params[:category][:name])
idea_body.save
else
render json: ideas
end
end
def idea_params
params.require(:idea).permit(:body)
end
end
としておきます。
Gemfileに以下を追加して $ bundle install します。
gem 'active_model_serializers'
モデルを編集していきます。
class CategorySerializer < ActiveModel::Serializer
attributes :id, :name, :created_at
has_many :ideas
end
class IdeaSerializer < ActiveModel::Serializer
attributes :id, :body
belongs_to :category
end
Gemfileに以下を追加します。
gem 'faker'
$ bundle install
5.times do
name = Faker::Construction.subcontract_category
Category.create!(name: name)
end
10.times do
category_id = rand(1..3)
body = Faker::Food.dish
Idea.create!(category_id: category_id, body: body)
end
無事データが格納されているか確認してみましょう。