学生向けプログラミング入門

学生向けにプログラミングを解説。Java、C++、Ruby、PHP、データベース、Ruby on Rails, Python, Django

Ruby on Rails6.0 | フリーランスの仕事を登録・購入できるWebサイトを作成する 48 | メッセージと会話 | リアルタイムメッセージ

[47]メッセージと会話 | 会話 << [ホームに戻る] >> [49]メッセージと会話| コメント


メッセージをリアルタイムで送りあうことができるようにします。


コマンド
rails g channel Message


ルートの設定をします。


記述追加 config\routes.rb
36行目に「mount ActionCable.server => '/cable'」の記述を追加しています。

Rails.application.routes.draw do

  # ルートを app\views\pages\home.html.erb に設定
  root 'pages#home'

  devise_for :users, 
              path: '', 
              path_names: {sign_up: 'register', sign_in: 'login', edit: 'profile', sign_out: 'logout'},
              controllers: {omniauth_callbacks: 'omniauth_callbacks', registrations: 'registrations'}

  get 'pages/home'
  get '/dashboard', to: 'users#dashboard'
  get '/users/:id', to: 'users#show', as: 'users'
  get '/selling_orders', to: 'orders#selling_orders'
  get '/buying_orders', to: 'orders#buying_orders'
  get '/all_requests', to: 'requests#list'
  get '/request_offers/:id', to: 'requests#offers', as: 'request_offers'
  get '/my_offers', to: 'requests#my_offers'
  get '/search', to: 'pages#search'
  get 'settings/payment', to: 'users#payment', as: 'settings_payment'
  get 'settings/payout', to: 'users#payout', as: 'settings_payout'
  get '/gigs/:id/checkout/:pricing_type', to: 'gigs#checkout', as: 'checkout'
  get '/conversations', to: 'conversations#list', as: "conversations"
  get '/conversations/:id', to: 'conversations#show', as: "conversation_detail"

  post '/users/edit', to: 'users#update'
  post '/offers', to: 'offers#create'
  post '/reviews', to: 'reviews#create'
  post '/settings/payment', to: 'users#update_payment', as: "update_payment"
  post 'messages', to: 'messages#create'

  put '/orders/:id/complete', to: 'orders#complete', as: 'complete_order'
  put '/offers/:id/accept', to: 'offers#accept', as: 'accept_offer'
  put '/offers/:id/reject', to: 'offers#reject', as: 'reject_offer'

  mount ActionCable.server => '/cable'

  resources :gigs do
    member do
      delete :delete_photo
      post :upload_photo
    end
    resources :orders, only: [:create]
  end

  resources :requests

  # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html
end



「app\channels\message_channel.rb」ファイルの記述を以下のように変更します。


記述変更 app\channels\message_channel.rb

class MessageChannel < ApplicationCable::Channel
  def subscribed
    conversation = Conversation.find params[:conversation]
    stream_for conversation
  end
end



「app\controllers\messages_controller.rb」ファイルに記述を追加します。


記述追加 app\controllers\messages_controller.rb
20~36行目、41~43行目に記述を追加しています。
コードをコピーしてファイルの内容を置き換えて下さい。

class MessagesController < ApplicationController
  def create
    if current_user.id == message_params[:receiver_id]
      redirect_to request.referrer, alert: "自分にメッセージを送ることはできません"
    end

    conversation = Conversation.where("(sender_id = ? AND receiver_id = ?) OR (sender_id = ? AND receiver_id = ?)",
                                      current_user.id, message_params[:receiver_id], 
                                      message_params[:receiver_id], current_user.id
                                    ).first
    if !conversation.present?
      conversation = Conversation.create(sender_id: current_user.id, receiver_id: message_params[:receiver_id])
    end

    @message = Message.new(user_id: current_user.id, 
                           conversation_id: conversation.id,
                           content: message_params[:content]
    )

    if @message.save
      conversation.update!(updated_at: @message.created_at)
      receiver = conversation.sender.id == current_user.id ? conversation.receiver : conversation.sender

      MessageChannel.broadcast_to conversation, 
                                  sender_id: current_user.id, 
                                  sender: render_message(@message, current_user),
                                  receiver: render_message(@message, receiver)

      if URI(request.referrer).path == conversation_detail_path(id: receiver.id)
        return render json: {success: true}
      end

      redirect_to request.referrer, notice: "メッセージを送りました"
    else
      redirect_to request.referrer, alert: "メッセージを送れませんでした"
    end
  end

  private

  def render_message(message, user)
    self.render_to_string partial: 'conversations/message', locals: {m: message, user: user}
  end

  def message_params
    params.require(:message).permit(:content, :receiver_id)
  end
end



「app\javascript\channels\message_channel.js」ファイルを以下のように編集します。


記述編集 app\javascript\channels\message_channel.js

import consumer from "./consumer"

$(document).on('turbolinks:load', () => {
    $('[data-channel-subscribe="conversation"]').each(function(index, element) {
        var $element = $(element),
            $chatList = $('#message_list'),
            $form = $('#new_message'),

            conversation_id = $element.data('conversation-id'),
            user_id = $element.data('user-id')

        consumer.subscriptions.create(
            {
                channel: "MessageChannel",
                conversation: conversation_id
            },
            {
                received: function(data) {
                    if (data.sender_id == user_id) {
                        $chatList.append(data.sender)
                    } else {
                        $chatList.append(data.receiver)
                    }

                    $form[0].reset();
                    $chatList.animate({ scrollTop: $chatList.prop("scrollHeight") }, 1000)
                }
            }
        )
    });
});



ブラウザ確認
http://localhost:3000/conversations


メッセージを送るとリアルタイムで表示できるようになりました。

リアルタイムメッセージ
リアルタイムメッセージ



[47]メッセージと会話 | 会話 << [ホームに戻る] >> [49]メッセージと会話| コメント