Search code examples
ruby-on-railsactioncable

preventing actioncable subscribers from submitting messages to chatrooms that they are not a part of in Rails


If my app uses AJAX to submit a user's message to a server side speak method that has no need for a controller (and therefore no space to write a before_filter), how would I implement behavior that restricts users who are not a part of that conversation from submitting messages through the browser console?

If I open my app and type App.messages.speak("hi", #guess random number#) that message is submitted to the conversation whether they are a part of it or not.

messages_channel.rb

class MessagesChannel < ApplicationCable::Channel
 def speak(data)
  Message.create! body: data['body'], conversation_id: data['conversation_id'], user_id: current_user.id
 end
end

messages.coffee

App.messages = App.cable.subscriptions.create "MessagesChannel", 
 speak: (body, conversation_id) ->
  @perform 'speak', body: body, conversation_id: conversation_id

 submit_message = () ->
 $('#response').on 'keydown', (event) ->
  if event.keyCode is 13
    conversation_id = $("[data-conversation-id]").data("conversation-id")
    App.messages.speak(event.target.value, conversation_id)
    event.target.value = ""
    event.preventDefault()

I'm thinking I could remove the conversation_id param from the speak method and set it elsewhere that isn't dependent on user input? Currently I have it set as a data attribute, which means people could still mess with it.


Solution

  • Solved it with a callback.

    class Message < ApplicationRecord
     before_create :exclude_non_participants
    
     def exclude_non_participants
      if conversation.participates?(user)
       true
      else
       throw :abort
      end
     end
    end
    

    participates?(user) in this case is:

    class Conversation < ApplicationRecord
     def participates?(user)
     sender == user || receiver == user
     end
    end
    

    If there's a better way to do this, please let me know. For now, I think this works?