Автор: Derek Wischusen
Перевод: Андрей Горбатов
Данное приложение продемонстрирует интеграцию Flex2, Ruby on Rails и MySQL на примере создания приложения, отслеживающего ошибки. Данное приложение будет добавлять баги в базу данных, удалять их, обновлять и выводить в таблицу.
Необходимо
Почему Rails?
Flex + Rails + Ruby = RIA Nirvana.
Создание пользовательского интерфейса
Для начала создадим пользовательский интерфейс.
Открываем Flex Builder, создаем новое приложение (File > New > Flex Project). Назовем его flex_issuetracker. Теперь откроем файл flex_issuetracker.mxml и добавим код:
<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">
<mx:Script>
<![CDATA[
[Bindable]
private var statusArray:Array = ["Opened", "Assigned", "Closed"];
[Bindable]
private var priorityArray:Array = ["Blocker", "Critical", "Major", "Minor", "Trivial"];
]]>
</mx:Script>
<mx:VDividedBox x="0" y="0" height="100%" width="100%">
<mx:Panel width="100%" height="376" layout="absolute" title="Create/Update Bugs">
<mx:Form x="10" y="10" width="930" height="280">
<mx:FormItem label="Reported by">
<mx:TextInput width="220" id="reportedby" text="{bugs_dg.selectedItem.reportedby}"/>
</mx:FormItem>
<mx:FormItem label="Assigned to">
<mx:TextInput width="220" id="assignedto" text="{bugs_dg.selectedItem.assignedto}"/>
</mx:FormItem>
<mx:FormItem label="Description">
<mx:TextArea width="336" height="111" id="description" text="{bugs_dg.selectedItem.description}"/>
</mx:FormItem>
<mx:FormItem label="Status" width="287">
<mx:ComboBox width="199" id="status" selectedIndex="{statusArray.indexOf(bugs_dg.selectedItem.status)}">
<mx:dataProvider>
{statusArray}
</mx:dataProvider>
</mx:ComboBox>
</mx:FormItem>
<mx:FormItem label="Priority">
<mx:ComboBox width="199" id="priority" selectedIndex="{priorityArray.indexOf(bugs_dg.selectedItem.priority)}">
<mx:dataProvider>
{priorityArray}
</mx:dataProvider>
</mx:ComboBox>
</mx:FormItem>
</mx:Form>
<mx:ControlBar horizontalAlign="right">
<mx:Button label="Clear" />
<mx:Button label="Update" />
<mx:Button label="Create" />
</mx:ControlBar>
</mx:Panel>
<mx:Panel width="100%" height="444" layout="absolute" title="Bugs">
<mx:DataGrid x="0" y="0" width="100%" height="100%" id="bugs_dg" >
<mx:columns>
<mx:DataGridColumn headerText="Reported by" dataField="reportedby"/>
<mx:DataGridColumn headerText="Assigned to" dataField="assignedto"/>
<mx:DataGridColumn headerText="Description" dataField="description"/>
<mx:DataGridColumn headerText="Status" dataField="status"/>
<mx:DataGridColumn headerText="Priority" dataField="priority"/>
</mx:columns>
</mx:DataGrid>
<mx:ControlBar horizontalAlign="right">
<mx:Button label="Delete" />
</mx:ControlBar>
</mx:Panel>
</mx:VDividedBox>
</mx:Application>Данный код делает следующее:
1. Создает форму для добавления новых багов и редактирования существующих. Поля FormItems обновляются автоматически при выборе рядов таблицы с помощью связывания данных. Форма заключена в контейнер Panel. Внизу Panel создается ControlBar с тремя кнопками, которые управляют записями багов.
<mx:Panel width="100%" height="376" layout="absolute" title="Create/Update Bugs">
<mx:Form x="10" y="10" width="930" height="280">
<mx:FormItem label="Reported by">
<mx:TextInput width="220" id="reportedby" text="{bugs_dg.selectedItem.reportedby}"/>
</mx:FormItem>
<mx:FormItem label="Assigned to">
<mx:TextInput width="220" id="assignedto" text="{bugs_dg.selectedItem.assignedto}"/>
</mx:FormItem>
<mx:FormItem label="Description">
<mx:TextArea width="336" height="111" id="description" text="{bugs_dg.selectedItem.description}"/>
</mx:FormItem>
<mx:FormItem label="Status" width="287">
<mx:ComboBox width="199" id="status" selectedIndex="{statusArray.indexOf(bugs_dg.selectedItem.status)}">
<mx:dataProvider>
{statusArray}
</mx:dataProvider>
</mx:ComboBox>h
</mx:FormItem>
<mx:FormItem label="Priority">
<mx:ComboBox width="199" id="priority" selectedIndex="{priorityArray.indexOf(bugs_dg.selectedItem.priority)}">
<mx:dataProvider>
{priorityArray}
</mx:dataProvider>
</mx:ComboBox>
</mx:FormItem>
</mx:Form>
<mx:ControlBar horizontalAlign="right">
<mx:Button label="Clear" />
<mx:Button label="Update" />
<mx:Button label="Create" />
</mx:ControlBar>
</mx:Panel>
2. Следующий код создает компонент
DataGrid, отображающий существующие записи багов и
позволяющий их выбирать для обновления или удаления. Параметр колонок
dataField используется для определения имени атрибута в
dataprovider. Данных для наполнения еще нет, но важно
иметь ввиду, что имена столбцов таблицы базы данных должны с ними
совпадать. DataGrid также заключен в Panel с ControlBar,
который содержит единственную кнопку для удаления выбранной записи.
<mx:Panel width="100%" height="444" layout="absolute" title="Bugs">
<mx:DataGrid x="0" y="0" width="100%" height="100%" id="bugs_dg" >
<mx:columns>
<mx:DataGridColumn headerText="Reported by" dataField="reportedby"/>
<mx:DataGridColumn headerText="Assigned to" dataField="assignedto"/>
<mx:DataGridColumn headerText="Description" dataField="description"/>
<mx:DataGridColumn headerText="Status" dataField="status"/>
<mx:DataGridColumn headerText="Priority" dataField="priority"/>
</mx:columns>
</mx:DataGrid>
<mx:ControlBar horizontalAlign="right">
<mx:Button label="Delete" />
</mx:ControlBar>
</mx:Panel>
3. Компоненты Panel находятся в
контейнере VdividedBox, который позволяет изменять
пространтсво отведенное для них.
4. Следующий код определяет два
массива, которые используются в качестве источников данных для
ComboBox.
[Bindable]
private var statusArray:Array = ["Opened", "Assigned", "Closed"];
[Bindable]
private var priorityArray:Array = ["Blocker", "Critical", "Major", "Minor", "Trivial"];Создание Rails приложения
Создадим базу данных:
CREATE flex_issue_tracker_development
Это все, что должен сделать SQL. Остальное берет на себя Rails.
Для создания Rails приложения, откроем командную строку... Нет! Откроем Radrails. File > New > Rails > Rails Project. Введем имя issue_tracker и жмем Finish (рис.1).
Аналогичная команда:
rails issue_tracker
Данная команда создает структуру каталогов и файлов, необходимых для приложения.
Рис.1 Создание нового приложения
Теперь создадим модель. Открываем вкладку Generators. Выбираем из выпадающего меню model, пишем в текстовом поле название модели bug. Должен быть отмечен радиобаттон Create. Жмем Go (рис.2).
Рис. 2 Создание модели
Модель создана.
Аналогичная команда:
ruby script/generate model bug
Теперь необходимо создать контроллер. Контроллер содержит логику взаимодейтсвия между видом (Flex-приложение) и моделью. Контроллер создается так же как и модель, но из выпадающего меню выбирается controller и в название пишется bugs.
Аналогичная команда:
ruby script/generate controller bugs
Теперь перейдем в папку приложения app > controllers (рис.3). Там находится файл bugs_controller.rb, который только что был сгенерирован. Откройте его и добавьте следующий код.
Рис.3 Папка controllers
def create @bug = Bug.new(params[:bug]) @bug.save render :xml => @bug.to_xml end def list @bugs = Bug.find :all render :xml => @bugs.to_xml end def update @bug = Bug.find(params[:id]) @bug.update_attributes(params[:bug]) render :xml => @bug.to_xml end def delete @bug = Bug.find(params[:id]) @bug.destroy render :xml => @bug.to_xml end
Эти методы реализуют CRUD функциональность.
params:
Эта переменная является хэшем, который автоматически наполняется
значениями аргументов, передающихся методу.
Bug:
это ссылка на ActiveRecord, которая была создана при генерации
модели. По правилам, название таблицы базы данных должно быть
множественным числом названия модели. То есть при создании модели
«bug» Rails ищет таблицу «bugs».
find:
данный метод ищет записи в базе данных для определенной таблицы.
Bug.find
:all возвращает
все записи таблицы bugs. Bug.find(params[:id])
возвращает все записи, в которых id соответствует переданному
значению. Обратите внимание, что в Rails для всех таблиц поле id
является основным ключом.
new:
создает новый экземпляр ActiveRecord.
save:
сохраняет запись в базе данных.
update_attributes:
обновляет запись переданными значениями.
destroy:
удаляет запись.
to_xml:
создает XML документ из модели.
Важно заметить, что все методы
в Ruby возвращают значение. Если вы не используете return,
Ruby методы возвращают значение последней строки метода.
Теперь создадим доступ приложения к базе данных. Откроем файл database.yml, который находится в папке config и добавим свои значения для имени пользователя и пароля:
development:
adapter: mysql
database: flex_issue_tracker_development
username: <имя пользователя>
password: <пароль>
host: localhostДанное приложение будет запущено только в режиме разработки, поэтому необходимо заполнить только блок development.
Следующим этапом будет добавление таблицы в базу данных. Наиболее просто это сделать с помощью Rails migrations. Migrations устраняют необходимость использовать SQL команды для создания таблиц. Существуют и другие преимущества, но это выходит за рамки данного урока.
Чтобы реализовать migration, перейдем в папку db > migrate. Откроем файл 001_create_bugs.rb и внесем код:
class CreateBugs < ActiveRecord::Migration
def self.up
create_table :bugs do |t|
t.column :reportedby, :string
t.column :assignedto, :string
t.column :description, :text
t.column :status, :string
t.column :priority, :string
end
end
def self.down
drop_table :bugs
end
endМетод up создает таблицу из шести колонок:
id
reportedby
assignedto
description
status
priority
Обратите внимание, что названия
колонок соответствуют значениям атрибутов dataField
в DataGrid
Flex приложения. Метод down удаляет таблицу.
Чтобы запустить migration, перейдите в командную строку каталога приложения и выполните команду:
rake migrate
Теперь откройте перспективу Data и нажмите дважды на ветвь development. Перед нами предстанет таблица bugs (рис.4).

Рис.4 Таблица bugs.
Тот же результат можно достичь и с помощью командной строки (рис.5):
USE
flex_issue_tracker_development
DESCRIBE bugs;

Рис.5 Таблица bugs в командной строке.
Теперь запустим сервер, нажав на кнопку Start вкладки Servers.
Аналогичная команда:
ruby script/server
Сервер будет запущен на 3000 порту.
Все, Rails приложение готово. Запустить в браузере его можно, перейдя на страницу http://localhost:3000 или нажав Launch Browser вкладки Servers.
Интеграция
Теперь
необходимо заставить взаимодействовать Flex интерфейс и Rails
приложение. Это можно сделать с помощью HTTPService вызовов методов
create, list, update и delete,
определенных в файле bugs_controller.rb Rails приложения. Добавьте
следующий код в начало Flex приложения:
<mx:HTTPService id="listBugs" url="http://localhost:3000/bugs/list" useProxy="false" method="GET"/>
<mx:HTTPService id="updateBug" url="http://localhost:3000/bugs/update" useProxy="false" method="POST" result="listBugs.send()"/>
<mx:HTTPService id="deleteBug" url="http://localhost:3000/bugs/delete" useProxy="false" method="POST" result="listBugs.send()"/>
<mx:HTTPService id="createBug" url="http://localhost:3000/bugs/create" useProxy="false" method="POST" result="listBugs.send()"
contentType="application/xml">
<mx:request xmlns="">
<bug>
<reportedby>{reportedby.text}</reportedby>
<assignedto>{assignedto.text}</assignedto>
<description>{description.text}</description>
<status>{status.text}</status>
<priority>{priority.text}</priority>
</bug>
</mx:request>
</mx:HTTPService>
Каждый HTTPServices создает вызов
метода. Параметр url
имеет структуру: http://<адрес
сервера>/<имя контроллера>/<имя метода>.
При рпазмещении приложения не
забудьте поменять абсолютные адреса на относительные:
url="http://localhost:3000/bugs/list"
на url="bugs/list"
и переместить SWF и
HTML файлы Flex приложения в папку public Rails приложения.
Теперь отредактируем код кнопок:
<mx:Button label="Clear" click="clearForm()"/> <mx:Button label="Update" click="sendBugUpdate(); clearForm()"/> <mx:Button label="Create" click="createBug.send(); clearForm()"/>
И еще одной:
<mx:Button label="Delete" click="deleteBug.send({id:bugs_dg.selectedItem.id}); "/>
Добавим к DataGrid
атрибут dataProvider,
связывающий результат выполнения
listbugs:
<mx:DataGrid x="0" y="0" width="100%" height="100%" id="bugs_dg" dataProvider="{listBugs.lastResult.bugs.bug}">
Теперь добавим обработчик события
creationComplete:
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="listBugs.send()">
Наконец, добавим некоторый код в блок
<mx:Script>
после определения массивов:
private function clearForm():void
{
reportedby.text = ""
assignedto.text = "";
description.text = "";
status.selectedIndex = 0;
priority.selectedIndex = 0;
}
private function sendBugUpdate():void
{
var bugUpdate:Object = new Object();
bugUpdate['id'] = bugs_dg.selectedItem.id;
bugUpdate['bug[reportedby]'] = reportedby.text;
bugUpdate['bug[assignedto]'] = assignedto.text;
bugUpdate['bug[description]'] = description.text;
bugUpdate['bug[status]'] = status.text;
bugUpdate['bug[priority]'] = priority.text;
updateBug.send(bugUpdate);
}
Вот и все. Теперь при запущенном сервере, запустите приложение, создайте несколько записей, обновите, удалите их.