module PushRoute::ClassMethods

Public Instance Methods

add_belongs_to_trigger(action, model, type = :after_save) click to toggle source

If you have a route like /room/:id/messages where Message belongs_to room you can use add_belongs_to_trigger :index, Message It will look at the url and try to add a trigger on Message save triggering the id as Message.room.id

# File lib/push_routes/push_route.rb, line 162
def add_belongs_to_trigger(action, model, type = :after_save)
  enable_push_route action unless push_routes[action]
  url = push_routes[action]
  warn "Push Routes WARNING: Url #{url.inspect} contains too many params" if url.param_associations.count > 1
  warn "Push Routes WARNING: Url #{url.inspect} contains not enough notated params" if url.param_associations.count > 1
  sym = url.param_associations.first[1].singularize.to_sym
  if model.table_exists?
    if model&.send(:new)&.respond_to?(sym)
      add_trigger(action, model, type) { |object| {id: object.send(sym)&.id} }
    else
      warn "Push Routes WARNING: #{model} does not respond to #{sym} in belongs_to trigger"
    end
  else
    warn("Push Routes WARNING: no table exists for #{model}")
  end
end
add_id_trigger(action, model, id_name, type = :after_save) click to toggle source
# File lib/push_routes/push_route.rb, line 154
def add_id_trigger(action, model, id_name, type = :after_save)
  add_trigger(action, model, type) { |object| {id: object.send(id_name)} }
end
add_show_trigger(action) click to toggle source
# File lib/push_routes/push_route.rb, line 179
def add_show_trigger(action)
  if self.model
    add_id_trigger(action, self.model, :id)
  else
    warn "Push Routes WARNING: No model found for #{controller_path}"
  end
end
add_trigger(action, model, type, trigger_function = nil) click to toggle source

Sets a trigger for pushing updates @param [symbol] the action in this controller for the listener to trigger @param model [ModelType] The type of model to listen to e.g. User, LabOrder @param type [Symbol] Listener type, e.g. :after_update, see below for list @param trigger_function [function] Function to determine if an update should be triggered, either proc or reference function should return true to trigger update of the route; if the route requires params to resolve (i.e /users/:id/files) the params should be returned as a hash. Return false or nil to not trigger an update

# File lib/push_routes/push_route.rb, line 106
def add_trigger(action, model, type, trigger_function = nil)
  enable_push_route action unless push_routes[action]

  # Get get the callback passed in
  if (!trigger_function and block_given?)
    # Block only
    # Note Proc.new gets the passed in block without instantiating an extra proc
    # See http://mudge.name/2011/01/26/passing-blocks-in-ruby-without-block.html
    callback = Proc.new
  elsif trigger_function && trigger_function.is_a?(Proc)
    # Proc passed
    callback = trigger_function
  elsif trigger_function #&& !trigger_function.is_a?(Proc) implied here
    # Symbol passed
    trigger_symbols << trigger_function
    callback = lambda { |e| self.send(trigger_function, e) }
  else
    #default value
    callback = Proc.new { true }
  end

  if [:after_commit, :after_save, :after_update, :after_create, :after_destroy].include? type
    this = self
    func = lambda do |e|
      result = callback.call(e)
      if (result)
        result = [result] unless result.kind_of?(Array)
        result.each do |params|
          PushRoutes.trigger(this.push_routes[action].notification_string(params))
        end
      end
    end
    model.send(type, func)
  else
    raise ArgumentError.new("Invalid trigger type")
  end
end
enable_push_route(action, route = nil) click to toggle source

TODO: if not route already make, make it; set association between route(s) and action

test method aliasing, perhaps can still do caching explicitly, or maybe just
expiring caches properly; ignore caches for now

maybe just internal whisper pub sub with a routing adapter
also pull out seperate class for each push route to store routes and triggers
Maybe rails magic on for trigger function names
# File lib/push_routes/push_route.rb, line 42
def enable_push_route(action, route = nil)
  matched_url = nil
  Rails.application.routes.routes.each do |e|
    if e.defaults[:controller] == self.controller_path && e.defaults[:action] == action.to_s
      unless matched_url
        matched_url = PushRoutes::PushRouteUrl.new(e)
      else
        raise ArgumentError.new("Duplicate route for push route controller")
      end
    end
  end

  #If a route exists and one is provided, make sure they are compatable
  if matched_url and route
    raise ArgumentError.new("Provided route does not match pre-existing route") unless (matched_url.matches(route))
    url = matched_url
  elsif route and !matched_url
    #There was no pre-existing route found and a route was specified
    # Add this route to the list of live routes
    url = PushRoutes::PushRouteUrl.new(route)
  elsif !route and matched_url
    #Matched one route only, we're good
    url = matched_url
  else
    #No route and no match
    raise ArgumentError.new("No route found and no route provided")
  end

  if push_routes[action]
    raise ArgumentError.new("Push Route enabled twice")
  else
    push_routes[action] = url
  end
end
instance_trigger?(method_sym) click to toggle source
# File lib/push_routes/push_route.rb, line 93
def instance_trigger?(method_sym)
  trigger_symbols.include?(method_sym) && instance_methods.include?(method_sym)
end
method_missing(method_sym, *arguments, &block) click to toggle source

If it's defined as an instance method and not a static method we'll define a static method which wraps the functinality While this seems crazy, ActionMailer does this so there's precident

Calls superclass method
# File lib/push_routes/push_route.rb, line 80
def method_missing(method_sym, *arguments, &block)
  if instance_trigger?(method_sym)
    new.send(method_sym, *arguments, &block)
  else
    super
  end
end
model() click to toggle source

TODO: check for full class depth or shallow depth i.e. Api2::VitalsController

# File lib/push_routes/push_route.rb, line 145
def model
  #Note: const_defined is unrelialbe due to rails auto_loading, model might not be loaded
  begin
    Object.const_get(controller_path.classify)
  rescue
    nil
  end
end
respond_to_missing?(method_sym, include_private = false) click to toggle source

Overriding respond_to_missing to allow our method_missing override to behave properly

Calls superclass method
# File lib/push_routes/push_route.rb, line 89
def respond_to_missing?(method_sym, include_private = false)
  instance_trigger?(method_sym) || super
end