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.
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.
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.
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.
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
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
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.
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.
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.
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
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
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.
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!
| Description | Name | Size | Download method |
|---|---|---|---|
| Part 4 sample code | part4_doctorsOffice.zip | 15KB | HTTP |
Information about download methods
Learn
-
XForms and Ruby on Rails at the doctor's office, Part 1: Setting up IBM DB2 9 pureXML (Michael Galpin, developerWorks, December 2007): Examine how XForms, DB2 pureXML, and Ruby on Rails can all help more rapidly build XML-centric Web applications.
-
XForms and Ruby on Rails at the doctor's office, Part 2: Implementing the patient information XForm (Michael Galpin, developerWorks, December 2007): Combine XForms, DB2 pureXML, and Ruby for easier Web app creation. In Part 2 of this series, start your hypothetical app that manages patient information in a doctor's office.
-
XForms and Ruby on Rails at the doctor's office, Part 3: Implementing the nurse and doctor XForm (Tyler Anderson, developerWorks, June 2008: Create Web apps easily with XForms, DB2 pureXML, and Ruby. In Part 3, you make a form for nurses to edit existing patient data.
- For a great introduction to XForms read the three-part series Introduction to XForms (Chris Herbroth, developerWorks, September 2006).
- Did you know you can use XForms and Ajax together? See how in the XForms tip: Combining Ajax and XForms (Nicholas Chase, developerWorks, October 2006).
- Go even further with XForms and Ajax by using it with the Google Web Toolkit in the article Integrate XForms with the Google Web Toolkit, Part 1: Introducing GWT's JavaScript Native Interface (Michael Galpin, developerWorks, September 2007).
- Read one of the first in-depth tutorials on GWT in the
article Ajax for Java developers: Exploring the Google Web Toolkit (Philip McCarthy, developerWorks, June 2006).
- Get started with Ruby on Rails and DB2 by reading the article An introduction to Ruby on Rails for DB2 developers (Edd Dumbill, developerWorks, June 2006).
- Read all about using DB2 and Ruby on Rails together in the article DB2 and Ruby on Rails, Part 1: Getting started with DB2 and Ruby on Rails (John Chun, et al., developerWorks, May 2007).
- See how to use DB2's pureXML with Ruby on Rails in the article DB2 and Ruby on Rails, Part2: DB2 and pureXML with Ruby on Rails (John Chun, et al., developerWorks, June 2007).
- Find out how to use DB2 to enhance the built-in unit testing facilities in Rails by reading the article DB2 and Ruby on Rails, Part 3: Testing with DB2 and Ruby on Rails (John Chun, et al., developerWorks, June 2007).
- Get the scoop on the latest enhancements to DB2 in the article Overview of new DB2 Version 9.5 pureXML enhancements (Manaj Sardana, developerWorks, November 2007).
- Learn about using XQuery with DB2 in the developerWorks article Query DB2 XML data with XQuery (Don Chamberlin and Cynthia Saracco, developerWorks, April 2006).
- Read about the REXML library for working
with XML in Ruby in the article XML Matters: The REXML library (David Mertz, developerWorks, March 2002).
- Check out IBM developerWorks' Ajax Resource Center
- Visit the XForms home at W3C.
-
IBM XML certification: Find out how you can become an IBM-Certified Developer in XML and related technologies.
-
XML technical library: See the developerWorks XML library for a wide range of technical articles and tips, tutorials, standards, and IBM Redbooks.
-
developerWorks technical events and webcasts: Stay current with technology in these sessions.
- The technology
bookstore: Browse for books on these and other technical topics.
-
developerWorks
podcasts: Listen to interesting interviews and discussions for software developers.
Get products and technologies
- Get the XForms extension for Mozilla, Firefox, or Seamonkey.
-
XForms Buddy is Mozilla/Firefox extension that allows you to see the instance data of an XForm. It updates automatically if the instance data changes.
- Get DB2 Express-C version 9.5 from IBM.
- Get Ruby 1.8.6 with Rails 1.2.5.
-
IBM
trial software for product evaluation: Build your next project with trial software available for download directly from developerWorks, including application development tools and middleware products from DB2®, Lotus®, Rational®, Tivoli®, and WebSphere®.
Discuss
- Participate in the discussion forum.
-
XML zone discussion forums: Participate in any of several XML-related discussions.
-
developerWorks XML zone: Share your thoughts: After you read this article, post your comments and thoughts in this forum. The XML zone editors moderate the forum and welcome your input.
-
developerWorks blogs: Check out these blogs and get involved in the developerWorks community.




