#はじめに
こんにちは、とあるプログラミングスクールでメンターをしている者です。
今回Actioncableを用いたリアルタイムグループチャット機能の第二部となっております。
第一部をまだ読んでいない方はぜひそちらの方を読んでいただければと思います。
【Rails6】ActionCableを用いたリアルタイムグループチャット機能① ~リアルタイムチャット完成まで~
#参考記事
Railsでグループチャット機能を実装
#本題
今回作成していくために使っている機能は以下の通りです。
- ユーザー認証・・・Devise
- リアルタイムチャットの実現・・・Actioncable
また第一部の実装が完了していることが前提となっております。
##作成順序
以下の手法で作成していきます。
- チャット機能の作成
- グループに参加するメンバーのみでチャットができるよう改良
第二部では、グループ作成→完成まで行います。
##開発環境
macOS Big Sur 11.4
Ruby2.7.4
Rails6.1.4.1
DB:sqlite3
##必要なファイルの作成
アソシエーション用に必要なファイルを作成していきます。
$ rails g controller room_users
$ rails g model room_user
class CreateRoomUsers < ActiveRecord::Migration[6.1]
def change
create_table :room_users do |t|
t.references :room, foreign_key: true
t.references :user, foreign_key: true
t.timestamps
end
end
end
$ rails db:migrate
##モデルファイルの修正
モデルファイルの修正を行います。
has_many :room_users, dependent: :destroy
has_many :rooms, through: :room_users, source: :room, dependent: :destroy
class Room < ApplicationRecord
has_many :messages
has_many :room_users, dependent: :destroy
has_many :users, through: :room_users, source: :user
end
class RoomUser < ApplicationRecord
belongs_to :room
belongs_to :user
end
参考:外部キー周りでエラーが出ることがあるのでご注意ください。
参考:アソシエーションはroomとuserが1:N、userとroomが1:N
##ルーティング
第一部のまま。
##コントローラーの作成
以下のようにコントローラーを書きます。
class RoomsController < ApplicationController
before_action :set_group, only: [:edit, :update]
def index
@room_lists = Room.all.order(:id)
@room_joining = RoomUser.where(user_id: current_user.id)
@room_lists_none = "You don't join any groups."
end
def new
@room = Room.new
@room.users << current_user
end
def create
@room = Room.new(room_params)
if @room.save
redirect_to rooms_path, notice: 'make a group.'
else
render :new
end
end
def show
@room = Room.find(params[:id])
@messages = @room.messages
end
def edit
# @group = Group.find(params[:id])
end
def update
# @group = Group.find(params[:id])
if @room.update(room_params)
redirect_to rooms_path, notice: 'update your group.'
else
render :edit
end
end
def destroy
delete_room = Room.find(params[:id])
if delete_room.destroy
redirect_to rooms_path, notice: 'delete your group.'
end
end
private
def set_group
@room = Room.find(params[:id])
end
def room_params
params.require(:room).permit(:roomname, user_ids: [])
end
end
before_actionの仕様に関しては自分で調べていただければと思います。
##ビューの作成
第一部とかぶっている所はありますが、以下のように記述しました。
デザインの導入で一部Bootstrapの機能を使っています。導入はしてもらった方が便利なのでぜひしてみてください。
Bootstrap公式記事
<h1>Real part</h1>
<div>
<ul>
<% @room_lists.each do |room| %>
<li><%= link_to "ROOM#{room.id}", room_path(room) %></li>
<% end %>
</ul>
</div>
<div class="chat-group">
<h1>All chat groups</h1>
<div class="group-search">
<div class="group-search-form">
<%= form_with(url: rooms_path, local: true) do |f| %>
<%= f.text_field :keyword, placeholder: "search for group", class: "group-search-form-input" %>
<%= f.submit 'search' %>
<% end %>
</div>
<div class="group-new">
<%= link_to 'make a group', new_room_path %>
</div>
<% if @room_joining == [] %>
<%= @room_lists_none %>
<% else %>
<div class="group-list">
<ul class="group-list-table">
<% @room_lists.each do |list| %>
<% if list.user_ids.include?(current_user.id) %>
<li class="group-list-table-each-group">
<%= link_to "/rooms/#{list.id}" do %>
<%= list.roomname %>(<%= list.user_ids.count %>)
<%= link_to 'edit', edit_room_path(list.id), method: :get %>
<%= link_to 'delete', room_path(list.id), method: :delete %>
<% end %>
</li>
<% end %>
<% end %>
</ul>
</div>
<% end %>
</div>
<div class="user-page">
<%#= link_to 'ユーザーページへ', current_user %>
</div>
</div>
<h1>Create new group</h1>
<%= form_with(model: @room, local: true) do |f| %>
<div class="group-new-form">
<div class="gtoup-new-form-name">
<%= f.label :roomname, 'group name' %>
<%= f.text_field :roomname, class: 'form-control' %>
<%= f.collection_check_boxes :user_ids, User.all, :id, :username %>
</div>
<%= f.submit '新規作成', class: "btn btn-primary" %>
</div>
<% end %>
<h1>edit group</h1>
<%= form_with(model: @room, local: true) do |f| %>
<div class="group-new-form">
<div class="gtoup-new-form-name">
<%= f.label :roomname, 'group name' %>
<%= f.text_field :roomname, class: 'form-control' %>
<%= f.collection_check_boxes :user_ids, User.all, :id, :username %>
</div>
<%= f.submit 'update', class: "btn btn-primary" %>
</div>
<% end %>
<h1>Real Chat room</h1>
<div id='messages' data-room_id="<%= @room.id %>">
<%= render @messages %>
</div>
<form>
<%= label_tag :content, 'Say something:' %>
<input type="text" data-behavior="room_speaker">
</form>
#完成
これでリアルタイムグループチャットの完成となります。
まだデザインを整えたらどのように動くか確認は出来ていないので、デザイン時にはあまりコードをいじらずにデザインしていただければと思います。
#おまけ
今回が私が実装したコードをgithubの方に載せています。
もし、エラーがでて詰まったという場合は参考にしてください。→参考コード
また今回第二部で載せさせていただいた参考記事とコメント機能を合わせると、リアルタイムではないですがグループチャットが完成できます。そちらのコードも載せているのでぜひ参考にしてみてください。