Skip to main content

By clicking Submit, you agree to the developerWorks terms of use.

The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

All information submitted is secure.

  • Close [x]

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerworks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

By clicking Submit, you agree to the developerWorks terms of use.

All information submitted is secure.

  • Close [x]

XForms and Ruby on Rails at the doctor's office, Part 4: Implementing the doctor and patient lookup XForms

Tyler Anderson (tyleranderson5@yahoo.com), Freelance writer, Backstop Media
Tyler Anderson has graduated with a degree in computer science in 2004 and a Master of Science degree in computer engineering in December, 2005, both from Brigham Young University. Tyler is currently a freelance writer and developer for Backstop Media.

Summary:  This is the fourth article in a four-part series about using XForms, IBM® DB2® pureXML™, and Ruby together to more easily create Web applications. In this series you will develop a hypothetical application for managing patient information at a doctor's office. You will get a taste of the individual strengths of each technology, but you will also see how to integrate them together. In Part 4 of the series, you continue to develop XForms for the doctor's office including an all new form to look up patients by last name.

Date:  10 Jun 2008
Level:  Intermediate
Also available in:   Chinese  Russian  Japanese

Activity:  12201 views
Comments:  

Introduction

Up to now in this series, you created a DB2 database and three XForms that help patients and nurses manage patient data. You used Ruby on Rails as the processing interface to allow patients to add new patient records into the database, and subsequently go back and update their information. Nurses are then able to view the information, make appropriate edits, and approve entered information, as they ready patients to meet with the doctor.

In this final installment of the series, Part 4, you will create a new view and controller for doctors along with two new XForms for this view. With the first form, doctors can view the same patient records entered by patients and approved by nurses, plus enter extra information specific to the patient's visit with the doctor. Then, you'll develop a form that allows doctors and nurses to look up patient information by last name.


Prerequisites

This article assumes familiarity with XML and with Web applications in general. Prior exposure to the three core technologies, XForms, DB2 pureXML, and Ruby on Rails, is helpful but definitely not necessary. The article was written using the Mozilla XForms plugin version 0.8.0.3. This provides XForms runtime support in any Mozilla browser such as Firefox. Another very useful Mozilla plugin is XForms Buddy, which provides a debugger for XForms. Version 0.5.6 was used in this article. You will also need the DB2 database server from IBM. This article uses DB2 Express-C version 9.5. This is available for Windows®, Linux®, and UNIX® systems. Finally, you will need Ruby on Rails. This article uses Ruby 1.8.6 with Rails 1.2.5. This article also uses the Mongrel Web server in conjunction with Rails. This is available through Ruby Gems (just type gem install mongrel from the command line). See Resources for download links.


Doctor visit XForm

Frequently used acronyms

  • XML: Extensible Markup Language

The purpose of the doctor's XForm (doctorPatient.xhtml) is to allow doctors to see the exact same information entered by patients at the kiosk and approved by the nurses. On top of that, the doctors XForm needs to allow doctors to enter more information about their visits with the patient. With this in mind, the doctorPatient form is similar to the triagePatient form with several differences, as in Listing 1. Name this file doctorPatient.xhtml, and save it to the public folder.


Listing 1. The doctorPatient form
                
...
      <xf:instance xmlns="" id="patient" >
        <p:Info>
          <FirstName></FirstName>
          <MiddleName></MiddleName>
          <LastName></LastName>
          <Age></Age>
          <Insurer></Insurer>
          <Id></Id>
          <PolicyHolder></PolicyHolder>
          <Copay></Copay>
          <Symptoms></Symptoms>
          <BPressure></BPressure>
          <Notes></Notes>
        </p:Info>
      </xf:instance>

      <xf:submission action="http://localhost:3000/doctor/update/0"
                     method="post"
                     id="submit-info"/>

      <xf:submission id="load_data"
                     action="http://localhost:3000/doctor/grab/0"
                     method="post"
                     replace="instance"
                     />
      
      <xf:action ev:event="xforms-ready">
        <xf:dispatch name="xforms-submit" target="load_data"/>
      </xf:action>   
...
          <xf:label>Please describe your symptoms:<br/></xf:label>
        </xf:textarea>    
      </div>  
      <div id="bloodpressure">
        <xf:input ref="BPressure">
          <xf:label>Blood Pressure: </xf:label>
        </xf:input>
      </div>
      <div id="notes">
        <xf:textarea ref="Notes">
          <xf:label>Notes regarding<br/>visit 
		  with patient:<br/></xf:label>
        </xf:textarea>    
      </div>  
      <div id="submit">
        <xf:submit submission="submit-info">
          <xf:label>Submit Information</xf:label>
        </xf:submit>
      </div>
    </p>

    <a href="doctor/list">Back to List</a>
  </body>
</html>

First notice the two extra elements in the instance data, BPressure and Notes. These two fields will contain the blood pressure of the patient, as measured by the doctor and notes that the doctor can enter into a text field. Here the submit-info and load_data submission element's action attributes point to the doctor controller. Lastly, you can see the two new XForms elements declared in the body of the XForm.

Next, you'll generate the scaffolding for the doctor view and controller.


Doctor view and controller

Rails scaffolding gives an excellent starting point as you develop a Ruby application. Generate scaffolding for the doctor view and controller, as in Listing 2.


Listing 2. Generating scaffolding for the doctor view and controller
                
ruby script/generate scaffold patient doctor
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/doctor
      exists  app/views/layouts/
      exists  test/functional/
  dependency  model
      exists    app/models/
      exists    test/unit/
      exists    test/fixtures/
        skip    app/models/patient.rb
   identical    test/unit/patient_test.rb
   identical    test/fixtures/patients.yml
      create  app/views/doctor/_form.rhtml
      create  app/views/doctor/list.rhtml
      create  app/views/doctor/show.rhtml
      create  app/views/doctor/new.rhtml
      create  app/views/doctor/edit.rhtml
      create  app/controllers/doctor_controller.rb
      create  test/functional/doctor_controller_test.rb
      create  app/helpers/doctor_helper.rb
      create  app/views/layouts/doctor.rhtml
   identical  public/stylesheets/scaffold.css

Note that many things are already created, and only files that do not exist yet are created by Rails. Next you'll define the grab and update methods in the doctor controller, as in Listing 3.


Listing 3. Defining the grab and update methods in the doctor controller
                
  def grab
    id = @request.env["HTTP_REFERER"].split('=')[1]
    @patient = Patient.find(id)
    doc = REXML::Document.new(@patient.information)
    if doc.root.elements["Notes"] == nil then
      el = REXML::Element.new("Notes")
      doc.root.add el
    end
    if doc.root.elements["BPressure"] == nil then
      el = REXML::Element.new("BPressure")
      doc.root.add el
    end
    @patient.information = doc
  end

  def update
    doc = REXML::Document.new("<Info></Info>")
    params[:Info].each_pair do |key,value|
      if (key.index(':') == nil) #removes 
        el = REXML::Element.new key
        el.add_text value
        doc.root.add el
      else
        doc.root.add_attribute key,value
      end
    end

    id = @request.env["HTTP_REFERER"].split('=')[1]
    @patient = Patient.find(id)
    @patient.information = doc
    @patient.update_attributes(params[:patient])
    redirect_to :action => 'list'
  end

You'll first notice that the grab method is quite different from the other two (kiosk and triage) controllers. This is because the two new elements, BPressure and Notes do not currently exist for newly created and approved records in the database. Thus, when the record is requested, each of the two new XML elements are searched for, and if the element doesn't exist, it needs to be added to the XML before being sent back to the XForm through the grab view. After both the BPressure and Notes elements are ensured to exist in the XML document, the patient information field is then set to be the new XML as contained in the doc variable.

Before you move on to the update method, copy the grab.rhtml from the triage view (app/views/triage/grab.rhtml) to the doctor view (app/views/doctor). The grab view is good to go!

The update method here brings no new functionality, but is definitely necessary to save the new XML data to DB2.

Next you'll move on and update the list view for the doctor.


Doctor list view

This view is where the doctor can see all the first and last names of patients whose information the nurses have already approved. Update the list view (app/views/doctors/list.rhtml), as in Listing 4.


Listing 4. Updating the doctor's list view
                
<h1>Listing patients</h1>

<table>
  <tr>
    <th><%= "First Name" %></th>
    <th><%= "Last Name" %></th>
  </tr>
  
<% for patient in @patients %>
<%   if patient.approved=="true" then %>
  <tr>
    <td><% doc = REXML::Document.new(patient.information) %>
      <%= doc.root.elements["FirstName"] %>
    </td>
    <td>
      <%= doc.root.elements["LastName"] %>
    </td>
    <td><%= "<a href=\"../doctorPatient.xhtml?id=" +
             patient[:id].to_s + "\">View/Add Notes</a>" %></td>
    <td><%= link_to 'Delete', { :action => 'destroy', :id => patient },
                                 :confirm => 'Are you sure?',
                                 :method => :post %></td>
  </tr>
<%   end %>
<% end %>
</table>
...

Here you'll output the first and last names for the doctor to see. Also in Listing 4, note the View/Add Notes link that points to the doctorPatient form. When a user clicks this link, he opens the XForm that allows doctors to enter information (blood pressure and notes) not previously allowed by prior forms (see Figure 1).


Figure 1. Taking a look at the doctor XForm
Taking a look at the doctor XForm

The doctor can view the first and last name of the patient, and click the View/Add Notes link to bring it up in an XForm (see Figure 2).


Figure 2. Viewing the doctorPatient XForm in action
Viewing the doctorPatient XForm in action

Here the doctor can add to the Please describe your symptoms text box, enter the patient's blood pressure, and any other specific notes regarding the visit in the Notes box. Submitting the information returns the user to the Web page in Figure 1.

That completes the doctor's form. Next, you'll create the patient lookup form.


Patient lookup form

Now what if you have many patients to scroll through? That makes the task of looking up patients time consuming in busy clinics. This form, that allows doctors and nurses to look up patients by last name, will shorten manual search time. This new form requires a new graball view that places all patients in a single XML document and returns it to the XForm. First you'll create the new view, followed by the new XForm itself.


Creating a graball control

The graball control, as the name implies, is a new view that returns all the patients in the database in a single XML file. Create a new file in the doctor's view directory (app/views/doctor/graball.rhtml), and define is as in Listing 5.


Listing 5. Writing the graball view
                
<% @headers["Content-Type"] = "text/xml; charset=utf-8" %><%= 
"<Patients xmlns:xf=\"http://www.w3.org/2002/xforms\"
           xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" 
           xmlns:p=\"http://developerworks.ibm.com/patient\" 
           xmlns:ev=\"http://www.w3.org/2001/xml-events\">" %>
<% for pat in @patient %>
<%=  "<Info DbId=\"" + pat.id.to_s +
     "\" ViewEditLinkDoc=\"\" ViewEditLinkTri=\"\">" %>
<%   doc = REXML::Document.new(pat.information) %>
<%=  doc.root.elements["LastName"].to_s %>
<%=  "</Info>" %>
<% end %>
<%= "</Patients>" %>

Note that this view, like the grab view, first sets the Content-Type header to be of type "text/xml" so Mongrel and Firefox will know how to handle it. Next the Patients tag is opened and namespaces set. The interesting area is the for loop: Here each patient in the database is looped through, where each patient in the database will get its own set of <Info>...</Info> tags in the XML document. The Info tag then has three attributes:

  • DbId —The patient's corresponding ID in the database.
  • ViewEditLinkDoc —This is a local variable that contains the link to bring up a patient's information in the doctorPatient form.
  • ViewEditLinkTri —Like ViewEditLinkDoc, this is also a local variable, but will instead bring up the patient's information in the triagePatient form.

After the Info opening tag displays, the last name of the patient is retrieved from the patient's XML record, just as it is retrieved in the list view (see Listing 4). The closing </Info> tag finalizes the entry of that patient into the XML. When there are no more patients, the for loop execution finishes and the closing </Patients> tag is written to complete the XML.

Note that the corresponding graball method in the doctor controller is missing. Define it, as in Listing 6.


Listing 6. The graball method in the doctor controller
                
  def graball
    @patient = Patient.find_by_sql("select * from patients");
  end

Instead of finding by a unique identifier like ID, an SQL statement requests that all patients be returned. This is how you get all the patients in the database to the graball view you defined in Listing 5.

Next you'll code up the patient lookup form, itself.


The patient lookup XForm

You've made it to the last XForm of this series! With this handy form, doctors or nurses can easily find patients by last name. Create a new XForm (lookupPatient.xhtml), save it into the public directory, and define is as in Listing 7.


Listing 7. Writing the lookupPatient form
                
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
         "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      xmlns:xf="http://www.w3.org/2002/xforms"
      xmlns:ev="http://www.w3.org/2001/xml-events">
  <head>
    <meta http-equiv="Content-Type"
          content="text/html; charset=ISO-8859-1" />
    <title>Patient Lookup</title>
    <xf:model id="patientModel">

      <xf:instance xmlns="" id="searchLastName">
        <search>
          <LastName/>
        </search>
      </xf:instance>

      <xf:instance xmlns="" id="patients">
        <Patients>
<!--
          <Info DbId="" ViewEditLinkDoc="" ViewEditLinkTri="">
            <LastName/>
          </Info>
          ...
-->
        </Patients>
      </xf:instance>

      <xf:submission id="load_data"
                     action="http://localhost:3000/doctor/graball/0"
                     method="post"
                     replace="instance"
                     instance="patients"/>
      
      <xf:action ev:event="xforms-ready">
        <xf:dispatch name="xforms-submit" target="load_data"/>
      </xf:action>

    </xf:model>
  </head>
  <body>
    <p>
      <div id="searchLastName">
        <xf:input ref="instance('searchLastName')//LastName"
                  incremental="true">
          <xf:label>Search Last Name:</xf:label>
        </xf:input>
      </div>
      <table>
        <th>
          <td width="200px">Last Name</td>
          <td width="100px">View/Edit Doctor</td>
          <td width="100px">View/Edit Triage</td>
        </th>
      </table>

      <xf:repeat id="patientRepeat"
                 nodeset="instance('patients')//Info
                          [LastName=instance('searchLastName')//LastName]">
        <table>
          <tr>
            <td width="200px">
              <div id="LastName">
                <xf:output ref="LastName"/>
              </div>
            </td>
            <td width="100px">
              <div id="viewDoctor">
                <xf:trigger>
                  <xf:label>View/Edit Doc</xf:label>
                  <xf:action ev:event="DOMActivate">
                    <xf:setvalue ref="@ViewEditLinkDoc"
                        value="concat('doctorPatient.xhtml?id=',../@DbId)"/>
                    <xf:load ref="@ViewEditLinkDoc" show="new"/>
                  </xf:action>
                </xf:trigger>
              </div>
            </td>
            <td width="100px">
              <div id="viewTriage">
                <xf:trigger>
                  <xf:label>View/Edit Tri</xf:label>
                  <xf:action ev:event="DOMActivate">
                    <xf:setvalue ref="@ViewEditLinkTri"
                        value="concat('triagePatient.xhtml?id=',../@DbId)"/>
                    <xf:load ref="@ViewEditLinkTri" show="new"/>
                  </xf:action>
                </xf:trigger>
              </div>
            </td>
          </tr>
        </table>
      </xf:repeat>
    </p>

    <a href="doctor/list">Back to Doctor</a><br/>
    <a href="triage/list">Back to Triage</a>
  </body>
</html>

This form has a few elements not yet seen in this series. Plus, it has two instance documents that you'll need to manage separately. The first instance document with id searchLastName contains the last name of the patient searched for. The patient's instance document contains the XML loaded by the load_data submission element (dispatched by calling the doctor's graball view upon loading of the XForm). Once the instance data is loaded you won't see anything special in the XForm unless you enter a last name that matches one of the last names in the patient's XML instance data (see Figure 3).


Figure 3. The lookupPatient form
The lookupPatient form

In the body of the XForm of Listing 7, you can see the text box where doctors and nurses enter last names for matching. Then you see the headings set up, one for the matched lastname, two for buttons that allow doctors or nurses to open the information for each found patient in a separate form (doctorPatient versus triagePatient). If a result is found, that's where the repeat element comes into play. The XPath statement in the nodeset attribute of the repeat element defines which Info elements display within the repeat statement. If a last name in the patients XML instance data matches that entered in the text box, a match is found through the XPath. It displays the last name in the first column, a button to pull up the patient information in the doctorPatient form in the second column, and a button to pull up the patient information in the triagePatient form in the third column (see Figure 4).


Figure 4. The lookupPatient form in action
The lookupPatient form in action

And there you see the matched patient data appear as a row in the table. This immediate Ajax-like processing is made possible by the incremental="true" attribute on the "Search Last Name" textbox (see Listing 7). To bring up patient data in either the doctorPatient or triagePatient form, just click either of the two buttons in Figure 4.

Quite handy, isn't it! You just completed this series on developing XForms using Ruby and DB2 pureXML.


Summary

What an accomplishment! To finish the application in the last installment of this four-part articles series, you developed an XForms for the doctor, and a final patient lookup XForm to ease the daunting task of searching through potentially thousands of patient records.

With your mastery of this trio of technologies, you discovered for yourself that XForms, Ruby on Rails, and DB2 pureXML form quite the team! Maybe you're not a master of these technologies yet, but that's where the Resources come in. You'll find many excellent links to help you expand your knowledge and skills in each of these three technologies. Good luck!



Download

DescriptionNameSizeDownload method
Part 4 sample codepart4_doctorsOffice.zip15KB HTTP

Information about download methods


Resources

Learn

Get products and technologies

Discuss

About the author

Tyler Anderson has graduated with a degree in computer science in 2004 and a Master of Science degree in computer engineering in December, 2005, both from Brigham Young University. Tyler is currently a freelance writer and developer for Backstop Media.

Report abuse help

Report abuse

Thank you. This entry has been flagged for moderator attention.


Report abuse help

Report abuse

Report abuse submission failed. Please try again later.


developerWorks: Sign in


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Select information in your developerWorks profile is displayed to the public, but you may edit the information at any time. Your first name, last name (unless you choose to hide them), and display name will accompany the content that you post.

Choose your display name

The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


Rate this article

Comments

Help: Update or add to My dW interests

What's this?

This little timesaver lets you update your My developerWorks profile with just one click! The general subject of this content (AIX and UNIX, Information Management, Lotus, Rational, Tivoli, WebSphere, Java, Linux, Open source, SOA and Web services, Web development, or XML) will be added to the interests section of your profile, if it's not there already. You only need to be logged in to My developerWorks.

And what's the point of adding your interests to your profile? That's how you find other users with the same interests as yours, and see what they're reading and contributing to the community. Your interests also help us recommend relevant developerWorks content to you.

View your My developerWorks profile

Return from help

Help: Remove from My dW interests

What's this?

Removing this interest does not alter your profile, but rather removes this piece of content from a list of all content for which you've indicated interest. In a future enhancement to My developerWorks, you'll be able to see a record of that content.

View your My developerWorks profile

Return from help

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=XML, Information Management
ArticleID=312543
ArticleTitle=XForms and Ruby on Rails at the doctor's office, Part 4: Implementing the doctor and patient lookup XForms
publish-date=06102008
author1-email=tyleranderson5@yahoo.com
author1-email-cc=dwxed@us.ibm.com

Tags

Help
Use the search field to find all types of content in My developerWorks with that tag.

Use the slider bar to see more or fewer tags.

For articles in technology zones (such as Java technology, Linux, Open source, XML), Popular tags shows the top tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), Popular tags shows the top tags for just that product zone.

For articles in technology zones (such as Java technology, Linux, Open source, XML), My tags shows your tags for all technology zones. For articles in product zones (such as Info Mgmt, Rational, WebSphere), My tags shows your tags for just that product zone.

Use the search field to find all types of content in My developerWorks with that tag. Popular tags shows the top tags for this particular content zone (for example, Java technology, Linux, WebSphere). My tags shows your tags for this particular content zone (for example, Java technology, Linux, WebSphere).

Special offers