Class: Rage::Cable::Channel

Inherits:
Object
  • Object
show all
Defined in:
lib/rage/cable/channel.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.after_subscribe(action_name = nil, **opts, &block) ⇒ Object

Note:

This callback will be triggered even if the subscription was rejected with the #reject method.

Register a new after_subscribe hook that will be called after the #subscribed method.

Examples:

after_subscribe do
  ...
end
after_subscribe :my_method, unless: :subscription_rejected?


209
210
211
# File 'lib/rage/cable/channel.rb', line 209

def after_subscribe(action_name = nil, **opts, &block)
  add_action(:after_subscribe, action_name, **opts, &block)
end

.after_unsubscribe(action_name = nil, **opts, &block) ⇒ Object

Register a new after_unsubscribe hook that will be called after the #unsubscribed method.



219
220
221
# File 'lib/rage/cable/channel.rb', line 219

def after_unsubscribe(action_name = nil, **opts, &block)
  add_action(:after_unsubscribe, action_name, **opts, &block)
end

.before_subscribe(action_name = nil, **opts, &block) ⇒ Object

Register a new before_subscribe hook that will be called before the #subscribed method.

Examples:

before_subscribe :my_method
before_subscribe do
  ...
end
before_subscribe :my_method, if: -> { ... }


196
197
198
# File 'lib/rage/cable/channel.rb', line 196

def before_subscribe(action_name = nil, **opts, &block)
  add_action(:before_subscribe, action_name, **opts, &block)
end

.before_unsubscribe(action_name = nil, **opts, &block) ⇒ Object

Register a new before_unsubscribe hook that will be called before the #unsubscribed method.



214
215
216
# File 'lib/rage/cable/channel.rb', line 214

def before_unsubscribe(action_name = nil, **opts, &block)
  add_action(:before_unsubscribe, action_name, **opts, &block)
end

.broadcast_to(streamable, data) ⇒ Object

Broadcast data to all the clients subscribed to a channel-local stream.

Examples:

NotificationsChannel.broadcast_to(current_user, { message: "You have a new notification!" })

Parameters:

  • streamable (#id, String, Symbol, Numeric, Array)

    an object that will be used to generate the stream name

  • data (Object)

    the data to send to the clients

Raises:

  • (ArgumentError)

    if the streamable object does not satisfy the type requirements



299
300
301
# File 'lib/rage/cable/channel.rb', line 299

def broadcast_to(streamable, data)
  Rage.cable.broadcast(__stream_name_for(streamable), data)
end

.periodically(method_name = nil, every:, &block) ⇒ Object

Set up a timer to periodically perform a task on the channel. Accepts a method name or a block.

Examples:

periodically every: 3.minutes do
  transmit({ action: :update_count, count: current_count })
end
periodically :update_count, every: 3.minutes

Parameters:

  • method_name (Symbol, nil) (defaults to: nil)

    the name of the method to call

  • every (Integer)

    the calling period in seconds



267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# File 'lib/rage/cable/channel.rb', line 267

def periodically(method_name = nil, every:, &block)
  callback_name = if block_given?
    raise ArgumentError, "Pass the `method_name` argument or provide a block, not both" if method_name
    define_tmp_method(block)
  elsif method_name.is_a?(Symbol)
    define_tmp_method(eval("-> { #{method_name} }"))
  else
    raise ArgumentError, "Expected a Symbol method name, got #{method_name.inspect}"
  end

  unless every.is_a?(Numeric) && every > 0
    raise ArgumentError, "Expected every: to be a positive number of seconds, got #{every.inspect}"
  end

  callback = eval("->(channel) { channel.#{callback_name} }")

  if @__periodic_timers.nil?
    @__periodic_timers = []
  elsif @__periodic_timers.frozen?
    @__periodic_timers = @__periodic_timers.dup
  end

  @__periodic_timers << [callback, every]
end

.rescue_from(*klasses, with: nil, &block) ⇒ Object

Register an exception handler.

Examples:

rescue_from StandardError, with: :report_error

private

def report_error(e)
  SomeExternalBugtrackingService.notify(e)
end
rescue_from StandardError do |e|
  SomeExternalBugtrackingService.notify(e)
end

Parameters:

  • klasses (Class, Array<Class>)

    exception classes to watch on

  • with (Symbol) (defaults to: nil)

    the name of a handler method. The method can take one argument, which is the raised exception. Alternatively, you can pass a block, which can also take one argument.



239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/rage/cable/channel.rb', line 239

def rescue_from(*klasses, with: nil, &block)
  unless with
    if block_given?
      with = define_tmp_method(block)
    else
      raise ArgumentError, "No handler provided. Pass the `with` keyword argument or provide a block."
    end
  end

  if @__rescue_handlers.nil?
    @__rescue_handlers = []
  elsif @__rescue_handlers.frozen?
    @__rescue_handlers = @__rescue_handlers.dup
  end

  @__rescue_handlers.unshift([klasses, with])
end

Instance Method Details

#broadcast(stream, data) ⇒ Object

Broadcast data to all the clients subscribed to a stream.

Examples:

def subscribed
  broadcast("notifications", { message: "A new member has joined!" })
end

Parameters:

  • stream (String)

    the name of the stream

  • data (Object)

    the data to send to the clients



511
512
513
# File 'lib/rage/cable/channel.rb', line 511

def broadcast(stream, data)
  Rage.cable.broadcast(stream, data)
end

#paramsHash{Symbol=>String,Array,Hash,Numeric,NilClass,TrueClass,FalseClass}

Get the params hash passed in during the subscription process.

Returns:

  • (Hash{Symbol=>String,Array,Hash,Numeric,NilClass,TrueClass,FalseClass})


419
420
421
# File 'lib/rage/cable/channel.rb', line 419

def params
  @__params
end

#rejectObject

Reject the subscription request. The method should only be called during the subscription process (i.e. inside the #subscribed method or before_subscribe/after_subscribe hooks).



425
426
427
# File 'lib/rage/cable/channel.rb', line 425

def reject
  @__subscription_rejected = true
end

#stop_stream_for(streamable) ⇒ Object

Unsubscribe from a local stream. The counterpart to #stream_for.

Examples:

Unsubscribe from a model stream

class NotificationsChannel < Rage::Cable::Channel
  def unfollow(data)
    stop_stream_for User.find(data['user_id'])
  end
end

Parameters:

  • streamable (#id, String, Symbol, Numeric, Array)

    an object that will be used to generate the stream name

Raises:

  • (ArgumentError)

    if the streamable object does not satisfy the type requirements



499
500
501
# File 'lib/rage/cable/channel.rb', line 499

def stop_stream_for(streamable)
  stop_stream_from(self.class.__stream_name_for(streamable))
end

#stop_stream_from(stream) ⇒ Object

Unsubscribe from a global stream.

Examples:

Unsubscribe from a stream and subscribe to a new one

class ChatChannel < Rage::Cable::Channel
  def subscribed
    stream_from "chat_#{params[:room]}"
  end

  def switch_room(data)
    stop_stream_from "chat_#{params[:room]}"
    stream_from "chat_#{data['new_room']}"
  end
end

Parameters:

  • stream (String)

    the name of the stream

Raises:

  • (ArgumentError)

    if the stream name is not a String



484
485
486
487
# File 'lib/rage/cable/channel.rb', line 484

def stop_stream_from(stream)
  raise ArgumentError, "Stream name must be a String" unless stream.is_a?(String)
  Rage.cable.__protocol.unsubscribe(@__connection, stream, @__params)
end

#stream_for(streamable) ⇒ Object

Subscribe to a local stream. Local streams are associated with a specific channel instance and can be used to send data to the current channel only.

Examples:

Subscribe to a stream

class NotificationsChannel < Rage::Cable::Channel
  def subscribed
    stream_for current_user
  end
end

Broadcast to the stream

NotificationsChannel.broadcast_to(current_user, { message: "You have a new notification!" })

Parameters:

  • streamable (#id, String, Symbol, Numeric, Array)

    an object that will be used to generate the stream name

Raises:

  • (ArgumentError)

    if the streamable object does not satisfy the type requirements



465
466
467
# File 'lib/rage/cable/channel.rb', line 465

def stream_for(streamable)
  stream_from(self.class.__stream_name_for(streamable))
end

#stream_from(stream) ⇒ Object

Subscribe to a stream global stream. Global streams are not associated with any specific channel instance and can be used to broadcast data to multiple channels at once.

Examples:

Subscribe to a stream

class NotificationsChannel < Rage::Cable::Channel
  def subscribed
    stream_from "notifications"
  end
end

Broadcast to the stream

Rage::Cable.broadcast("notifications", { message: "A new member has joined!" })

Parameters:

  • stream (String)

    the name of the stream

Raises:

  • (ArgumentError)

    if the stream name is not a String



448
449
450
451
# File 'lib/rage/cable/channel.rb', line 448

def stream_from(stream)
  raise ArgumentError, "Stream name must be a String" unless stream.is_a?(String)
  Rage.cable.__protocol.subscribe(@__connection, stream, @__params)
end

#subscribedObject

Called once a client has become a subscriber of the channel.



535
536
# File 'lib/rage/cable/channel.rb', line 535

def subscribed
end

#subscription_rejected?Boolean

Checks whether the #reject method has been called.

Returns:

  • (Boolean)


432
433
434
# File 'lib/rage/cable/channel.rb', line 432

def subscription_rejected?
  !!@__subscription_rejected
end

#transmit(data) ⇒ Object

Transmit data to the current client.

Examples:

def subscribed
  transmit({ message: "Hello!" })
end

Parameters:

  • data (Object)

    the data to send to the client



522
523
524
525
526
527
528
529
530
531
532
# File 'lib/rage/cable/channel.rb', line 522

def transmit(data)
  message = Rage.cable.__protocol.serialize(@__params, data)

  if @__is_subscribing
    # we expect a confirmation message to be sent as a result of a successful subscribe call;
    # this will make sure `transmit` calls send data after the confirmation;
    ::Iodine.defer { @__connection.write(message) }
  else
    @__connection.write(message)
  end
end

#unsubscribedObject

Called once a client unsubscribes from the channel.



539
540
# File 'lib/rage/cable/channel.rb', line 539

def unsubscribed
end