Ruby on Railsでデータベース(MySQL)のテーブル作成をしてみた話
きっかけ
本当はORMの話を書くつもりでしたが、テーブル作成までで一旦区切ることにしました。
手順
事前準備
Docker
今回はMySQLを使います。
Rubyに関しては
と同様のDockerfileを使用しています。FROM mysql:latest
RUN echo '\
[mysqld]\n\
character-set-server=utf8mb4\n\
collation-server=utf8mb4_unicode_ci\n\
\n\
[client]\n\
default-character-set=utf8mb4\n\
' > /etc/mysql/conf.d/my.cnf
version: '3'
services:
db:
build: ./mysql
environment:
MYSQL_ROOT_PASSWORD: root
TZ: "Asia/Tokyo"
ports:
- "3306:3306"
web:
image: ruby
build: .
ports:
- "3000:3000"
volumes:
- /d/github/xxx:/home/rubyuser/git-workspace/xxx
depends_on:
- db
phpmyadmin:
image: phpmyadmin/phpmyadmin
environment:
- PMA_ARBITRARY=1
- PMA_HOST=db
- PMA_USER=root
- PMA_PASSWORD=root
depends_on:
- db
ports:
- "3001:80"
Railsプロジェクトの作成
コンテナ内の展開先で以下のコマンドを叩いていきます。
今回はデータベースにMySQLを使用するのでオプションで「使用するSQL」を指定しています。
rails _6.1.4.1_ new . --force --minimal --skip-test --database=mysql
SQL設定
SQLに関する設定が無いとSQLに繋がらないので、まずはその設定を加えます。
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: root
host: db
ポイント
- 【password】はdocker-compose.ymlで指定しているMYSQL_ROOT_PASSWORDです。
- 【host】はdocker-compose.ymlで指定しているservicesのMySQLが動いているコンテナ名*dbです。
上記設定後、rakeのコマンドでこのRailsプロジェクトが使用するデータベースを作成します。
rake db:create
同ディレクトリで以下のコマンドを実行してブラウザで http://localhost:3000/ にアクセスするととりあえず動作していることが確認できました。
rails s -p 3000 -b '0.0.0.0'
テーブルの作成
単純なテーブル
一般ユーザー[1]を想定したテーブルを定義します。
rails generate scaffoldでrails側にファイルを作成します。
このコマンドでテーブルの情報から、そのテーブルに関するCRUDが一通りできるMVC各ファイル他が作成されたり更新されたりします。
rails generate scaffold Normal_User name:string mail:string last_login_at:datetime
id、created_at、updated_atは明示的に指定していませんが暗黙的に作成されます。
rails generate scaffoldの実行だけではMySQLサーバー側には反映されていないので、それを反映します。
rake db:migrate
ブラウザで http://localhost:3000/normal_users にアクセスすると色々操作できます。
外部キーを持つテーブル
一般ユーザーが日常を投稿することが可能なテーブルを想定します。
このテーブルのレコードは必ず一般ユーザーが登録されていることを前提とします。
テーブル名は「normal_users」ですが、rails g を実行する際は「normal_users」を指定すると整合性が取れないのか、saveでエラーしました。sを付けずに「normal_user」とする必要があるようです。
rails generate scaffold Everyday_Post normal_user:references everydaypost_comment:string
MySQLサーバー側に反映します。
rake db:migrate
NOT NULL 制約 & DEFAULT & UNIQUE 制約
既に一部で勝手にnot null制約が付与されていますが、明示的にnot null制約を持つカラムを含むテーブルを追加してみます。
ついでにデフォルト値設定を加えます。
作成しようとしたテーブルがユニーク制約が合った方が良さそうな気がしたのでユニーク制約も付けます。
残念ながら現時点ではnullやデフォルトをrails generateコマンドで設定するのは難しいようなので、一旦これらは無かったことにしてファイルを作成します。
rails generate scaffold User_Setting normal_user:references:uniq use_notification:boolean
こんなファイルが作成されました。数字の部分は実行時に依存すると思うのでdb/migrate/配下からそれっぽいファイル名のものを探してください。
class CreateUserSettings < ActiveRecord::Migration[6.1]
def change
create_table :user_settings do |t|
t.references :normal_user, index: {:unique=>true}, null: false, foreign_key: true
t.boolean :use_notification
t.timestamps
end
end
end
NOT NULL制約とDEFAULTを追加します。
class CreateUserSettings < ActiveRecord::Migration[6.1]
def change
create_table :user_settings do |t|
t.references :normal_user, index: {:unique=>true}, null: false, foreign_key: true
t.boolean :use_notification, null: false, default: 'true'
t.timestamps
end
end
end
MySQLサーバー側に反映します。
rake db:migrate
「ID」以外をPRIMARY KEYとする
先に追加したテーブルはユニーク制約を追加してみたかったので一旦そうしたのですが、このテーブルであればnormal_user自体がプライマリである方が自然というか間違いが起きづらい気がします。
ここでは既存テーブルの変更ではなく、無かったものとして話を進めます。
rails generate scaffold User_Setting normal_user:references use_notification:boolean
IDの作成を抑止し、プライマリーキーを別途明示します。
class CreateUserSettings < ActiveRecord::Migration[6.1]
def change
create_table :user_settings, id: false do |t|
t.references :normal_user, null: false, foreign_key: true, primary_key: true
t.boolean :use_notification, null: false, default: 'true'
t.timestamps
end
end
end
MySQLサーバー側に反映します。
rake db:migrate
このままだとIDが無いのでrails generate scaffoldで生成された画面が動きません。
色々修正します。
まずルーター。
「param:」を付けて明示しておきます。
これ自体はそのままIDで使っても動くかもしれませんが後々混乱を招きかねません。
Rails.application.routes.draw do
# resources :user_settings
resources :user_settings, param: :normal_user_id
resources :everyday_posts
resources :normal_users
end
idでfindしているので、normal_user_idに変更します。
private
# Use callbacks to share common setup or constraints between actions.
def set_user_setting
# @user_setting = UserSetting.find(params[:id])
@user_setting = UserSetting.find(params[:normal_user_id])
end
http://localhost:3000/user_settings から登録済みのnormal_userのIDしか登録できないことが確認できると思います。
phpMyAdmin
名前に「php」と入っていますが、php用ではなくPHPで実装されたMySQLサーバ向けのデータベース接続クライアントツールです。
railsの確認が出来ているのであれば上記アドレスでアクセスできると思います。
DBの値のチェックはrailsの画面ではなく、データベース接続クライアントツールを使って確認してください。
必ずしもphpMyAdminでなければいけないわけではありません。データベース接続クライアントツールは色々あるので自分に合うものを探すと良いと思います。(というよりセキュリティリスクにしかならないのでネットワーク上の環境にphpMyAdminを配置するのは避けた方が良いです)
今回のコマンドを写経すると画像のような感じになります。
まとめ
rails generate scaffold テーブル名 カラム名1 カラム名2 ...
を実行して
rake db:migrate
でMySQLサーバーへ反映する。
本文中では触れていませんが、railsのCRUDが生成時に不要であればscaffoldの代わりにmodel等を指定するのもよいかもしれません。
お疲れさまでした。
-
個人的に1単語のテーブル名はあまり好きではないので私が作成するテーブルは大体二単語以上です。カラム名も同様なのですが参考にした元のまま端折っちゃいました。 ↩︎
Discussion