Skip to main content

XForms and Ruby on Rails at the doctor's office, Part 3: Implementing the nurse and doctor XForm

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 third 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 3 of the series, you will develop a form for nurses to go back and edit patient data, and you'll also learn what you need to do in Ruby to make this happen.

04 Dec 2008 - As a followup to reader comments, instances of three directory names (app/view/..., app/model/..., and app/controller/...) were changed to app/views/... in paragraph 2 after Listing 6 and paragraph 1 of Triage list view, app/models/... in paragraph 1 of Patient class , and app/controllers/... in paragraph 4 of Kiosk grab view and controller.

View more content in this series

Date:  04 Dec 2008 (Published 03 Jun 2008)
Level:  Intermediate
Activity:  4930 views

Introduction

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.


Prerequisites

Frequently used acronyms

  • CSS: Cascading Stylesheets
  • URL: Uniform Resource Locator
  • XML: Extensible Markup Language

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.


Editing existing patient data

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.


Patient edit form

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.


Kiosk list view

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
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
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.


Kiosk update 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.


Nurse approval form

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.


Altering the patients table

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
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
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
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.


Triage view and controller

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.


Patient class

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.


Triage 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
Triage list view

Now, on to the triagePatient form.


Triage XForm

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
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
Approving a patient's information

You've successfully completed the work outlined in this article.


Summary

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.



Download

DescriptionNameSizeDownload method
Part 3 sample codepart3_doctorsOffice.zip11KB 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.

Comments (Undergoing maintenance)



Trademarks  |  My developerWorks terms and conditions

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=311183
ArticleTitle=XForms and Ruby on Rails at the doctor's office, Part 3: Implementing the nurse and doctor XForm
publish-date=12042008
author1-email=tyleranderson5@yahoo.com
author1-email-cc=dwxed@us.ibm.com

My developerWorks community

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.

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).

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).

Rate a product. Write a review.

Special offers