This gem is a collection of resources to help build Rails applications on AI Bridge.

Installation

To install the harbinger-rails-extensions gem add the following to your Gemfile:

gem 'harbinger-rails-extensions', source: 'http://gem.analytical.info:9292'

Single Sign-on

Page Filtering

The gem provides methods for authentication/authorization filtering requests using the SDK and filtering specific page content within views. Filtering pages can be done using the authenticate_and_authorize method. It takes as the first argument an Array of clinical role names. Each item in that Array can be its own array that represents a group of clinical roles that are all required. The second argument is an entity manager. Here are some examples:

# Only ai-staff, it-staff, and radiologist roles can access this page
authenticate_and_authorize(["ai-staff","it-staff","radiologist"],@entity_manager)
# Only ai-staff or someone in both the radiologist and supervisor roles can access this page
authenticate_and_authorize(["ai-staff",["supervisor","radiologist"]],@entity_manager)

Best Practice - Typically you'll create your own methods that use authenticate_and_authorize as your before_filter. This demonstrated in part 5 of the Rails tutorial.

You need to create a route and controller/controller method to handle the redirect of authenticate_and_authorize when the user does not have the required role(s). Here is an example route:

get 'unauthorized' => "unauthorized#index"

Hiding page components by role

In addition to redirecting an unauthorized user, it is possible to show different fragments of a page dependent on employee-clinical role mappings. Here is an example of a block helper that hides components of a view unless the logged in user is authorized to see them:

<% authorized(["radiologist","ai-staff"],@entity_manager) do %>
  <h1>You will only see this heading when the logged in user is a radiologist or ai-staff</h1>
<% end %>

Note - The authorized block helper is using a concat-based method to add the contents of the block to the page. Do not put an = in the erb tag, similar to the each expression.

You can also use the authorize_all which requires that the logged in user have all of the clinical roles in the list.

In addition to the block helpers, there are other helpers that return booleans. They have the same names as the block helpers with a ? suffix (e.g. authorized?(["radiologist"])). These methods reflect the behaviors found on Java::HarbingerSdk::Employee instances: authorizedForAny, authorizedForAll. These methods can be found in the SDK API documentation.

Logout button

Apps should always give the user a way to log out. This is done with a link that has the href set to the value returned by the SDK method Java::HarbingerSdk::SSO.logoutUrl():

<a href="<%= Java::HarbingerSdk::SSO.logoutUrl() %>">Logout</a><

Usage Logging

To log application usage statistics, add the following line to the application controller:

after_filter :log_usage_data

This library will take care of capturing information from the request and sending it to be logged. Application usage data is viewable in the Service Tools application.

Messaging

Application Generated

When building an application you may find that you not only need real-time clinical data, but you also want to alert others in your application of an action taken by a user. This idea is explored more fully in part 9 of the Rails tutorial. To send a message to the messaging bus you can use Harbinger::Rails::Extensions::Messaging.send_application_message. It takes three arguments:

  1. Your application name (the canonical / approved short name of the application)
  2. A routing key
  3. The payload or body of the message. This can be any string.

Here is an example for an application exampleapp inside a model that defines a employee_id, rad_exam_id, and attributes:

def send_amqp_message
  Harbinger::Rails::Extensions::Messaging.send_application_message("railsdevelopertutorial","#{self.employee_id}.#{self.rad_exam_id}",self.attributes.to_json)
end

Consuming messages server-side

HarbingerJS provides a way to consume messages in real-time by the client (browser), but there are some situations where you may want to consume messages server-side. As explained in part 10 of the Rails tutorial, handling this as a background task will require a cron script. The script will make a request to a URL which can consume and process messages stored in a queue. This is an example controller request to build a queue and consume messages from the audit exchange:

dev BackgroundTasks < ApplicationController
  before_filter :cron_authentication

  def process_queue
    conn = Bunny.new(Harbinger::Rails::Extensions::Messaging.bus_credentials)
    conn.start
    channel = conn.create_channel
    exchange = Bunny::Exchange.new(channel,:topic, "audit", :durable => true)
    # prepend the name of your queue with your application name
    # making your queue durable will ensure messages will survive a server restart
    queue = Bunny::Queue.new(channel,"application-name-queue",:durable => true)
    queue.bind(exchange,routing_key: "rad_exams.#")
    while (queue.message_count > 0) do
      message = queue.pop
      # ... Process the given message
      # A message is an Array where
      # [0] is information about the message,
      # [1] is information about the transport, and
      # [2] is the message payload
    end
    conn.close

    render :nothing
  end
end

HarbingerJS

Setup

HarbingerJS uses serverside information to setup proper routing of resource/AJAX calls and the location of cometd (the HTTP push messaging system). Add a call to harbingerjs_setup() to your application view to set up this information so it is available for HarbingerJS. This call must come before the requirement of the HarbingerJS libraries. If you are including HarbingerJS as part of the asset pipeline's application.js you will need to place the harbingerjs_setup() call before a call to javascript_include_tag "application". Here is the head of a typical application layout:

<head>
  <title>My Application</title>
  <%= stylesheet_link_tag    "application", :media => "all" %>
  <%= harbingerjs_setup %>
  <%= javascript_include_tag "application" %>
  <%= csrf_meta_tags %>
<!-- ... anything else you might have -->
</head>

Functionality