In this section you will implement email alerts to a radiologist when an exam in the worklist is over 7 days old.

Prerequisites

Email will be sent using the Rails mailer ActionMailer.

Email

Start by creating a mailer app/mailers/alert.rb:

class Alert < ActionMailer::Base
  default from: '[email protected]'

  def too_old(count,entity_manager)
    @host = Java::HarbingerSdkData::ConfigurationVariable.firstWith({".configurationKey" => "host"},entity_manager).configurationValue
    @count = count
    q = Java::HarbingerSdkData::Employee.createQuery(entity_manager)
    q.where([q.equal(".employeeClinicalRoleMappings.clinicalRole.clinicalRole","radiologist")])
    rad_emails = q.list.to_a.inject([]) do |list,employee|
      email = employee.demographicHash["email"]
      list << email unless email.blank?
      list
    end
    mail(bcc: rad_emails, subject: 'exam(s) on the worklist too')
  end

end

Best Practice - This example has a hardcoded from address in the Alert model for convenience in the tutorial. This app would not be approved for production without a configurable from address, due to the requirements of interacting with various email systems. Similarly, the entire concept of sending email automatically would require an enable/disable feature, particularly since the potential audience and frequency of such emails could be hundreds of people multiple times an hour.

The too_old method takes two arguments: an entity manager and the count of exams that are too old. Inside the method, the SDK is used to pull get a list of all employee records with an associated clinical role of radiologist. That list is filtered to keep all records with an email address. Finally, the mail command is run to send the email. By convention, an ActionMailer method creates the email body by rendering a view. Create that view in app/views/alert/too_old.text.erb:

There are <%= @count %> exams that are older than 7 days.

Please take a look at the worklist <%= url_for(host: @host, controller: :worklist, action: :index) %>.

The view has access to all instance variables set in the mailer method. Links in emails need to be handled differently than those in a web page: you must specify a host in the options passed to url_for. There is not a reliable way to get the correct host from rails, but the platform provides this through the ConfigurationVariable model, using the record with a configuration_key of host. You can create an HTML format email and use helper functions like link_to following the same principle (also requiring the same host information).

You can test the email and see the headers and body printed to the log by running Alert.too_old(5,nil) in the Rails console.

Background task

You need to build a background task with a query to get the count of exams, determines if an email should be sent, and evaluate regularly. Create a new controller to handler this, app/controllers/alerts_controller.rb:

class AlertsController < ApplicationController
  before_filter :get_entity_manager

  def too_old
    query = Java::HarbingerSdkData::RadExam.createQuery(@entity_manager)
    query.select(query.count(".id"))
    query.where([ query.equal(".currentStatus.universalEventType.eventType","complete"),
                  query.greaterThan(".radExamTime.endExam",7.days.ago.to_time)])
    count = query.first
    if count.size > 0
      Alert.too_old(count,@entity_manager).deliver_now
    end
    render status: 200, text: "sucessfully sent email alerts #{count}"
  end

end

Bridge is not set up to handle the use of deliver_later, you must use deliver_now when sending email.

Add a route for the controller, edit config/routes.rb:

get 'alerts/too_old' => "alerts/too_old"

You can run that method/action from a browser or as an API call, but that will not run periodically in the background as desired.

The current solution for background tasks is to add a curl request to the application server crontab on the desired schedule. This is a manual deployment task, so please document how it needs to work.

Background jobs need to be secured to not run by mistake or without authorization, so create a new filter in the application controller:

  def cron_authenticate()
    if params[:api_key] != "9o8ajewfj9283jflaksueau4938jff"
      render status: 401, text: "Incorrect cron api key"
      return false
    else
      return true
    end
  end

Best Practice - As is the case with the from address in our mailer, it would be required to have a configuration page to edit the API key (rather than hardcoding it like this example code) for this application to be approved and deployed in production.

Finally, add the before_filter call to app/controllers/alerts_controller.rb:

class AlertsController < ApplicationController
  before_filter :cron_authenticate
  before_filter :get_entity_manager
  #...

Invoking the mailer now requires the API key. Here is an example curl request that would be put into crontab to execute the too_long alert:

curl 'http://server.example.com/railsdevelopertutorial/alerts/too_old?api_key=9o8ajewfj9283jflaksueau4938jff'