In Part 1 of this four-part series, you started to design a Web application that would let patients enter information at the doctor's office. It discussed how you can create such an application with XForms, DB2 pureXML, and Ruby on Rails, and you experimented with using these technologies together. In Part 2 you began to implement the application. You designed your first XForm and created a Ruby on Rails back-end to insert the data from the form into DB2. You will continue to see how you can use these three technologies to leverage XML across all of your application.
In this article, Part 3, you will refine the user interface presented in Ruby to allow you to view and edit existing patients with two new forms: One to edit patient data from the Kiosk view, and a new form for nurses to view, edit, and approve entered patient data from a new Triage view. After a nurse approves entered information, the patient is ready to see the doctor. When the patient is with the doctor, the doctor can view the patient's data and supplement the data with her own findings and notes. In Part 4, you'll learn about the structure of the doctor's form which allows the doctor to read and edit patient data approved by nurses, with additional inputs for the results of the doctor's visit.
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.
With patients able to enter their data into the system, how do you handle returning patients who require an update to their information? Currently you can only create new patients and view the results. Now you'll develop a form that allows you to edit and update existing patient information.
The ability to view and edit existing data is an integral part of any application, and you'll accomplish this in a new form. So create a new XHTML file in your public directory, editPatient.xhtml, and while you're at it, rename the patient.xhtml form from Part 2 to newPatient.xhtml. The new editPatient form is quite similar to the newPatient form. Look at the changes in Listing 1.
Listing 1. Creating the editPatient form
...
<xf:model id="patientModel">
<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>
</p:Info>
</xf:instance>
<xf:submission action="http://localhost:3000/kiosk/update/0"
method="post"
id="submit-info"/>
<xf:submission id="load_data"
action="http://localhost:3000/kiosk/grab/0"
method="post"
replace="instance"
/>
<xf:action ev:event="xforms-ready">
<xf:dispatch name="xforms-submit" target="load_data"/>
</xf:action>
</xf:model>
...
<a href="kiosk/list">Back to List</a>
</body>
</html>
|
Pretty simple change, no? First, note that in the submission element with id="submit-info" you modified the action URL to point to the Ruby update script. You also added a new action element that is triggered on the xforms-ready event, which triggers when the form loads. This triggered action then dispatches the submission element with id="load_data" to fetch data from a new view, grab. You'll take a look at this new view next.
Kiosk grab view and controller
The grab view simply queries the database for the patient record as indicated in the id variable of the referring URL, formats the XML appropriately, and sends the data back to the XForm. Implementing this new view requires a new file, grab.rhtml in your app\views\kiosk directory. Define it as follows (as one line).
<% @headers["Content-Type"] = "text/xml; charset=utf-8" %><%= @patient.information %> |
That's it, here you set the header's Content-Type to text/xml, a required format by the XForms processor. Then you simply output the patients information variable, the XML defined for that record in the DB2 database.
However, for this to work, you also need to edit the kiosk layout (app/views/layouts/kiosk.rhtml), to only contain the following line: <%= yield %>.
What this does is remove all the extraneous tags before and after the XML data required by the XForms processor. The last step in this flow is to define grab in the kiosk controller (app/controllers/kiosk_controller.rb), as in Listing 2.
Listing 2. Defining grab in the controller
def grab
id = @request.env["HTTP_REFERER"].split('=')[1]
@patient = Patient.find(id)
end
|
Note that the code obtains the id of the customer being grabbed from the referring URL.
This is to overcome a limitation: XForms cannot submit received GET request variables in its POST requests. Thus, if the URL is:
http://localhost:3000/editPatient.xhtml?id=60 |
The record extracted from the database is the one whose id is 60. The data is then passed to the grab view that you defined in Listing 1, which gets passed to XForms.
Next you need to update the list view (app/views/kiosk/list.rhtml) to list all the current patients with links so you can go to the editPatient form to view and edit patients appropriately. Update this view, as in Listing 3.
Listing 3. Updating the list view
<h1>Listing patients</h1>
<table>
<tr>
<th><%= "ID" %></th>
</tr>
<% for patient in @patients %>
<tr>
<td><%=h patient.id %></td>
<td><%= "<a href=\"../editPatient.xhtml?id=" +
patient[:id].to_s + "\">Show/Edit</a>" %></td>
<td><%= link_to 'Delete', { :action => 'destroy',
:id => patient },
:confirm => 'Are you sure?',
:method => :post %></td>
</tr>
<% end %>
</table>
...
<br />
<a href="/newPatient.xhtml">New patient</a>
|
Note the changes to the columns displayed. Here you display the ID column, with a Show/Edit link that points to the editPatient form with ID appended in the URL (this is how the grab view knows which record to read from the database and return to the XForm). Note the link to add a new patient at the bottom. Click this link to open the form you created in Part 2 of this series.
Take a look at this form in Figure 1.
Figure 1. Listing patients
Click on one of the links, and you see the editPatient form with the existing data correctly displayed, as in Figure 2.
Figure 2. Viewing existing data in the editPatient form
Here you can edit the data as desired. Note that when you submit the form, you go to the kiosk/update script rather than the kiosk/create script as defined in Listing 1. Note the id variable in the URL, which is how the grab controller in Listing 2 knows which id to fetch from the database.
Before you select the Submit Information button, you'll modify the update method in the kiosk controller.
You'll modify the update controller to handle XForms submission data and store it in the database, and replace existing XML data. Update the kiosk controller as defined in Listing 4.
Listing 4. Updating the update method in the kiosk controller
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
|
Note the similarity between this and the create controller. The difference lies in how you retrieve the existing patient information using the referring URL. To start, the method creates an XML document of the XForms submission data, then it retrieves the existing patient from the database, replaces the existing XML data with the new data, and saves it to the database.
That'll do it! It's amazing how a few changes to the user interface can make the patient tool that much more powerful. Now you can view and update existing patients records.
The nurse approval form (triagePatient.xhtml) allows nurses to edit and approve data entered by patients from an entirely different view (triage) that you'll create. The triagePatient form allows nurses to edit patient information only using a Submit Information button, and to edit and approve patient information using an Approve button. Before you start on the form, however, a new field is required in the patients table and you'll add it next.
A new approve field in the patient schema allows you to determine which information have been approved by nurses and which hasn't. To modify the patient schema, open the DB2 Control Center, and look up the Patients table, as in Figure 3.
Figure 3. Altering the patient schema
Right-click the Patient table, and click Alter as shown above. On the screen that comes up, click Add and enter the new field information, as in Figure 4.
Figure 4. Adding an approved field
Note the values for name, data type, default value and Nullable. Click OK twice. The Control Center should then give you final notification that the alteration was successful, and you should see the udpated table schema, similar to that in Figure 5.
Figure 5. Updated patient schema
If you use the DB2 Control Center, you don't really need to use the command line tool.
Now you're ready to create the Triage view.
You'll associate a triage view and controller along with patient model for the nurse's XForm. To create the new view and controller, type the code in Listing 5.
Listing 5. Creating a triage view and controller
ruby script/generate scaffold patient triage
exists app/controllers/
exists app/helpers/
create app/views/triage
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/triage/_form.rhtml
create app/views/triage/list.rhtml
create app/views/triage/show.rhtml
create app/views/triage/new.rhtml
create app/views/triage/edit.rhtml
create app/controllers/triage_controller.rb
create test/functional/triage_controller_test.rb
create app/helpers/triage_helper.rb
create app/views/layouts/triage.rhtml
identical public/stylesheets/scaffold.css
|
Now update the triage controller (app/controllers/triage_controller.rb) by defining grab and updating the update controllers, as in Listing 6.
Listing 6. Editing in the triage controller.
def grab
id = @request.env["HTTP_REFERER"].split('=')[1]
@patient = Patient.find(id)
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
approvedCode = params[:id]
if approvedCode == "1" then
@patient.approved = "true"
end
@patient.update_attributes(params[:patient])
redirect_to :action => 'list'
end
|
Note that grab is identical to the grab controller for the
kiosk controller (see Listing 2). The only difference with update is the use of the new approved field in the database. Note that this value is grabbed from the ID field, thus if the update URL being called to update this record is http://localhost:3000/triage/update/1 then the patient is approved.
Lastly, make a quick update to the triage layout (app/views/layouts/triage.rhtml), and define it as you did the kiosk layout (<%= yield %>). You'll need it like this if the grab view is going to work. Speaking of the grab view, copy the grab view from the kiosk view (app/views/kiosk/grab.rhtml), and copy it to the triage view folder (app/views/triage). The grab view and controller are now good to go.
Next you'll update the patient class (patient.rb) to account for the new database field.
To saver the approved variable in the database, you need to update the patient class (app/models/patient.rb), as in Listing 7.
Listing 7. Updating the patient class
class Patient < ActiveRecord::Base
def information=(value)
self[:information] = value.to_s
end
def approved=(value)
self[:approved] = value.to_s
end
end
|
The patient class is now ready. Next you'll update the list view.
This is the last view you need to update before you tackle the nurse form. With a correct list view in place, you can click on the name of the patient whose information you wish to edit. Update the list view (app/views/triage/list.rhtml), as in Listing 8.
Listing 8. Updating the list view
<h1>Listing patients</h1>
<table>
<tr>
<th><%= "First Name" %></th>
<th><%= "Last Name" %></th>
<th><%= "Approved" %></th>
</tr>
<% for patient in @patients %>
<% if patient.approved=="false" then %>
<tr>
<td><% doc = REXML::Document.new(patient.information) %>
<%= doc.root.elements["FirstName"] %>
</td>
<td>
<%= doc.root.elements["LastName"] %>
</td>
<td><%=h patient.approved %></td>
<td><%= "<a href=\"../triagePatient.xhtml?id=" +
patient[:id].to_s + "\">Edit/Approve</a>" %></td>
<td><%= link_to 'Destroy', { :action => 'Delete', :id => patient },
:confirm => 'Are you sure?',
:method => :post %></td>
</tr>
<% end %>
<% end %>
</table>
...
|
Here you're experimenting with adding columns from the XML into the listing by displaying the first and last names, as well as whether or not the patient's information has been approved yet. With the if statement after the for loop, you also only display to the nurses the patients whose information is not yet approved. Important to note is how the first and last names are retrieved from the XML. First a new XML document is created, passing in the XML information, and then the FirstName element is retrieved with the call to doc.root.elements["FirstName"]. The last name is retrieved in this same way. Also check out the Edit/Approve link. When you click this link, it takes you to the triagePatient form, which you'll create next.
Before you work on the triagePatient form, look at the triage list view in Figure 6.
Figure 6. Triage list view
Now, on to the triagePatient form.
All the Ruby scripts are ready to accept XForms submission data. You only need to define the triagePatient XForm. Be sure to name it triagePatient.xhtml and place it in your public folder. Define it, as in Listing 9.
Listing 9. The triagePatient XForm
...
</p:Info>
</xf:instance>
<xf:submission action="http://localhost:3000/triage/update/0"
method="post"
id="submit-info"/>
<xf:submission action="http://localhost:3000/triage/update/1"
method="post"
id="approve"/>
<xf:submission id="load_data"
action="http://localhost:3000/triage/grab/0"
method="post"
replace="instance"
/>
<xf:action ev:event="xforms-ready">
<xf:dispatch name="xforms-submit" target="load_data"/>
</xf:action>
...
<xf:label>Submit Information</xf:label>
</xf:submit>
</div>
<div id="approve">
<xf:submit submission="approve">
<xf:label>Approve</xf:label>
</xf:submit>
</div>
</p>
<a href="triage/list">Back to List</a>
</body>
</html>
|
The form in Listing 9 is similar to the editPatient form (in Listing 1), and so the differences between the two are shown above. The load_data and submit-info submission elements are exactly the same except they now point to the triage scripts. There is also a new submission element here with id="approve" that points to the following URL as shown above in Listing 9:
http://localhost:3000/triage/update/1 |
This URL has an id of 1, thus setting the approved field of the patient record to true, as shown back in the triage update control in Listing 5. A new submit button labeled Approve activates this new submission element. See the XForm in action in Figure 7.
Figure 7. Viewing patient data for approval in the triagePatient form
To set the approved field to true in the database, click Approve. This also removes it from the list view, as shown in Figure 8.
Figure 8. Approving a patient's information
You've successfully completed the work outlined in this article.
Your Ruby, XForms, and DB2 skills are coming along nicely. You're learning how to integrate Ruby and XForms, as well as the joys and user friendliness of using DB2 and its Control Center.
Be sure to come back for Part 4, where you'll create a form for the doctor, including a completely new form for doctors and nurses to look up patients by last name.
| Description | Name | Size | Download method |
|---|---|---|---|
| Part 3 sample code | part3_doctorsOffice.zip | 11KB | HTTP |
Information about download methods
Learn
-
XForms and Ruby on Rails at the doctor's office, Part 1L 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 4: Implementing the doctor and patient lookup XForm (Tyler Anderson, developerWorks, June 2008): Integrate XForms, IBM DB2 pureXML, and Ruby to rapidly build XML-centric Web apps. Complete the sample app with a new XForm to look up patients by last name.
- 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 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 Ajax for Java developers: Exploring the Google Web Toolkit (Philip McCarthy, developerWorks, June 2006).
- Get started with Ruby on Rails and DB2 with 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 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 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 with 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 Overview of new DB2 Version 9.5 pureXML enhancements (Manaj Sardana, developerWorks, November 2007).
- Learn about using XQuery with DB2 in 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 XMLMatters: 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.
Comments (Undergoing maintenance)





