module ActionCableNotifications::Model

Constants

ChannelPublications

Public Instance Methods

broadcast_notifications_from( publication, options = {} ) click to toggle source

Sets or removes notificacions options for Active Record model

@param [sym] publication Topic name to broadcast in @param [hash] options Hash containing notification options

# File lib/action_cable_notifications/model.rb, line 25
def broadcast_notifications_from ( publication, options = {} )
  # Default options
  options = {
    actions: [:create, :update, :destroy],
    track_scope_changes: false,
    scope: :all,             # Default collection scope
    records: []
    }.merge(options)

  self.ChannelPublications[publication.to_s] = options
end
notify_create() click to toggle source

Broadcast notifications when a new record is created

# File lib/action_cable_notifications/model.rb, line 74
def notify_create
  self.ChannelPublications.each do |publication, options|
    if options[:actions].include? :create
      # Checks if record is within scope before broadcasting
      if options[:scope]==:all or self.class.scoped_collection(options[:scope]).where(id: self.id).present?
        ActionCable.server.broadcast publication,
          msg: 'create',
          id: self.id,
          data: self
      end
    end
  end
end
notify_destroy() click to toggle source

Broadcast notifications when a record is destroyed.

# File lib/action_cable_notifications/model.rb, line 172
def notify_destroy
  self.ChannelPublications.each do |publication, options|
    if options[:scope]==:all or options[:actions].include? :destroy
      # Checks if record is within scope before broadcasting
      if options[:scope]==:all or self.class.scoped_collection(options[:scope]).where(id: self.id).present?
        ActionCable.server.broadcast publication,
          msg: 'destroy',
          id: self.id
      end
    end
  end
end
notify_initial( publication ) click to toggle source

Retrieves initial values to be sent to clients upon subscription

@param [Sym] publication Name of publication stream

@return [Hash] Hash containing the results in the following format: {

msg: 'add_collection',
data: self.scoped_collection(options[:scope])

}

# File lib/action_cable_notifications/model.rb, line 60
def notify_initial ( publication )
  options = self.ChannelPublications[publication.to_s]
  if options.present?
    {
      msg: 'upsert_many',
      data: self.scoped_collection(options[:scope])
    }
  end
end
notify_update() click to toggle source

Broadcast notifications when a record is updated. Only changed fields will be sent if they are within configured scope

# File lib/action_cable_notifications/model.rb, line 107
def notify_update
  # Get model changes
  if self.respond_to?(:saved_changes) # For Rails >= 5.1
    changes = self.saved_changes.transform_values(&:second)
  else # For Rails < 5.1
    changes = self.changes.transform_values(&:second)
  end

  # Checks if there are changes in the model
  if !changes.empty?
    self.ChannelPublications.each do |publication, options|
      if options[:actions].include? :update
        # Checks if previous record was within scope
        record = options[:records].detect{|r| r.id==self.id}
        was_in_scope = record.present?
        options[:records].delete(record) if was_in_scope

        # Checks if current record is within scope
        if options[:track_scope_changes]==true
          is_in_scope = false
          if options[:scope]==:all
            record = self
            is_in_scope = true
          else
            record = self.class.scoped_collection(options[:scope]).where(id: self.id)
            if record.present?
              record = record.first
              is_in_scope = true
            end
          end
        else
          is_in_scope = was_in_scope
        end

        # Broadcasts notifications about model changes
        if is_in_scope
          if was_in_scope
            # Get model changes and applies them to the scoped collection record
            changes.select!{|k,v| record.respond_to?(k)}

            if !changes.empty?
              ActionCable.server.broadcast publication,
                msg: 'update',
                id: self.id,
                data: changes
            end
          else
            ActionCable.server.broadcast publication,
              msg: 'create',
              id: record.id,
              data: record
          end
        elsif was_in_scope # checks if needs to delete the record if its no longer in scope
          ActionCable.server.broadcast publication,
            msg: 'destroy',
            id: self.id
        end
      end
    end
  end
end
prepare_update() click to toggle source
# File lib/action_cable_notifications/model.rb, line 88
def prepare_update
  self.ChannelPublications.each do |publication, options|
    if options[:actions].include? :update
      if options[:scope]==:all
        options[:records].push self
      else
        record = self.class.scoped_collection(options[:scope]).where(id: self.id)
        if record.present?
          options[:records].push record.first
        end
      end
    end
  end
end
scoped_collection( scope = :all ) click to toggle source

Returns collection scoped as specified in parameters.

@param [Array] scope Contains the scopes to be applied. For example: [[:limit, 5], [:order, :id]]

@return [ActiveRecordRelation] Results fetched from the database

# File lib/action_cable_notifications/model.rb, line 45
def scoped_collection ( scope = :all )
  scope = scope.to_a if scope.is_a? Hash
  Array(scope).inject(self) {|o, a| o.try(*a)} rescue nil
end