Rails 5:使用ActionCable和Sidekiq设置用户聊天的样式

时间:2018-04-13 11:13:20

标签: ruby-on-rails sidekiq actioncable

我正在使用Rails 5和ActionCable创建一个聊天室。我按照video on GoRails进行了设置。

我现在想根据current_user是否发送消息来设置消息样式。

这是我的 views / messages / _message.html.erb partial:

<div class="<%= message.user == current_user ? 'bubble' : 'bubble bubble-alt' %>">
  <%= message.body %>
</div>

如果我只是刷新页面,样式就有效。问题是,当Sidekiq作业呈现此部分(触发MessagesController.render(message))时,它不知道current_user是谁,因为它没有正确的上下文,所以聊天无法正常工作。

我的问题是,我如何允许用户在彼此之间发送消息并根据他们是否是发件人来设置样式?使用ActionCable + Sidekiq?

以下是其他相关文件:

message_relay_job.rb

class MessageRelayJob < ApplicationJob
  queue_as :high

  def perform(message)
    ActionCable.server.broadcast("chatrooms:#{message.chatroom.id}",
      {
        message: MessagesController.render(message),
        chatroom_id: message.chatroom.id
      }
    )
  end
end

chatrooms_channel.rb

class ChatroomsChannel < ApplicationCable::Channel
  def subscribed
    current_user.chatrooms.each do |chatroom|
      stream_from "chatrooms:#{chatroom.id}"
    end
  end

  def unsubscribed
    stop_all_streams
  end

  def send_message(data)
    @chatroom = Chatroom.find(data['chatroom_id'])
    message = @chatroom.messages.create(body: data['body'], user: current_user)
    MessageRelayJob.perform_later(message)
  end
end

chatrooms.coffee

if $("meta[name='current-user']").length > 0
  App.chatrooms = App.cable.subscriptions.create "ChatroomsChannel",
    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) ->
      # Called when there's incoming data on the websocket for this channel
      active_chatroom = $("[data-behavior='messages'][data-chatroom-id='#{data.chatroom_id}']")
      if active_chatroom.length > 0
        active_chatroom.append(data.message)
      else
        $("[data-behavior='chatroom-link'][data-chatroom-id='#{data.chatroom_id}']").css("font-weight", "bold")

    send_message: (chatroom_id, body) ->
      @perform "send_message", {chatroom_id: chatroom_id, body: body}

cable.js

(function() {
  this.App || (this.App = {});
  App.cable = ActionCable.createConsumer("/cable");
}).call(this);

chatrooms.coffee

$ ->
  $('#new_message').on 'keypress', (e) ->
    if e && e.keyCode == 13
      e.preventDefault()
      $(this).submit()
  $('#new_message').on 'submit', (e) ->
    e.preventDefault()
    chatroom_id = $("[data-behavior='messages']").data("chatroom-id")
    body        = $('#message_body')
    App.chatrooms.send_message(chatroom_id, body.val())
    # Clear out the message box
    body.val("")

渠道/ application_cable / connection.rb

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

    def connect
      self.current_user = find_verified_user
      logger.add_tags 'ActionCable', "User #{current_user.email} - id: #{current_user.id}"
    end

    private

    def find_verified_user
      verified_user = User.find_by_id(cookies.signed['user.id'])
      if verified_user && cookies.signed['user.expires_at'] > Time.zone.now
        verified_user
      else
        reject_unauthorized_connection
      end
    end
  end
end

渠道/ application_cable / channel.rb

module ApplicationCable
  class Channel < ActionCable::Channel::Base
  end
end

chatroom_users_controller.rb

class ChatroomUsersController < ApplicationController
  before_action :authenticate_user!
  before_action :set_chatroom

  def create
    @chatroom_user = @chatroom.chatroom_users.where(user_id: current_user.id).first_or_create
    redirect_to @chatroom
  end

  private

  def set_chatroom
    @chatroom = Chatroom.find(params[:chatroom_id])
  end
end

chatrooms_controller.rb

class ChatroomsController < ApplicationController
  before_action :authenticate_user!
  before_action :set_chatroom, only: %i[show edit update destroy]

  def show
    @messages = @chatroom.messages.includes(:user).order(created_at: :asc)
  end

  def create
    @chatroom = Chatroom.new(chatroom_params)

    respond_to do |format|
      if @chatroom.save
        format.html { redirect_to @chatroom, notice: 'Chatroom was successfully created.' }
        format.json { render :show, status: :created, location: @chatroom }
      else
        format.html { render :new }
        format.json { render json: @chatroom.errors, status: :unprocessable_entity }
      end
    end
  end


  def messages
    @chatrooms = Chatroom.all
  end

  private

  def set_chatroom
    @chatroom = Chatroom.find(params[:id])
  rescue ActiveRecord::RecordNotFound
    flash[:warning] = 'Unable to find the specified conversation.'
    redirect_to messages_path
  end

  def chatroom_params
    params.require(:chatroom).permit(:name)
  end
end

messages_controller.rb

class MessagesController < ApplicationController
  before_action :authenticate_user!
  before_action :set_chatroom

  def create
    message = @chatroom.messages.new(message_params)
    message.user = current_user
    message.save
    MessageRelayJob.perform_later(message)
  end

  private

  def set_chatroom
    @chatroom = Chatroom.find(params[:chatroom_id])
  end

  def message_params
    params.require(:message).permit(:body)
  end
end

视图/消息/ create.js.erb

$('#new_message')[0].reset()

模型/ chatroom_user.rb

class ChatroomUser < ApplicationRecord
  # Associations
  belongs_to :chatroom
  belongs_to :user
end

模型/ chatroom.rb

class Chatroom < ApplicationRecord
  # Associations
  has_many :chatroom_users
  has_many :users, through: :chatroom_users
  has_many :messages
end

模型/ message.rb

class Message < ApplicationRecord
  # Associations
  belongs_to :chatroom
  belongs_to :user
end

模型/ user.rb

class User < ApplicationRecord
  has_many :chatroom_users
  has_many :chatrooms, through: :chatroom_users
  has_many :messages
end

非常感谢任何帮助。提前谢谢!

1 个答案:

答案 0 :(得分:1)

如果我理解正确,你可以将params传递给你工作中的渲染方法:

ApplicationController.render(
    partial: 'your partial',
    locals: { current_user: current_user and your other locals }
)

另外,当你执行你的工作时,你应该传递你的current_user

作为参数
MessageRelayJob.perform_later(message, current_user.id)

在你的工作中,你可以找到current_user。