IBM®
Перейти к тексту
    в России и странах СНГ [изменить]    Условия использования
 
 
   
    Главная страница    Продукты    Услуги и решения    Поддержка и загрузка    Мой профиль    
Перейти к тексту

developerWorks Россия  >  XML | Information Management  >

XForms и Ruby on Rails в кабинете врача: Часть 4. Создание форм для врача и для поиска карточек пациентов

developerWorks
Опции документа

Опции документа, требующие включения JavaScript, не отображаются

Обсудить

Исходные тексты примера


Выскажите мнение об этой странице

Помогите нам улучшить содержание


Уровень сложности: средний

Тайлер Андерсон, независимый автор, Backstop Media

24.08.2009

Это четвертая часть серии из четырех статей, посвященной совместному использованию XForms, IBM® DB2® pureXML™ и Ruby для упрощения создания Web-приложений. В этой серии мы разрабатываем гипотетическое приложение для управления информацией о пациентах в кабинете врача. Вы получите представление об отдельных достоинствах каждой технологии, но также увидите, как объединить их друг с другом. В четвертой части мы продолжим разработку форм для кабинета врача и добавим новую форму для поиска пациентов по фамилии.

Введение

Мы уже создали базу данных DB2 и три формы XForms, которые помогают пациентам и медсестрам работать со сведениями о пациентах. В качестве интерфейса обработки для добавления в базу данных новых карточек пациентов и последующего редактирования этой информации применялся Ruby on Rails. Теперь медсестра имеет возможность просматривать информацию, вносить необходимые поправки и утверждать введенные данные, чтобы пациент мог отправиться на прием к врачу.

Другие статьи этой серии

В этой последней, четвертой статье мы создадим новое представление и контроллер для врача, а также две новые формы XForms для этого представления. Первая форма позволит врачу просматривать данные, введенные пациентами и утвержденные медсестрой, а также вводить дополнительную информацию, связанную с осмотром пациента. Затем мы разработаем форму, при помощи которой врачи и медсестры смогут искать карточки пациентов по фамилии.



В начало


Предварительные замечания

Эта статья предполагает знакомство с XML и Web-приложениями в целом. Конечно, будет полезно предварительное знакомство с тремя основными технологиями, XForms, DB2 pureXML и Ruby on Rails, но это не обязательно. При написании статьи использовался плагин Mozilla XForms версии 0.8.0.3. Он обеспечивает поддержку XForms в любом браузере Mozilla, в частности, Firefox. Другой очень полезный плагин Mozilla — XForms Buddy. Это отладчик для XForms. Для этой статьи использовалась версия 0.5.6. Нам также потребуется сервер баз данных IBM DB2. Для этой статьи используется DB2 Express-C версии 9.5. Он работает на системах Windows®, Linux® и UNIX®. Наконец, нам потребуется Ruby on Rails. Для этой статьи используется Ruby 1.8.6 с Rails 1.2.5. В этой статье применяется также Web-сервер Mongrel в сочетании с Rails. Его можно получить через Ruby Gems (просто наберите в командной строке gem install). Ссылки для загрузки приведены в разделе Ресурсы.



В начало


Форма для врача

Часто используемые сокращения
  • XML: Extensible Markup Language – расширяемый язык разметки

Форма для врача (doctorPatient.xhtml) позволяет лечащему врачу видеть ту информацию, которую ввел пациент и проверила медсестра. При помощи этой формы врач может также вводить дополнительную информацию по результатам осмотра пациента. Поэтому форма 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. Эти поля будут содержать данные об артериальном давлении пациента, измеренном врачом, и текстовые комментарии. Здесь атрибуты действия элемента передачи submit-info и load_data указывают на контроллер doctor. Наконец, в теле формы объявлены два новых элемента XForms.

Теперь сгенерируем скаффолдинг для представления и контроллера doctor.



В начало


Представление и контроллер doctor

Скаффолдинг Rails служит превосходной исходной точкой для разработки приложения Ruby. Сгенерируем скаффолдинг представления и контроллера doctor, как показано в листинге 2.


Листинг 2. Генерация скаффолдинга представления и контроллера doctor
                
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 создает только отсутствующие файлы. Затем определим методы grab и update в контроллере doctor (листинг 3).


Листинг 3. Определение методов grab и update в контроллере doctor
                
  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 существенно отличается от двух других контроллеров (kiosk и triage). Это связано с тем, что во вновь созданных и утвержденных записях базы данных пока не существует двух новых элементов BPressure и Notes. Поэтому при обращении к записи производится поиск каждого из двух новых XML-элементов, и если их нет, они должны быть добавлены в XML до возврата в форму через представление grab. После добавления в документ XML обоих новых элементов поле с информацией о пациенте устанавливается в соответствии с новым кодом XML, содержащимся в переменной doc.

Прежде чем перейти к методу update, скопируйте grab.rhtml из представления triage (app/views/triage/grab.rhtml) в представление doctor (app/views/doctor). Представление grab готово!

Здесь метод update не несет в себе никакой новой функциональности, но явно необходим для сохранения новых данных XML в DB2.

Теперь отредактируем представление list для врача.



В начало


Представление list для врача

В этом представлении врач может видеть имена и фамилии пациентов, карточки которых утверждены медсестрой. Отредактируем представление 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>
...

В этот список выводятся имена и фамилии пациентов. Обратите также внимание на ссылку View/Add Notes в листинге 4, которая указывает на форму doctorPatient. Когда пользователь нажимает на эту ссылку, он открывает форму, позволяющую врачу вводить информацию (артериальное давление и заметки), которой не было в прежних формах (рисунок 1).


Рисунок 1. Так выглядит форма для врача.
Форма для врача

Теперь врач может просматривать имена и фамилии пациентов и открывать карточку по ссылке View/Add Notes (рисунок 2).


Рисунок 2. Форма doctorPatient в действии
Форма doctorPatient XForm

Врач может делать записи в текстовом окне Please describe your symptoms (укажите, пожалуйста, симптомы), вводить значение артериального давления пациента и делать любые другие замечания, относящиеся к осмотру, в окне Notes. После передачи этой информации возвращается Web-страница, приведенная на рисунке 1.

Форма для врача готова. Теперь создадим форму поиска карточек пациентов.



В начало


Форма поиска карточек пациентов

А что, если пациентов много, и список приходится долго прокручивать? Это усложняет задачу поиска пациентов. Форма, которая позволяет врачам и медсестрам искать карточки пациентов по фамилии, ускорит процесс. Для этой новой формы потребуется представление graball, которое помещает всех пациентов в один документ XML и возвращает его в форму XForms. Сначала создадим новое представление, а затем и саму форму.



В начало


Создание элемента управления graball

Элемент управления graball – это новое представление, которое собирает всех пациентов из базы данных в один XML-файл. Создайте новый файл в каталоге врача (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: в этом цикле каждый пациент из базы данных получает в документе XML свой набор тегов <Info>...</Info>. Тег Info имеет три атрибута:

  • DbId — идентификатор пациента в базе данных;
  • ViewEditLinkDoc — локальная переменная, содержащая ссылку на информацию о пациенте в doctorPatient;
  • ViewEditLinkTri — это тоже локальная переменная, как и ViewEditLinkDoc, но она передает сведения о пациенте в форму triagePatient.

Когда отображается открывающий тег Info, фамилия пациента извлекается из его XML-записи, как в случае представления list (см. листинг 4). Замыкающий тег </Info> заканчивает ввод данного пациента в XML. Если пациентов много, выполняется цикл for, и замыкающий тег </Patients> завершает составление документа XML.

Заметьте, что соответствующий метод graball в контроллере doctor отсутствует. Определим его, как показано в листинге 6.


Листинг 6. Метод graball в контроллере doctor
                
  def graball
    @patient = Patient.find_by_sql("select * from patients");
  end

Вместо поиска по уникальному идентификатору, такому как ID, оператор SQL запрашивает всех пациентов. В результате все пациенты из базы данных извлекаются в представление graball, определенное в листинге 5.

Затем мы создаем собственно форму поиска пациентов.



В начало


Форма поиска карточек пациентов

Это последняя форма, которую мы создадим в этой серии статей. При помощи этой удобной формы врач или медсестра могут легко искать карточки пациентов по фамилии. Создайте новую форму 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>

Эта форма содержит несколько новых элементов, еще не встречавшихся нам в этой серии. В ней есть два экземпляра документа, которыми нужно управлять отдельно. Первый экземпляр документа с идентификатором searchLastName содержит фамилию искомого пациента. Экземпляр документа пациента содержит код XML, загруженный элементом передачи load_data (он отображается путем вызова представления graball для врача при загрузке формы). После загрузки экземпляра данных вы не увидите в форме ничего особенного, пока не введете фамилию, совпадающую с одной из фамилий в списке из экземпляра XML пациента (см. рисунок 3).


Рисунок 3. Форма lookupPatient
Форма lookupPatient

В теле формы из листинга 7 видно текстовое поле, в которое врач и медсестры вводят искомые фамилии. Затем следуют заголовки, один для найденной фамилии и два для кнопок, которые позволяют врачу и медсестрам открывать информацию по каждому найденному пациенту в отдельной форме (doctorPatient, а не triagePatient). Если результат обнаружен, вступает в действие элемент повторения. Оператор XPath атрибута nodeset элемента повторения определяет, какие элементы Info отображаются внутри элемента повторения. Если фамилия из экземпляра XML-данных пациента совпадает с фамилией, введенной в текстовое поле, значит, XPath обнаружил совпадение. Он отображает фамилию в первом столбце, кнопку вызова информации о пациенте в форме doctorPatient во втором столбце и кнопку вызова информации о пациенте в форме triagePatient в третьем столбце (см. рис. 4).


Рисунок 4. Форма lookupPatient в действии
Форма lookupPatient в действии

Данные о найденном пациенте отображаются в строках таблицы. Такая немедленная обработка в стиле Ajax возможна благодаря атрибуту incremental="true" в текстовом поле "Search Last Name" (поиск по фамилии) (см. листинг 7). Чтобы ввести данные о пациенте в любую из форм doctorPatient или triagePatient, просто нажмите одну из кнопок, изображенных на рисунке 4.

Удобно, не правда ли? На этом серия статей, посвященных созданию форм XForms с применением Ruby и DB2 pureXML, завершается.



В начало


Заключение

Итак, в последней части цикла из четырех статей, посвященных разработке приложения для кабинета врача, вы создали форму XForms для врача и последнюю форму для поиска карточек пациентов, которая облегчает задачу поиска среди, возможно, тысяч историй болезни.

Освоив XForms, Ruby on Rails и DB2 pureXML, вы поняли, что эти три технологии составляют отличную команду! Возможно, вы еще не совсем овладели ими, но в этом вам поможет раздел Ресурсы. Там вы найдете много полезных ссылок, которые позволят вам расширить знания и приобрести опыт по каждой из этих трех технологий. Удачи!




В начало


Загрузка

ОписаниеИмяРазмерМетод загрузки
Код примеров для части 4part4_doctorsOffice.zip15 KБHTTP
Информация о методах загрузки


Ресурсы

Научиться

Получить продукты и технологии

Обсудить


Об авторе

Тайлер Андерсон (Tyler Anderson) получил степень бакалавра по компьютерным наукам в Brigham Young University в 2004 и степень магистра по компьютерной технике в декабре 2005 тоже в Brigham Young University. Сейчас он работает инженером в фирме Stexar Corp., расположенной в Beaverton, Ore.




Выскажите мнение об этой странице


Пожалуйста, найдите минутку и заполните форму, чтобы повысить уровень сервиса.



 


 


 


Поделиться этой статьей:

забобрить забобрить memori сохранить в memori




В начало


IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия.
    IBM в России Конфиденциальность Контакты