Railsにこれから初めて触れる方を対象にしたチュートリアルです
RailsとStimulusを使ってリアルタイムに更新されるチャットアプリを作成します
まず、rails new
を実行し、Railsアプリのひな型を作成します
rails new realtime_chat --webpack=stimulus
--webpack
はRailsでWeboack
を使いやすくしたWebpacker
というものを使用するというオプションです
Vue、React、Angular、Elm、Stimulusを使用することができます
今回はStimulus
を使用するので--webpack=stimulus
としています
次に、作成したRailsアプリのディレクトリへと移動します。
cd realtime_chat
SQLite3のバージョン修正
先ほどのrails new
でsqlite3
のインストールがエラーになっている場合は、以下のようにバージョンを指定してください
gem 'sqlite3', '1.3.13'
その後、bundle install
を実行します
bundle install
Webpacker
を使う場合、ruby ./bin/webpack-dev-server
というコマンドを実行しつつ、rails s
でローカルサーバーを起動する必要があります
その為、現状のままではターミナルを複数開いておく必要があり、少々面倒です
そこで、複数のコマンドを並列して実行できるforeman
を使用します
まず、Gemfile
にgem 'foreman'
を追記します
gem 'foreman'
その後、bundle install
bundle install
次に、foreman
で使用するProcfile.dev
を作成します
web: bundle exec rails s
webpacker: ruby ./bin/webpack-dev-server
あとは、foreman start -f Procfile.dev
をターミナルで実行するだけです
foreman start -f Procfile.dev
localhost:5000
にアクセスできればOkです(foreman
を使用する場合、使用するポートが5000へと変更されています)
rails g scaffold
コマンドを使い、チャットルーム作成のCRUDを作ります
rails g scaffold room title:string
その後、rails db:migrate
を実行し、マイグレーションを行います
rails db:migrate
あとは、foreman start -f Procfile.dev
を実行してローカルサーバを起動します
localhost:5000/rooms
にアクセスし、チャットルームを作成できればOKです
ルームを作成したので、次はチャットができるようにしたいと思います
まず、チャットを取り扱うTalk
モデルを作成したいと思います
rails g model talk content:string room:references
その後、マイグレーションを行います
rails db:migrate
次に、app/models/room.rb
にリレーションを追加します
class Room < ApplicationRecord
has_many :talks
end
そして、config/routes.rb
にルーティングを追加します
Rails.application.routes.draw do
root 'rooms#index'
resources :rooms do
resources :talks, :only => [:index, :create]
end
# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html
end
次に、各チャットルームにチャットの入力フォームを作成します
まずはapp/views/rooms/show.html.erb
に以下を追加します
<h2>Chats</h2>
<div data-controller="chat">
<div data-target="chat.talks"></div>
<input data-target="chat.content">
<button data-action="click->chat#submit">add</div>
</div>
<%= javascript_pack_tag 'application.js' %>
このように変更します
<p id="notice"><%= notice %></p>
<p>
<strong>Title:</strong>
<%= @room.title %>
</p>
<h2>Chats</h2>
<div data-controller="chat" data-chat-refresh-interval="100">
<div data-target="chat.talks"></div>
<input data-target="chat.content">
<button data-action="click->chat#submit">add</div>
</div>
<%= javascript_pack_tag 'application.js' %>
<%= link_to 'Edit', edit_room_path(@room) %> |
<%= link_to 'Back', rooms_path %>
その後、app/javascript/controllers/chat_controller.js
を作成します
import { Controller } from "stimulus";
import axios from "axios";
export default class extends Controller {
static get targets() {
return ["talks", "content"];
}
connect() {
this.load();
if (this.data.has("refreshInterval")) {
this.startRefreshing()
}
}
load() {
axios.get(`${location.pathname}/talks`).then((res) => {
this.talksTarget.innerHTML = res.data;
}, (error) => {
console.log(error);
})
}
submit() {
axios.post(`${location.pathname}/talks`, { talk: { content: `${this.contentTarget.value}` }}).then((res) => {
this.contentTarget.value = "";
console.log(res);
}, (error) => {
console.log(error);
})
}
startRefreshing() {
this.refreshTimer = setInterval(() => {
this.load()
}, this.data.get("refreshInterval"))
}
stopRefreshing() {
if (this.refreshTimer) {
clearInterval(this.refreshTimer)
}
}
}
作成後、yarn add axios
でaxios
を追加します
yarn add axios
最後に、app/controllers/talks_controller.rb
を作成します
class TalksController < ActionController::API
before_action :set_room
def index
@talks = @room.talks.all
render json: @talks.map{|talk| "<p>#{talk.content}</p>"}.inject(:+)
end
def create
@room.talks.create! talks_params
redirect_to @room
end
private
def set_room
@room = Room.find(params[:room_id])
end
def talks_params
params.required(:talk).permit(:content)
end
end
これで、チャットを送信するとリアルタイムに更新されます!