こんにちは、Nanayakuです。
今回はとだこうき(@cohki0305 )さんのyoutube動画を参考にDockerでchatアプリを作ってみたので、それを解説したいと思います。
目次
Dockerで環境構築
今回は以下の環境で開発しました。
DockerでRails+PostgreSQLの環境構築を解説
Dockerfile
FROM ruby:2.5.5
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
RUN mkdir /myapp
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp
# Add a script to be executed every time the container starts.
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
docker-compose.yml
version: '3'
services:
db:
image: postgres
volumes:
- ./tmp/db:/var/lib/postgresql/data
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
localhost:3000をもう指定して使っている場合は、「ports:- "3000:3000"」を「ports:- "3001:3000"」に変更すれば、localhost:3001でサーバーをたてられます。
entrypoint.sh
#!/bin/bash
set -e
# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid
# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5'
Gemfile.lock
空のファイルです。
この情報はGitに上げておきました。
今回の開発環境(docker-compose.ymlの2列目以降のインデントが1段不要でした)
開発の流れ
下準備
以下のコマンドでRailsプログラムを作成します。
$ docker-compose run web rails new . --skip-coffee --force --no-deps --database=postgresql
動画では「pry-rails」と言うgemをインストールしています。
私はそれ以外に「rubocop」と言うgemをインストールしました。
gem 'pry-rails'
gem 'rubocop', require: false
「config/database.yml」の内容を以下のように変更し、dbと連携させます。
config/database.yml
default: &default
adapter: postgresql
encoding: unicode
host: db
username: postgres
password:
pool: 5
development:
<<: *default
database: myapp_development
test:
<<: *default
database: myapp_test
以下のコマンドで「bundle install」・コンテナの作成ができます。
$ docker-compose build
Dockerのコンテナをバックグラウンドで起動するには「-d」オプション付けます。
変更を確認しながら開発するとき、非常にやりやすくお勧めです。
$ docker-compose up -d
ここからは、動画の4分30秒からの手順にそって説明していきます。
Roomsコントローラーの作成
dockerでコントローラーの作成をする時のコマンドは、以下のようになります。
Roomsコントローラーとshowアクションを作成します。
$ docker-compose exec 'アプリ名' 'railsの命令'
$ docker-compose exec web rails g controller Rooms show
「docker-compose exec」は、コンテナが起動している時に使用するコマンドです。
ルーターの設定
ルーターで「views/show.html.erb」が表示するように設定します。
「$ docker-compose up」または、リロード(command + r)でページが変更されたのを確認できます。
modelの作成
以下のコマンドでモデルを作成し、マイグレーションをdbに反映させます。
$ docker-compose exec web rails g model Message content:string
$ docker-compose exec web rails db:migrate
データを表示
保存したデータを取得するために、コントローラーを画像のように追記します。
これは、dbのmessageのデータを全てインスタンス変数の@messagesに格納しています。
次に保存したデータを表示するために、view(rooms/show.httml.erb)を画像のように変更します。
また、viewにmessagesディレクトリ・_message.html.erbファイル作成し、画像のコードを追記します。
<p><%= message.content %></p>
注意ポイント
app/view/messages/_masseage.html.erbのアンダーバーを忘れないようにしましょう。
つけ忘れると画像のようなエラーが出ます。
コンソールでデータを保存
保存されたデータが正常に表示されるか確認します。
以下のコマンドでコンソールを開けます。
$ docker-compose up -d
$ docker-compose exec web rails c
「Message.create!(content: '保存する文字')」で、保存できます。
その後、ブラウザをリロードすれば、保存した文字が表示されます。
注意
日本語の文字化けが発生してしまいます。
以下の記事を参考にし、「docker-compose.yml」の内容を変更しても治せませんでした。
Dockerで立ち上げたMySQLにログインすると日本語が文字化け
volumes:
- ./mysql-data:/var/lib/mysql
- ./my.cnf:/etc/mysql/conf.d/my.cnf
チャットシステムの構築
チャットには「Websocket」と言う通信が使われます。
従来のHTTP通信は、欲しい情報を取得するにはユーザーがリクエストしなければなりませんでした。
このWebsocket通信は、情報が保存されるとその情報をユーザーへ発信するシステムになります。
つまり、あるユーザーがメッセージを送信(保存)すると、その情報が全員の画面に表示されるLINEなどで使用されているシステムです。
channelの作成
以下のコマンドでchannelを作成できます。
$ docker-compose exec web rails g channel Room speak
実行すると以下のファイルが作成されます。
- app/channels/room_channel.rb
- app/assets/javascripts/channels/room.js
「app/channels/room_channel.rb」は、サーバーサイドの処理(保存)に反応するチャンネルです。
「app/assets/javascripts/channels/room.js」は、クライアントサイドの処理(送信ボタンやサーバーから送られてくる情報)に反応するチャンネルです。
サーバーサイドとクライアントサイドをつなぐルートを設定します。
画像のように「config/routes.rb」に「mount ActionCable.server => '/cable'」追記します。
「binding.pry」を用いて、各メソッド・ファイルがどのような働きをしているかは、動画の方が分かりやすいので、動画の19分30秒から確認してみて下さい。
「$ docker-compose up」で起動しないと、どこで止まっているか確認する事が出来ません。
この時、「app/channels/room_channel.rb」のsubscribedの「stream_from "some_channel"」をコメントアウトし、"room_channel"に変更しなければ、ちゃんと実行出来ません。
speakアクションの設定
「app/assets/javascripts/channels/room.js」のspeakファンクションは、フロントサイドで処理があった場合、バックエンドのspeakアクションに情報を送ります。
「app/channels/room_channel.rb」のspeakアクションは、フロントサイドから送られた情報を、各ユーザーに送信する処理を行ないます。
入力フォームからデータの送信
Viewに入力フォームを作成します。
「app/assets/javascripts/channels/room.js」で、送られてきた情報を各ユーザーに送信する処理を作成します。
上記は、送信ボタンが押されたら、その情報をspeakアクションに送る処理を行います。
また、ボタンを押した後、入力欄を空欄にする処理も行なっています。
送信した情報を表示
ここまでで、フロントサイドからバックエンドへ、バックエンドからフロントサイドに情報を送信する処理は作成できました。
しかし、まだバックエンドからフロントサイドに送られた情報を表示できていないので、その処理を作成します。
「app/assets/javascripts/channels/room.js」のreceivedファンクションを、画像のように追記します。
bootstrapの導入
Gemfileに「gem 'bootstrap', '~> 4.3.1'」を追記します。
私は、「$ docker-compose exec web bundle install」では、ちゃんとできていなかったので、docker-compose downした後に「$ docker-compose build」を実行します。
その後、「$ docker-compose up -d」でコンテナを起動し、
「$ docker-compose exec web mv app/assets/stylesheets/application.css app/assets/stylesheets/application.scss」でファイル名を変更します。
「app/assets/stylesheets/application.scss」に「@import "bootstrap";」を追記します。
しかし、画像のようなエラーになると思います。
これを解決するには、Gemfileに「gem 'mini_racer'」を追記します。
その後、「$ docker-compose up --build」を実行します。
これで解決するはずです。
Viewを画像のように整えます。
参考資料
Action Cableでリアルタイムチャットアプリの作成方法 (Rails 5.1.4にて)(その1) herokuで動かす!
上記の記事を参考にする場合は、プログラムを作成するコマンドは以下の通りです。
$ docker-compose run web rails new . --force --no-deps --database=mysql
最後に
今回作成したサンプルをGitHubにアップしています。
https://github.com/sabakan789/chat.rails.sample
備忘録がわりに作ったので、間違っている所とかあったら、コメントくれると嬉しいです。