レベル: 中級 Tyler Anderson (tyleranderson5@yahoo.com), Freelance writer
2008年 6月 10日 この記事は、XForms と IBM® DB2® pureXML™、そして Ruby を一緒に使うことで容易に Web アプリケーションを作成する 4 回シリーズの第 4 回です。このシリーズでは、病院で患者の情報を管理するための、仮定のアプリケーションを作成し、XForms、DB2 pureXML、そして Ruby on Rails それぞれの技術が個々に持つ強みの一端を知ると共に、これらの技術を併せて使用する方法も学びます。シリーズ第 4 回の今回は病院用の XForms の作成を続け、苗字によって患者を検索する、まったく新しいフォームを作成します。
はじめに
このシリーズの前回の記事までに、患者や看護師が患者データを扱う上での補助となる DB2 データベースと 3 つの XForms を作成しました。また、患者が新しい患者レコードをデータベースに追加することができ、追加した後で患者が自分の情報に戻って更新できる処理インターフェースとして、Ruby on Rails を使用しました。その結果、看護師は患者が医師の診察を受けるための準備として、そうした患者の情報を開いて、適切な編集を行い、入力された情報を承認することができるようになりました。
シリーズ最終回であるこの第 4 回では、医師用の新しいビューとコントローラーを作成し、このビューのための新しい XForms も 2 つ作成します。最初のフォームでは、医師は患者が入力して看護師が承認したものと同じ患者レコードを見ることができるのに加え、その患者を診察したことによる追加情報を入力することができます。次に、医師と看護師が苗字で患者情報を検索できるフォームを作成します。
前提条件
この記事では XML と Web アプリケーションに関して全般的に慣れていることを前提としています。これまでに 3 つのコア技術 (XForms とDB2 pureXML、そして Ruby on Rails) を経験したことがあれば役立ちますが、決してそれが必須なわけではありません。この記事を執筆するにあたり、Mozilla XForms プラグインのバージョン 0.8.0.3 を使用しました。このプラグインによって、Firefox を始めとするすべての Mozilla ブラウザーで XForms ランタイムをサポートすることができます。もう 1 つ、Mozilla 用の非常に便利なプラグインが XForms 用のデバッガーである XForms Buddy です。この記事では XForms Buddy のバージョン 0.5.6 を使用しました。また IBM の DB2 データベース・サーバーも必要です。この記事では Windows® システムと Linux® システム、そして UNIX® システムで使用できる DB2 Express-C バージョン 9.5 を使用しています。最後に、Ruby on Rails が必要です。この記事では Ruby 1.8.6 と Rails 1.2.5 を使用しています。また Rails と合わせて Mongrel Web サーバーも使っています。Mongrel は Ruby Gems から入手することができます (コマンドラインから gem install mongrel と入力すればよいだけです)。ダウンロード用のリンクは「参考文献」を参照してください。
医師の診察のための XForms
医師用の XForms (doctorPatient.xhtml) の目的は、患者がキオスクで入力し、また看護師が承認したものとまったく同じ情報を医師が見られるようにすることです。医師用の XForms ではさらに、その患者を診察したことによる追加の情報を、その医師が入力できる必要があります。こうしたことを念頭に置くと、doctorPatient フォームは triagePatient フォームと似ていますが、いくつかの違いがあります (リスト 1)。このファイルに doctorPatient.xhtml という名前を付け、このファイルを公開フォルダーに保存します。
リスト 1. doctorPatient フォーム
...
<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>
|
まず、インスタンス・データの中に、BPressure と Notes という 2 つの要素が追加されていることに注目してください。この 2 つのフィールドには、それぞれ医師が測定した患者の血圧と、医師がテキスト・フィールドに入力できるコメントが含まれています。ここでは submit-info という submission 要素の action 属性と load_data という submission 要素の action 属性は doctor コントローラーを指しています。最後に、この XForms の body の中で 2 つの新しい XForms 要素が宣言されていることがわかります。
次に、doctor のビューとコントローラーに対する scaffold を生成します。
doctor のビューとコントローラー
Rails の scaffold は Ruby アプリケーションを開発する際の素晴らしい出発点となります。まず、doctor のビューとコントローラー用に scaffold を生成します (リスト 2)。
リスト 2. doctor のビューとコントローラー用に scaffold を生成する
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
|
多くのものが既に作成されており、まだ存在していないファイルのみが Rails によって作成されることに注意してください。次に、doctor コントローラーの中で grab メソッドと update メソッドを定義します (リスト 3)。
リスト 3. doctor コントローラーの中で grab メソッドと update メソッドを定義する
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
|
最初に気付くことは、grab メソッドは他の 2 つのコントローラー (kiosk と triage) と大きく異なることです。これは、2 つの新しい要素 (BPressure と Notes) が、新たに作成され承認された (データベースの中の) レコードには、まだ存在していないためです。従ってレコードが要求されると、この 2 つの新しい XML 要素がそれぞれ検索され、もしその要素が存在していない場合には、その要素を XML に追加してから grab ビューをとおして XForms に送り返す必要があります。BPressure 要素と Notes 要素が共にその XML 文書の中に存在することが確認されると、患者情報 (patient.information) フィールドは doc 変数の中に含まれる新しい XML として設定されます。
update メソッドに移る前に、grab.rhtml を triage ビュー (app/views/triage/grab.rhtml) から doctor ビュー (app/views/doctor) にコピーします。これで grab ビューは完成です。
この場合の update メソッドには何も新しい機能はありませんが、新しい XML データを DB2 に保管するためにはこのメソッドが絶対に必要です。
では次に進み、医師用の list ビューを変更します。
医師用の list ビュー
医師はこのビューによって、看護師が既に情報を承認したすべての患者の苗字 (Last Name) と名前 (First Name) を見ることができます。この list ビュー (app/views/doctors/list.rhtml) をリスト 4 のように変更します。
リスト 4. 医師用の list ビューを変更する
<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>
...
|
ここでは医師が見るための First name と Last name を出力しています。またリスト 4 で、doctorPatient フォームを指す View/Add Notes リンクに注目してください。ユーザーがこのリンクをクリックすると、これまでのフォームでは入力できなかった情報 (血圧とコメント) を医師が入力できる XForms が開きます (図 1)。
図 1. 医師用の XForms の表示
医師は患者の苗字と名前を見ることができ、また View/Add Notes リンクをクリックすると、その患者が XForms の中に表示されます (図 2)。
図 2. doctorPatient XForms の実際
このフォームでは、医師が Please describe your symptoms (症状を記入してください) というテキスト・ボックスに記述を追加したり、患者の血圧を入力したり、Notes regarding visit with patient (患者の診察に関するコメント) というボックスにこの診察に関する任意のコメントを入力したりすることができます。この情報を送信すると、ユーザーには図 1 の Web ページが返されます。
これで医師用のフォームは完成です。では次に、患者を検索するためのフォームを作成しましょう。
患者検索用のフォーム
さて、スクロールが必要なほど沢山の患者がいるとしたらどうでしょう。そうした場合には、多忙な病院での患者情報の検索作業が時間のかかるものになってしまいます。これから作成する、医師と看護師が患者を苗字で検索できるフォームによって、手動で検索していた検索時間を短縮することができます。この新しいフォームには、すべての患者情報を 1 つの XML 文書の中に配置し、その XML 文書を XForms に返す、新しい graball ビューが必要です。最初にこの新しいビューを作成し、その次に、新しい XForms そのものを作成します。
graball コントロールを作成する
graball コントロールはその名前のとおり、データベースの中にあるすべての患者を 1 つの XML ファイルに入れて返す新しいビューです。doctor ビューのディレクトリー (app/views/doctor/graball.rhtml) に新しいファイルを作成し、それをリスト 5 のように定義します。
リスト 5. graball ビューを作成する
<% @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>" %>
|
このビューは grab ビューと同様、まず Content-Type ヘッダーを「text/xml」に設定します。こうすることで Mongrel と Firefox はこのビューの処理方法を認識することができます。次に Patients という開始タグがあり、名前空間が設定されています。興味深い部分が for ループです。このループではデータベースの中にある各患者データに対してループにより独自の <Info>...</Info> タグ・セットが XML 文書の中で与えられます。そして Info タグは次の 3 つの属性を持ちます。
-
DbId
—その患者に対応する、データベースの中の ID
-
ViewEditLinkDoc
—これは doctorPatient フォームの中に患者の情報を表示するためのリンクを含むローカル変数です。
-
ViewEditLinkTri
—ViewEditLinkDoc と同様、これもローカル変数ですが、こちらは患者の情報を triagePatient フォームに表示します。
Info タグの開始タグを並べた後、患者の XML レコードからその患者の苗字 (LastName) を取得します。これは list ビューで苗字 (LastName) を取得する場合とまったく同じです (リスト 4)。</Info> 終了タグによって、その患者の情報を XML の中に入れる作業が完了します。他に患者がいなくなると、for ループの実行が終了し、</Patients> 終了タグが書き込まれて XML が完成します。
doctor コントローラーには、これに対応する graball メソッドがないことに注意してください。これをリスト 6 のように定義します。
リスト 6. doctor コントローラーの graball メソッド
def graball
@patient = Patient.find_by_sql("select * from patients");
end
|
ID のような固有識別子によって患者を発見する代わりに、SQL 文によって、すべての患者を返すように要求します。この方法で、リスト 5 で定義した graball ビューの中にデータベースの中のすべての患者を入れます。
次に、患者検索用のフォームそのもののコードを作成します。
患者検索用の XForms
いよいよ、このシリーズで最後の XForms にやって来ました。この便利なフォームを利用すると、医師や看護師が患者を苗字 (Last Name) で容易に見つけることができます。新しい XForms (lookupPatient.xhtml) を作成して公開ディレクトリーに保存し、それをリスト 7 のように定義します。
リスト 7. lookupPatient フォームを作成する
<?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>
|
このフォームには、今までこのシリーズに登場したことのない要素がいくつかあります。さらにこのフォームには、別々に管理が必要な 2 つのインスタンス文書があります。searchLastName という ID を持つ最初のインスタンス文書は検索される患者の苗字 (LastName) を含んでいます。patients という ID のインスタンス文書は、load_data という submission 要素によってロードされる XML を含んでいます (この XML は XForms がロードされる際に doctor の graball ビューを呼び出すことによってロードされます)。いったんインスタンス・データがロードされると、患者の XML インスタンス・データの中にある苗字 (LastName) の 1 つに一致する苗字 (Last Name) を入力しない限り、XForms には何も特別なデータが表示されません (図 3)。
図 3. lookupPatient フォーム
リスト 7 の XForms の body の中を見ると、医師と看護師が苗字 (Last Name) を入力して一致検索を行うためのテキスト・ボックスがあります。次に見出し行が設定されていることがわかります。一致した苗字 (Last Name) 用の見出しが 1 つ、そして見つかった各患者の情報を医師または看護師が別々のフォーム (doctorPatient と triagePatient) で開くためのボタン用の見出しが 2 つです。結果が見つかると、そこに repeat 要素が登場します。repeat 要素の nodeset 属性の中の XPath 式は、repeat 文の中でどちらの Info 要素を表示するかを定義します。XML による patients インスタンス・データの中にある苗字 (LastName) とテキスト・ボックスに入力された苗字 (Last Name) が一致する場合には、この XPath によって一致が見つかります。この XPath は、苗字 (LastName) を最初の列に、doctorPatient フォームに患者情報を表示するボタンを 2 番目の列に、そして triagePatient フォームに患者情報を表示するボタンを 3 番目の列に表示します (図 4)。
図 4. lookupPatient フォームの実際
するとこのように、一致した患者データがテーブルの行として表示されます。この、Ajax のような即時処理は「Search Last Name (苗字を検索)」テキスト・ボックスの incremental="true" 属性によって実現されています (リスト 7)。患者データを doctorPatient フォームまたは triagePatient フォームの中に表示するためには、図 4 の中にある 2 つのボタンのいずれかをクリックすればよいだけです。
非常に便利だと思いませんか。これで、Ruby と DB2 pureXML を使って XForms を作成するシリーズが完結しました。
まとめ
何という素晴らしい成果でしょう。この 4 回シリーズの記事の最終回でアプリケーションを完成するに当たり、医師用の XForms を作成し、そして何千件も潜在している可能性がある患者レコードの中から検索するという気の遠くなるような作業を容易にする、患者検索用の最終的な XForms を作成できたのです。
XForms と Ruby on Rails、そして DB2 pureXML の 3 つの技術をマスターしたことによって、これらを組み合わせることの強力さを理解できたはずです。まだ皆さんはこれらの技術を完全にマスターできていないかもしれませんが、その場合は「参考文献」が役立ちます。この 3 つの技術それぞれの知識やスキルを向上させるために役立つ数々の素晴らしいリンクを参考にしてください。では、幸運をお祈りします。
ダウンロード | 内容 | ファイル名 | サイズ | ダウンロード形式 |
|---|
| Part 4 sample code | part4_doctorsOffice.zip | 15KB | HTTP |
|---|
参考文献 学ぶために
製品や技術を入手するために
議論するために
著者について  | |  | Tyler Anderson は、2004年に Brigham Young University でコンピューター・サイエンスの学位を取得し、2005年12月に同大学のコンピューター・エンジニアリングの理学修士を取得して、同大学を卒業しました。Tyler はフリーランス・ライターであり、Backstop Media のライターでもあります。 |
記事の評価
|