Search code examples
ruby-on-railsrubyactioncablelivechat

Is there a way to add a temporary username to action cable chat box


Hello I have a basic chat room set up on action cable and was wondering whether there was a way to give the current user a temporary username while posting in the chat room? preferably set up so they have to type their username In before they are allowed to chat?

Here the code I have:

this is the view:

<h1>Chat room</h1>

<div id="messages">
 <%= render @messages %>
</div>

<form>
 <label>Say something:</label><br>
 <input type="text" data-behavior="room_speaker">

</form>

this is the room channel:

class RoomChannel < ApplicationCable::Channel
 def subscribed
 stream_from "room_channel"
end

def unsubscribed
# Any cleanup needed when channel is unsubscribed
end

def speak(data)
  Message.create! content: data['message']
end
end

the message broadcast job:

class MessageBroadcastJob < ApplicationJob
queue_as :default

def perform(message)
ActionCable.server.broadcast 'room_channel', message:       render_message(message)
end

private

def render_message(message)
ApplicationController.renderer.render(partial: 'messages/message',   locals: { message: message })
end
end

and the coffee script:

  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) ->
      $('#messages').append data['message']

    speak: (message) ->
      @perform 'speak' , message: message



  $(document).on 'keypress', '[data-behavior~=room_speaker]', (event) ->
    if event.keyCode is 13
      App.room.speak event.target.value
      event.target.value = ''
      event.preventDefault();

here is my controller:

 class RoomsController < ApplicationController
 def index
  @messages = Message.all
 end

end

the page that I render:

<div class="message">
  <p><%=message.content%></p>
</div>

Solution

  • Solution 1

    Initially redirect user to page where there will be textbox to enter username Once user enters username and click on submit, redirect him/her to chat page. Now you have params[:user_name] just create @username in chat action and make it a hidden variable in your chat form. (i.e in form where user enters chat message).

    Now your form will look like this

    class RoomsController < ApplicationController
    
     #index action will render form with just text_field to enter username and submit
    
     def index
     end
    
     # Now chat_window will handle you chat_form
     # From index action you will receive params username. Just create object with it
     # so that you can refer it in chat form
     def chat_window 
      @username = params[:user_name] 
      @messages = Message.all
     end
    end
    

    NOTE: Create route accordingly

    Now change your existing form like below.This form will have hidden @username value.

    <form>
     <label>Say something:</label><br>
     <input type="hidden" id="user_name" value="<%=@username%>">
     <input type="text" data-behavior="room_speaker">
    </form>
    

    Solution 2:

    You can just do it in single form using hide and show functionality. Here I am initially hiding chat form and making only username div visible. Once he/she enters username, Will show chat_form and username will be appended to username hidden field in that form. That's it.

    <h1>Chat room</h1>
    
    <div class="user-block">
    <input type="text" id="temp_user" placeholder="Enter Username"></input>
    <button id="submit_username">Ok</button>
    </div>
    
    
    <div class="chat-block" style="display: none;">
    <div id="messages">
    
    </div>
    
    <form>
     <label>Say something:</label><br>
     <input type="hidden" id="user_name" value="anonyms"></input>
     <input type="text" data-behavior="room_speaker">
    
    </form>
    </div>
    
    
    
    <script>
    
    $(document).ready(function(){
     $("#submit_username").click(function(){
        $(".chat-block").show();
        $(".user-block").hide()
        $("#user_name").val($("#temp_user").val());
     });
    });
    </script>
    

    Final steps

    Once on of above things done.Just send username as well along with your message to Room Channel classe's speak

      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) ->
          $('#messages').append data['message']
    
        speak: (message, user_name) ->
          @perform 'speak' , message: message, user_name: user_name
    
    
    
      $(document).on 'keypress', '[data-behavior~=room_speaker]', (event) ->
        if event.keyCode is 13
          App.room.speak event.target.value, $("#user_name").val()
          event.target.value = ''
          event.preventDefault();
    

    And in your Room Channel will have username like this

    def speak(data, user_name)
      # here you got user_name.Do whatever.
      # Either create field in message model called user_name or Separate User model.
      Message.create! content: data['message']
    end