[RUBY] Créez une discussion d'équipe avec Rails Action Cable

introduction

J'ai créé une fonction de chat en équipe avec Action Cable dans le portefeuille, je vais donc la publier.

Article de référence

J'ai fait référence à l'article suivant. Merci beaucoup. ・ Fabriqué avec Rails 5 + Action Cable! Application de chat simple (de la vidéo de démonstration de DHH)[Rails 6.0] Créez une discussion en temps réel avec Action Cable et l'ensemble gourmand de Devise (version révisée)

code

Modifiez le code de l'article de référence pour envoyer une discussion à chaque équipe. Cette fois, nous allons créer une action de chat sur le contrôleur d'équipe afin que nous puissions envoyer des chats. Créez les pièces autres que le câble d'action selon la structure MVC.

model Le modèle décrit la relation plusieurs-à-plusieurs entre le modèle d'équipe et le modèle utilisateur. De plus, le modèle de message, qui est le contenu du chat, est créé comme modèle de la table intermédiaire entre l'utilisateur et l'équipe.

app/models/team.rb


class Team < ApplicationRecord #Modèle d'équipe
  belongs_to :owner, class_name: 'User', foreign_key: :owner_id
  has_many :team_assigns, dependent: :destroy 
  has_many :members, through: :team_assigns, source: :user
  has_many :messages, dependent: :destroy
end

app/models/user.rb


class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  has_one_attached :icon #Ajouter une icône d'utilisateur dans Active Storage
  has_many :team_assigns, dependent: :destroy
  has_many :teams, through: :team_assigns, source: :team
  has_one :owner_team, class_name: 'Team', foreign_key: :owner_id, dependent: :destroy
  has_many :messages, dependent: :destroy
end

app/models/team_assign.rb


class TeamAssign < ApplicationRecord
  belongs_to :team
  belongs_to :user
end

app/models/message.rb


class Message < ApplicationRecord
  belongs_to :user
  belongs_to :team
end

controller Le contrôleur a créé une action de chat au sein de l'équipe. Recevez l'ID d'équipe à partir du lien, recherchez dans la classe Team, obtenez le chat de l'équipe et transmettez-le à la vue.

app/controllers/teams_controller.rb


  def chat
    @team = Team.find(params[:id])
    messages = @team.messages
  end

view Depuis que j'ai appliqué le bootstrap, j'utilise un conteneur, une alerte, etc. Fondamentalement, le chat reçu est affiché à l'écran en rendant un message partiel. Nous avons également un formulaire pour envoyer des chats.

html:app/views/teams/chat.html.erb


<h1 id="chat" data-team_id="<%= @team.id %>">
  <%= @team.name %>Tchat
</h1>

<div class="container">
  <% if @team.members.count == 1 %>
    <div class="alert alert-danger" role="alert">
Il n'y a aucun membre de l'équipe avec qui discuter. Ajouter des membres depuis l'écran d'équipe
    </div>
  <% end %>
  <form class="form-group">
    <label>bavarder:</label>
    <input type="text" data-behavior="team_speaker", placeholder="Contenu", class="form-control">
  </form>
  <div id="messages_<%= @team.id %>">
    <ul class="list-group">
      <%= render @messages %>
    </ul>
  </div>
</div>

html:app/views/messages/_message.html.erb


<div class="message">
  <li class="list-group-item">
    <div class="row">
      <div class="col-md-2">
        <% if message.user.icon.attached? %>
          <%= image_tag message.user.icon.variant(resize:'50x50').processed %>
        <% end %>
        <p><%= message.user.name %></p>
      </div>
      <div class="col-md-10">
        <small class="text-muted"><%= l message.created_at, format: :short %></small><br>
        <%= message.content %>
      </div>
    </div>
  </li>
</div>

De là, implémentez Action Cable. Tout d'abord, créez un canal d'équipe. Des répertoires et des fichiers sont créés pour le canal.

$ rails g channel team

coffeescript Tout d'abord, décrivez les paramètres de surveillance du serveur à partir du navigateur. Utilisez jQuery pour obtenir l'ID d'équipe de la vue et créer un canal auquel vous abonner.

app/assets/javascripts/channels/team.coffee


App.team = App.cable.subscriptions.create {
  channel: "TeamChannel",
  team_id: $("#chat").data("team_id")}, 

  connected: ->
    # Called when the subscription is ready for use on the server

  disconnected: ->
    # Called when the subscription has been terminated by the server

  received: (data) ->
    #Recevoir le chat reçu par la méthode Speak du côté Channel
    $('#messages_'+data['team_id']).prepend data['message']

  speak: (message) ->
    team_id = $('#chat').data('team_id')
    @perform 'speak', message: message, team_id: team_id

$(document).on 'keypress', '[data-behavior~=team_speaker]', (event) ->
  if event.keyCode is 13 # return = send
    App.team.speak event.target.value
    event.target.value = ''
    event.preventDefault()

channel.rb Ensuite, décrivez les paramètres de surveillance du navigateur à partir du serveur. @Perform speak du navigateur appelle l'action de parole côté serveur. L'action de parole crée une instance de la classe de message en fonction des informations reçues du navigateur.

app/channels/team_channel.rb


class TeamChannel < ApplicationCable::Channel
  def subscribed
    stream_from "team_channel_#{params['team_id']}" #Montrez quelle équipe vous surveillez
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def speak(data)
    message = Message.create!(
      content: data['message'],
      team_id: data['team_id'],
      user_id: current_user.id
    )
  end
end

J'utilise current_user dans le canal, mais pour cela, je dois ajouter le code suivant.

app/channels/application_cable/connection.rb


module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

      def find_verified_user
        verified_user = User.find_by(id: env['warden'].user.id)
        return reject_unauthorized_connection unless verified_user
        verified_user
      end
  end
end

Modèle de message

Fait exécuter la tâche lorsqu'une instance est créée dans le modèle Message (après validation).

app/models/message.rb


class Message < ApplicationRecord
  belongs_to :user
  belongs_to :team
  after_create_commit { MessageBroadcastJob.perform_later self } #Postscript
end

job Décrivez les paramètres pour envoyer le message créé du travail au navigateur. Commencez par créer un travail de diffusion de message à partir de la commande rails.

$ rails g job MessageBroadcast

Si vous utilisez ActiveStorage et que vous ne spécifiez pas http_host dans ApplicationController.renderer, la destination de référence d'image entraînera une erreur. Si vous souhaitez utiliser une URL commençant par https: // au lieu de http: // en production, vous devez spécifier https: true.

app/jobs/message_broadcast_job.rb


class MessageBroadcastJob < ApplicationJob
  queue_as :default

  def perform(message)
    ActionCable.server.broadcast(
      "team_channel_#{message.team_id}",
      message: render_message(message),
      team_id: message.team_id
    )
  end

  private
    def render_message(message)
      renderer = ApplicationController.renderer.new(
        http_host: 'http_numéro d'hôte', #Local, localhost:3000. Modifié en fonction de l'environnement de production
    #https: true          https://Pour les URL commençant par, vous devez ajouter ce code
      )
      renderer.render(partial: 'messages/message', locals: { message: message })
    end
end

Par ce travail, la partie du message est transmise à la réception de coffeescript et réfléchie en temps réel.

Résumé

Je pensais qu'ActionCable était compliqué, mais j'ai pu suivre et comprendre le passage des données par référence. De cette expérience, j'ai réalisé à nouveau qu'il est important de suivre le flux de données un par un même si cela semble compliqué, et c'est le meilleur raccourci pour utiliser binding.pry côté serveur et débogueur côté navigateur. ..

Recommended Posts

Créez une discussion d'équipe avec Rails Action Cable
[Rails6] Créer une nouvelle application avec Rails [Débutant]
[Retrait des rails] Créez une fonction de retrait simple avec des rails
[Rails 5] Créer une nouvelle application avec Rails [Débutant]
[Rails] rails nouveau pour créer une base de données avec PostgreSQL
Créer un site EC avec Rails 5 ⑨ ~ Créer une fonction de panier ~
Créez une application de chat avec WebSocket (Tyrus) + libGDX + Kotlin
Créez un terrain de jeu avec Xcode 12
Tutoriel pour créer un blog avec Rails pour les débutants Partie 1
[Rails] J'ai essayé de créer une mini application avec FullCalendar
Une série d'étapes pour créer des livrables pour les portefeuilles avec Rails
Tutoriel pour créer un blog avec Rails pour les débutants Partie 2
Tutoriel pour créer un blog avec Rails pour les débutants Partie 0
Créez un environnement Vue3 avec Docker!
Créer un portfolio avec rails + postgres sql
[Tutoriel Rails Chapitre 5] Créer une mise en page
Créer une nouvelle application avec Rails
Créer ma page avec Rails
Créez des exceptions avec une interface fluide
Créer un site EC avec Rails5 ② ~ Paramètres Bootstrap4, définition du contrôleur / action ~
Créez un fichier jar avec la commande
Créez une application Web simple avec Dropwizard
Construire un environnement Rails 6 + MySQL avec Docker compose
Créez un lot à la demande simple avec Spring Batch
[Ruby on Rails] Créez un graphique circulaire des totaux par colonne avec Chartkick
Créer un graphique à barres simple avec MPAndroidChart
Créez une classe temporaire avec le nouvel Object () {}
Créez quand même une fonction de connexion avec Rails
Créez une application de résumé de nouvelles techniques de style LINEnews avec Rails x LineBot! [Partie 1]
[rails] Comment créer un modèle partiel
Créez un site Web avec Spring Boot + Gradle (jdk1.8.x)
[Memo] Créez facilement un environnement CentOS 8 avec Docker
Créer un CSR avec des informations étendues en Java
Créez un tableau d'affichage simple avec Java + MySQL
[Windows] [IntelliJ] [Java] [Tomcat] Créer un environnement pour Tomcat 9 avec IntelliJ
[Rails] Comment créer un graphique à l'aide de lazy_high_charts
[Java] Créer une collection avec un seul élément
Créer un compte SandBox avec IP Fastlane Spaces
Faisons une fonction de recherche avec Rails (ransack)
Créer une carte multi-touches avec une bibliothèque standard
Comment créer facilement un pull-down avec des rails
[Rails] Comment créer un bouton de partage Twitter
Créer un site EC avec Rails5 ⑤ ~ Modèle client ~
J'ai créé un robot LINE avec Rails + heroku
Créer un serveur API Web avec Spring Boot
Créer un site EC avec Rails 5 ⑩ ~ Créer une fonction de commande ~
Créer un environnement de développement Spring Boot avec docker
J'ai fait un portfolio avec Ruby On Rails
Commande Docker pour créer un projet Rails avec un seul coup dans l'environnement sans Ruby
[Introduction] Créer une application Ruby on Rails