Rails 6와 Action Cable이 있는 간단한 채팅방입니다.

안녕하십니까,
이번 주에는 Rails 6와 ActionCable로 간단한 채팅방을 구축합니다.우리는 ActionCable이 어떻게 작동하는지, 그리고 Rails에서 어떻게 사용하는지 배울 것입니다.Ruby와 Rails에 대해 기본적으로 알고 있어야 공부를 계속할 수 있습니다.우리는 사용자에 대한 신분 검증도 하지 않고 데이터베이스에 메시지를 저장하지 않기 때문에 어떤 메시지도 오래 지속되지 않으면 익명 채팅방처럼 될 것이다.

소개


루비 가이드에 따르면:

Action Cable seamlessly integrates WebSockets with the rest of your Rails application. It's a full-stack offering that provides both a client-side JavaScript framework and a server-side Ruby framework.


WebSocket은 클라이언트와 서버 간의 지속적인 연결을 제공하여 쌍방이 언제든지 데이터를 보내기 시작할 수 있습니다.참고 자료 부분에서 WebSocket에 대한 더 많은 읽기 링크를 제공할 것입니다.다음은 루비가이드에서 주의해야 할 몇 가지 요점과 설명입니다.
  • 사용자는 WebSocket 연결
  • 클라이언트
  • 소비자는 여러 개의 유선 텔레비전 채널을 구독할 수 있다
  • 소비자가 채널을 구독할 때 구독자 역할을 한다
  • 구독자와 채널 간의 연결을 구독이라고 부른다
  • 그리고 채널당 0개 이상의 방송을 다시 스트리밍할 수 있음
  • 방송은 일종의pubsub 체인으로 이 체인에서 방송사가 전송하는 모든 내용은 유동식 전송을 하고 있는 채널 사용자에게 직접 발송되며 이 채널 사용자는 방송
  • 으로 명명된다
    한 마디로 하면 클라이언트가 WebSocket 연결을 시작합니다.이 연결은 클라이언트와 서버 사이에서 데이터를 보내고 받을 수 있는 전용 라인과 같습니다.ActionCable를 통해 채널을 구독했습니다. 지금은 asubscriber라고 불립니다.다른 사람들도 이 채널을 연결하고 구독할 것이다.구독자가 메시지를 보낼 때, 구독자 모두에게 방송됩니다.

    응용 프로그램 설정


    컨트롤러에서 rails 명령을 실행하고postgresql 데이터베이스로 새로운 프로그램을 만듭니다.
    $ rails new chat_room --database=postgresql
    
    Cd를 폴더에 넣고 데이터베이스 만들기
    $ cd chat_room
    $ rails db:create
    
    다음은 페이지를 디자인합시다.중요한 내용에 집중할 수 있도록 CSS 라이브러리를 사용하고 싶지 않습니다.
    색인 동작으로 메인 컨트롤러를 만듭니다.
    $ rails g controller Home index
    
    라우팅 파일에서 get 요청을 루트 경로로 변경합니다.
    # config/routes.rb
    
    root 'home#index'
    
    home/index.html.erb 파일에 다음 코드 추가
    <div id="main">
      <h2>Chat room</h2>
      <div>
        <div id="messages">
          <p class="received">Hello</p>
          <p class="sent">Hi</p>
          <p class="received">How are you doing?</p>
          <p class="sent">I am doing alright</p>
        </div>
        <form id="send_message">
          <input type="text" id="message" name="message">
          <button>Send</button>
        </form>
      </div>
    </div>
    
    application.css의 일부 CSS
    body {
      padding: 0;
      margin: 0;
    }
    
    h2 {
      margin: 0;
    }
    
    home.scss 파일의 CSS
    #main {
      height: 100vh;
      background-color: bisque;
      overflow: auto;
    
      h2 {
        text-align: center;
        margin-top: 20px;
        margin-bottom: 20px;
      }
    
      >div {
        height: 90vh;
        background-color: black;
        width: 80%;
        margin: auto;
        border-radius: 5px;
        overflow: auto;
        position: relative;
    
        div#messages {
          height: 90%;
          width: 95%;
          color: white;
          margin: 14px auto;
          overflow: auto;
          display: flex;
          flex-direction: column;
    
          p {
            display: inline-block;
            padding: 10px;
            border-top-left-radius: 10px;
            border-top-right-radius: 10px;
            margin-bottom: 5px;
            margin-top: 5px;
            max-width: 70%;
            width: max-content;
    
            &.received {
              background-color: chocolate;
              border-bottom-right-radius: 10px;
            }
    
            &.sent {
              border-bottom-left-radius: 10px;
              background-color: darkred;
              align-self: flex-end;
            }
          }
        }
    
        form#send_message {
          width: 95%;
          margin: auto;
    
          input {
            height: 30px;
            width: 90%;
            border-radius: 10px;
            border: 0;
          }
    
          button {
            height: 35px;
            width: 8.8%;
            border-radius: 20px;
            border: 0;
            background-color: tomato;
            color: white;
          }
        }
      }
    }
    
    우리는 아래에 그다지 예쁘지 않은 사용자 인터페이스가 있어야 한다.

    룸 채널 구현


    응용 프로그램에 jquery를 추가하고 설정합시다
    $ yarn add jquery
    
    환경에 jquery를 포함하기 위해 패키지 설정을 업데이트합니다
    // config/weboack/environment.js
    
    const webpack = require('webpack')
    environment.plugins.prepend('Provide',
      new webpack.ProvidePlugin({
        $: 'jquery/src/jquery',
        jQuery: 'jquery/src/jquery'
      })
    )
    
    jquery 액세스 필요 application.js 파일
    // app/javascript/packs/application.js
    
    require("jquery")
    
    다음으로, 우리는 우리의 채널을 생성한다
    $ rails g channel chat_room
    
    이것은 chat_room_channel.rbchat_room_channel.js 을 포함한 일부 파일을 생성합니다.이것은 우리가 변경할 두 개의 파일입니다.
    채널 설정이 올바른지 확인하기 위해 파일에 부차적인 코드를 추가합니다.
    # app/channels/chat_room_channel
    def subscribed
      stream_from "chat_room_channel"
    end
    
    // app/javascript/channels/chat_room_channel.js
    
    connected() {
        // Called when the subscription is ready for use on the server
        console.log("Connected to the chat room!");
      },
    
    서버를 시작하고 방문localhost:3000하면 저희 메시지가 컨트롤러에 기록되는 것을 보실 수 있습니다.
    우리 얘기 좀 하자.
    새로운 방송 방법을 포함하여 우리의 메시지를 표시하는 chat_room_channel.js 방법으로 업데이트하십시오.다른 자바스크립트 파일에서speak 방법에 접근할 수 있도록 received 내보내야 합니다.
    // app/javascript/channels/chat_room_channel.js
    import consumer from "./consumer"
    
    const chatRoomChannel = consumer.subscriptions.create("ChatRoomChannel", {
      connected() {
        // Called when the subscription is ready for use on the server
        console.log("Connected to the chat room!");
      },
    
      disconnected() {
        // Called when the subscription has been terminated by the server
      },
    
      received(data) {
        $('#messages').append('<p class="received"> ' + data.message + '</p>')
      },
    
      speak(message) {
        this.perform('speak', { message: message })
      }
    });
    
    export default chatRoomChannel;
    
    저희 ChatRoomChannel 에서 채널을 가져오고 이벤트 탐지기를 폼에 추가합니다.폼을 제출할 때, 입력 필드의 값을 가져와 application.js 방법에 전달합니다.이벤트 탐지기는 입력 필드의 내용도 삭제합니다.
    // app/javascript/packs/application.js
    
    // other code
    import chatRoomChannel from "../channels/chat_room_channel";
    
    $(document).on('turbolinks:load', function () {
      $("form").on('submit', function(e){
        e.preventDefault();
        let message = $('#message').val();
        if (message.length > 0) {
          chatRoomChannel.speak(message);
          $('#message').val('')
        }
      });
    })
    
    페이지를 다시 불러오면 메시지를 볼 수 있습니다.

    하지만 우리에게는 작은 문제가 하나 있다.메시지 발송자에 대해서도 모든 메시지가 왼쪽에 표시되어 수신된 메시지로 표시됩니다.우리는 송신자와 수신자를 구분할 수 있어야 한다.우리는 신분 검증을 사용하거나 데이터베이스에 저장하지 않았기 때문에, 우리는 어떤 방식으로 모든 사람을 식별할 수 있어야 한다.
    나는 간단한 해결 방안이 하나 있다.sessionStorage에 저장할 이름을 추가하기 위해 모든 사람을 위한 모드를 추가해야 합니다.sessionStorage를 사용하는 것은 사용자가 탭을 닫은 후에 세션을 지우기를 원하기 때문입니다. localStorage는 이렇게 하지 않습니다.우리는 또한 사용자가 가입하거나 채널을 떠날 때 사용자를 발표할 것이다.
    패턴 메시지를 포함하여 파일을 업데이트하고 앞에 추가된 정적 메시지를 삭제합니다.
    <div id="main">
      <h2>Chat room</h2>
      <div id="chat_body">
        <div id="messages">
        </div>
        <form id="send_message">
          <input type="text" id="message" name="message">
          <button>Send</button>
        </form>
      </div>
      <div id="modal">
        <div>
          <h4>Add a name</h4>
          <form id="set_name">
            <input type="text" id="add_name" name="add_name">
            <button>Submit</button>
          </form>
        </div>
      </div>
    </div>
    
    우리는 또한 사용자가 언제 가입하거나 방을 떠날 것인지를 알리기 위해 speak 파일을 업데이트할 것이다.모든 메시지의 표시 방식을 포맷할 수 있도록 index.html.erb 방법을 업데이트할 것입니다.
    import consumer from "./consumer"
    
    const chatRoomChannel = consumer.subscriptions.create("ChatRoomChannel", {
      connected() {
        console.log("Connected to the chat room!");
        $("#modal").css('display', 'flex');
      },
    
      disconnected() {
    
      },
    
      received(data) {
        if (data.message) {
          let current_name = sessionStorage.getItem('chat_room_name')
          let msg_class = data.sent_by === current_name ? "sent" : "received"
          $('#messages').append(`<p class='${msg_class}'>` + data.message + '</p>')
        } else if(data.chat_room_name) {
          let name = data.chat_room_name;
          let announcement_type = data.type == 'join' ? 'joined' : 'left';
          $('#messages').append(`<p class="announce"><em>${name}</em> ${announcement_type} the room</p>`)
        }
      },
    
      speak(message) {
        let name = sessionStorage.getItem('chat_room_name')
        this.perform('speak', { message, name })
      },
    
      announce(content) {
        this.perform('announce', { name: content.name, type: content.type })
      }
    });
    
    export default chatRoomChannel;
    
    다음은 업데이트된 css 파일입니다.
    // Place all the styles related to the Home controller here.
    // They will automatically be included in application.css.
    // You can use Sass (SCSS) here: https://sass-lang.com/
    #main {
      height: 100vh;
      background-color: bisque;
      overflow: auto;
    
      h2 {
        text-align: center;
        margin-top: 20px;
        margin-bottom: 20px;
      }
    
      >div#chat_body {
        height: 90vh;
        background-color: black;
        width: 80%;
        margin: auto;
        border-radius: 5px;
        overflow: auto;
        position: relative;
    
        div#messages {
          height: 90%;
          width: 95%;
          color: white;
          margin: 14px auto;
          overflow: auto;
          display: flex;
          flex-direction: column;
    
          p {
            display: inline-block;
            padding: 10px;
            border-top-left-radius: 10px;
            border-top-right-radius: 10px;
            margin-bottom: 5px;
            margin-top: 5px;
            max-width: 70%;
            width: max-content;
    
            &.received {
              background-color: chocolate;
              border-bottom-right-radius: 10px;
            }
    
            &.sent {
              border-bottom-left-radius: 10px;
              background-color: darkred;
              align-self: flex-end;
            }
    
            &.announce {
              align-self: center;
              font-style: italic;
              color: cyan;
    
              em {
                font-weight: 700;
                color: mediumorchid;
              }
            }
          }
        }
    
        form#send_message {
          width: 95%;
          margin: auto;
    
          input {
            height: 30px;
            width: 90%;
            border-radius: 10px;
            border: 0;
          }
    
          button {
            height: 35px;
            width: 8.8%;
            border-radius: 20px;
            border: 0;
            background-color: tomato;
            color: white;
          }
        }
    
      }
      div#modal {
        height: 100vh;
        position: absolute;
        top: 0;
        background-color: #000000bf;
        width: 100%;
        z-index: 2;
        display: flex;
        display: none;
    
        >div {
          width: 300px;
          background: white;
          margin: auto;
          padding: 30px;
          text-align: center;
          height: 150px;
          border-radius: 10px;
    
          input {
            height: 30px;
            border-radius: 10px;
            border: 2px dotted rebeccapurple;
            width: 100%;
            margin-bottom: 10px;
          }
    
          button {
            height: 35px;
            border-radius: 20px;
            border: 0;
            background-color: #673AB7;
            color: white;
            width: 80px;
          }
        }
      }
    }
    
    우리는 언제 누군가가 떠나고 언제 누군가가 가입했는지 알 수 있도록 우리의 chat_room_channel.js 를 업데이트해야 한다.
    import chatRoomChannel from "../channels/chat_room_channel";
    
    $(document).on('turbolinks:load', function () {
      $("form#set_name").on('submit', function(e){
        e.preventDefault();
        let name = $('#add_name').val();
        sessionStorage.setItem('chat_room_name', name)
        chatRoomChannel.announce({ name, type: 'join'})
        $("#modal").css('display', 'none');
      });
    
      $("form#send_message").on('submit', function(e){
        e.preventDefault();
        let message = $('#message').val();
        if (message.length > 0) {
          chatRoomChannel.speak(message);
          $('#message').val('')
        }
      });
    
      $(window).on('beforeunload', function() {
        let name = sessionStorage.getItem('chat_room_name')
        chatRoomChannel.announce({ name, type: 'leave'})
      });
    })
    
    마지막으로 received 파일을 업데이트하여 application.js 방법을 포함해야 합니다.
    # app/channels/chat_room_channel.rb
    
    class ChatRoomChannel < ApplicationCable::Channel
      def subscribed
        stream_from "chat_room_channel"
      end
    
      def unsubscribed
        # Any cleanup needed when channel is unsubscribed
      end
    
      def speak(data)
        ActionCable.server.broadcast "chat_room_channel", message: data["message"], sent_by: data["name"]
      end
    
      def announce(data)
        ActionCable.server.broadcast "chat_room_channel", chat_room_name: data["name"], type: data["type"]
      end
    end
    
    이름 추가

    네가 방에 가입할 때, 너에게 통지할 것이다

    구독자 두 명 사이를 간단히 오가다.사용자가 채널을 떠날 때 통지됩니다

    이 강좌는 끝났습니다.
    만약 평론 부분에 문제가 있으면 저에게 알려주세요.
    다음 주까지.
    환매에 연결 https://github.com/Nkemjiks/chat_room

    리소스


    Action Cable Overview - RubyGuide
    An Introduction to WebSockets - Treehouse
    Creating a Chat Using Rails' Action Cable

    좋은 웹페이지 즐겨찾기