At-mention notifications with Rails Actioncable



  • Giới thiệu

    Trong ứng dụng chat cũng như mạng xã hội thường có chức năng mention (@) để notify hoặc thông báo đến người đó là bạn muốn mention đến. Ví dụ khi chat, bạn muốn mention đến userA sẽ là "@userA Good morning", ....
    Hôm này mình sẽ làm demo về chức năng mention trong Rails sử dụng actioncable.

    Implement

    Có rất nhiều bài viết về actioncable trong chat, ... Bây giờ mình sẽ không giới thiệu chi tiết về actioncable nữa. Mình sẽ hướng dẫn luôn về cách làm chức năng mention luôn.

    Subscribe channel

    Đầu tiên, phải subscribe vào channel như sau. Khi có broadcast đến channel đó, bạn sẽ nhận được thông tin gửi đến.

    app/channels/room_channel.rb
     class RoomChannel < ApplicationCable::Channel
      def subscribed
        stream_from "room_channel_user_#{current_user.id}"
      end
    
      def unsubscribed
        # Any cleanup needed when channel is unsubscribed
      end
    end
    

    Làm mention như thế nào?

    Ý tưởng là bạn cần dùng regex để lấy được các từ mà người ta mention, tức là từ ngay sau @.
    Vào rails console để thử nhé:

    $ rails console
    >>  NAME_REGEX = /@(\w+)/
    >> content = "This mentions @alice and @bob, and also @nonexistent"
    
    >> content = content.scan(NAME_REGEX)
    => [["alice"], ["bob"], ["nonexistent"]]
    
    >> mention_names = content.flatten
    => ["alice", "bob", "nonexistent"]
    
    // tìm user có tên trong content
    >> mention_names.map do |username|
    ?>   User.find_by(username: username)
    >> end.compact
    => [#<User id: 1, username: "alice"...>, #<User id: 2, username: "bob"]
    

    Đến đây là mình có thể tạo hàm mention được rồi.

    app/models/message.rb
    class Message < ApplicationRecord
    NAME_REGEX = /@(\w+)/
    
      belongs_to :user
      validates :content, presence: true
        
      // trả về danh sách users đã mention trong message content
      def mentions
        content.scan(NAME_REGEX).flatten.map do |username|
          User.find_by(username: username)
        end.compact
      end
    end
    

    Thực hiện broadcast và nhận kết quả

    Sau khi tạo message thành công, mình sẽ broadcast tới channel của các users trong danh sách đã mention.

    app/controllers/messages_controller.rb
     class MessagesController < ApplicationController
      .
      .
      .
      def create
        message = current_user.messages.build(message_params)
        if message.save
          message.mentions.each do |user|
            ActionCable.server.broadcast "room_channel_user_#{user.id}", content: "#{message.user.name} đã mention bạn."
          end
        end
      end
      .
      .
      .
    end
    

    Khi broadcast được thực hiện, user trong danh sách được mention đó sẽ nhận được data gửi về channel RoomChannel của họ.

    app/assets/javascripts/channels/room.coffee
     App.room = App.cable.subscriptions.create "RoomChannel",
        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) ->
          alert(data.content);
    

    Khi có người mention bạn, bạn sẽ nhận được alert lên là "User đã mention bạn."
    Đến đây, bạn sẽ hoàn thành chức năng mention rồi.

    References:

    https://www.learnenough.com/action-cable-tutorial

    https://viblo.asia/p/using-reactjs-with-rails-action-cable-MJykjWZYvPB

    https://viblo.asia/search?q=actioncable
    Nguồn: Viblo



Có vẻ như bạn đã mất kết nối tới LaptrinhX, vui lòng đợi một lúc để chúng tôi thử kết nối lại.