LoginSignup
15
17

More than 5 years have passed since last update.

ほぼCRUDのみの知識でチャット機能を実装

Posted at

ちょっとずつ色々いじれるようになってきたポンコツ大学生エンジニアが助けを経て頑張ってチャット機能を実装してみました🙇
Railsの勉強をはじめて半年ほどですので、理解が至らないことや間違いなどあると思うので指摘していただけるとありがたいです(^^)

チャット機能を作るということは....

まず自分と相手がいないと始まりません!
なので、認証機能を作ってcurrent_userで今ログインしているuserを得られるとします

また、チャットが始まる、ということは同時にチャットルームもできるということです。なので 

$bin/rails g model user
$bin/rails model chat_user
$bin/rails g model chat
$bin/rails g model message

で、まず必要となるモデルを設計します
user、message,chatモデルは当然必要ですが、
chatとuserは多対多の関係であるので、中間テーブルであるchat_user.rbを作っておきます

で、モデルのアソシエーションは以下のようにしておきます

userは多くのchat,messageを持ち
chatもまた多くのuserを持ち
messageはuserにbelongs_toする。

といったところですね😎

model/user.rb

class User < ActiveRecord::Base

  has_many :chat_users 
  has_many :messages
  has_many :chats, through: :chat_users 

end
model/chat.rb
class Chat < ActiveRecord::Base

  has_many :chat_users
  has_many :users, through: :chat_users
  has_many :messages

end
model/chat_user.rb
class ChatUser < ActiveRecord::Base

  belongs_to :chat
  belongs_to :user

end

そしてマイグレーションファイルです

db/migrate/init_shema

lass InitSchema < ActiveRecord::Migration
  def change
    create_table(:users) do |t|

        t.string :email, null: false
        t.string :name, null: false
        t.string :password_digest
        t.string :remember_digest
    end

    create_table :chats do |t|
        t.integer :service_id, null: false, index: true
        t.integer :cny, null: false
        t.datetime :start_at#, null: false
        t.timestamps null: false
    end

    create_table :chat_users do |t|
        t.integer :user_id, null: false
        t.integer :chat_id, null: false
    end

    create_table :messages do |t|
        t.integer :user_id, null: false
        t.integer :chat_id, null: false
        t.text :contents, null: false
        t.date :created_at, null: false
    end

##本来でしたらindexなども貼ったり、いろいろ改善点はありますがいったんこれで最小限のmigrationにしておきます

end

実際にチャット機能を始めるための実装

まずroutingを作ります

config/routes.rb
Rails.application.routes.draw do

  resources :users
  resources :chats

end

とりあえず、雑ではありますがチャットできるuserのスコープをuser全体にして誰とででも会話をできるようにします
@users = User.allですね

controller/users_controller.rb
class UsersController < ApplicationController

  def index
    @users = User.all
    @chat = Chat.new
  end
end

そしてviewです
楽するため簡単に書きますが、new_chat_pathのparamsとしてそのuserのidを持たせ、
そしてそのidを自動的にheidden_fieldを使ってchatのcreateに飛ばします

users/index.html.haml
.container
  .row
    - @users.each do |user|
      %ul
        %li= link_to user.name, new_chat_path(reciever_id: user.id)
      = form_for @chat, url: chats_path, html: {role: 'form', class:"form-horizontal"} do |f|
        = f.hidden_field :reciever_id, value: params[:reciever_id]
      .form-group
        .col-sm-offset-3
          .col-sm-9= f.submit "このサービスで登録", class:"btn btn-primary"

で、このformがcreateで送信されてチャットルームができ、かつそのルームにuserが入ってこなくてはいけないので、chat.rbに次のメソッドを追加します

model/chat.rb

class Chat < ActiveRecord::Base
  has_many :chat_users
  has_many :users, through: :chat_users
  has_many :service_categories
  has_many :messages


   ##追加分##
  def join(user_id)
    self.chat_users.create(user_id: user_id)
  end

そしてcreateアクションの中身です😇

controller/chats_controller.rb
class ChatsController < ApplicationController
  def create
    @chat = Chat.create
    @chat.join(current_user.id)
    @chat.join(params[:chat][:reciever_id])
    redirect_to @chat
  end
end

redirectされたchat#showを追加します

chats_controller.rb

  def show
    @chat = Chat.find(params[:id])
    @message = Message.new
    @message_logs = @chat.messages#チャットが持つmesaage、すなわちチャットログです
  end 

そしてここで、userが実際にチャットをするので、Message.newに情報を送信するformが必要です

chats/show.html.haml
.container
  .row
    - @message_logs.each do |message|
      %p= message.contents
    = form_for @message, url: messages_path, html: {role: 'form', class:"form-horizontal"} do |f|
      .form-group
        = f.label :contents, class: "col-sm-3 control-label"
        .col-sm-9= f.text_area :contents, class: "form-control"
      .form-group
        = f.hidden_field :chat_id, value: @chat.id
      .form-group
        .col-sm-4.col-sm-offset-3= f.submit "この内容で送信する", class:"btn btn-primary transition"

そしてこの情報をMessageに格納するためのmessage#createが必要ですね

messages_controller.rb
class MessagesController < ApplicationController

  def create
    @message = current_user.messages.create(message_params)
    redirect_to :back if @message.save
  end


  private

  def message_params
    params.require(:message).permit(
    :chat_id,
    :user_id,
    :contents,
    :chat_id
    )
  end
end

最低限のチャット機能の完成です!!😇

15
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
17