23

The descriptions here seem to imply that stream_for is used only when passing in a record, but overall the documentation is rather vague. Can anyone explain the differences between stream_from and stream_for and why would you use one over the other?

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
Xavier
  • 3,423
  • 23
  • 36

3 Answers3

30

stream_for is simply a wrapper method of stream_from with ease.

When you need a stream that is related to a specific model, stream_for automatically generates broadcasting from the model and channel for you.

Let's assume you have a chat_room instance of ChatRoom class,

stream_from "chat_rooms:#{chat_room.to_gid_param}"

or

stream_for chat_room # equivalent with stream_from "chat_rooms:Z2lkOi8vVGVzdEFwcC9Qb3N0LzE"

the two lines of code does the same thing.

https://github.com/rails/rails/blob/master/actioncable/lib/action_cable/channel/streams.rb

kevinhyunilkim
  • 844
  • 7
  • 5
  • What is the point of the `to_gid_param` part ? Couldn't you just say `chat_room_#{params[:chat_room_id]}` ? – the_critic Nov 17 '16 at 17:40
  • Is it just for encoding an arbitrary string into a valid non-whitespace string ? Or is there any other idea behind it ? – the_critic Nov 17 '16 at 17:42
  • `stream_for is used when there is a particular record (or record and association) we want updates about. Under the hood, Action Cable is generating a unique string for that record or that record and its association and then calls the stream_for [sic -- probably should be 'stream_from'] method.`Source: https://www.sitepoint.com/action-cable-and-websockets-an-in-depth-tutorial/ – the_critic Nov 17 '16 at 17:47
  • 1
    gid_param is hard to predict. It blocks an attacker who give random ids to get streams. – kuboon Aug 20 '17 at 19:45
  • @the_critic and how do you subscribe from the client side to a channel that you won't know in advance? I mean how do you subscribe to it? – tommyalvarez Nov 05 '18 at 12:23
  • You can send an id as params for connection. – Almaron Jan 19 '19 at 09:08
7

kevinhyunilkim's answer is almost ok, but prefix depends on channel_name, not model class.

class CommentsChannel < ApplicationCable::Channel
  def subscribed
    stream_for article
    # is equivalent to
    stream_from "#{self.channel_name}:{article.to_gid_param}"
    # in this class this means
    stream_from "comments:{article.to_gid_param}"
  end

  private

  # any activerecord instance has 'to_gid_param'
  def article
    Article.find_by(id: params[:article_id])
  end
end

you can also pass simple string to stream_for which simply adds channel name.

kuboon
  • 9,557
  • 3
  • 42
  • 32
0

stream_for takes an object as argument

class UserChannel < ApplicationCable::Channel
  def subscribed
    stream_for current_user
  end
end

stream_from takes a string as an argument

class ChatChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chat_channel_#{params[:id]}"
  end
end

check this article it deals with the concept very well in my opinion

Addo
  • 273
  • 3
  • 8