@@items[author]
end
end
Теперь контроллер может запрашивать данные у класса Book
. Изменим метод index
:
def index
book = Book.find_by_author('Mark Twain')
@author = book.author
@title = book.title
@last_update = book.update_time
end
А в файл run.rb
вставим ссылку на модель Book
и загрузим какие- нибудь данные:
require 'model/book'
Book.new(:title => 'Life on the Mississippi',
:author => 'Mark Twain').save
После перезапуска приложения и перезагрузки страницы мы увидим сведения о книге. А если книг больше? Вместо того чтобы «зашивать» в код данные о них, мы можем попросить контроллер выполнить поиск по имени автора. Добавим в него новый метод find
:
def find(author)
book = Book.find_by_author(author)
@author = book.author
@title = book.title
@last_update = book.update_time
end
Это тот же код, что в методе index
(и для создания соответствующего ему шаблона достаточно было бы переименовать index.xhtml
в find.xhtml
), но он принимает один аргумент — имя автора. Хотя мы разрабатываем Web-приложение, класс контроллера мало чем отличается от класса в любом другом приложении, написанном на Ruby. Самое заметное отличие заключается в том, что методы не возвращают значений, но никаких зависимостей от специальных переменных окружения или каких-то особых объектов нет. (Впрочем, имейте в виду, что Nitro все же добавляет разные «приятности» для программирования Web-приложений; для доступа к ним достаточно унаследовать свой класс от Nitro::Controller.
) Например, Nitro обеспечивает «обстраивание», быструю передачу сообщений от одного запроса другому и хитроумный конвейер конструирования страницы, но все это только если вы сами захотите.
Сделаем еще одно замечание по поводу методов контроллера. Методы, предназначенные для обработки запросов на получение страницы, обычно идут в паре с шаблонами, имеющими схожее имя. Для получения конечного результата Nitro объединяет метод и шаблон. Мы видели, что Nitro может работать без контроллеров, ограничиваясь только видами. Но верно и обратное. Метод контроллера может генерировать всю страницу вообще без шаблона. Запросы на получение страниц обрабатываются в Nitro как действия (actions).
Например, некоторый URL может отвечать на запрос, возвращая лишь название книги. Для этого достаточно такого метода контроллера BookController
:
def sparse(author)
@context.content_type = 'text/plain'
book = Book.find_by_author(author)
book.title
end
Если метод контроллера возвращает не HTML-документ, то следует изменить заголовок content-type, отравляемый вместе с ответом в результате присваивания @context.content_type=
. (Кстати, даже если парный шаблон существует, его можно не использовать, переопределив метод render_text
.)
Но откуда метод find
или sparse
получает аргумент? По умолчанию Nitro следует привычному для Web-приложений паттерну, согласно которому сегменты пути URL отображаются на контроллеры, методы и аргументы. Перезапустите приложение и введите такой URL: http://127.0.0.1:9999/books/find/Hal%20Fulton.
Обратите внимание, что %20
— это кодированное представление пробела в имени автора. Nitro производит декодирование еще до вызова метода find
.
В общем случае отображение URL выполняется так: /controller/method/arg1
. Дополнительные аргументы можно передать в виде последующих сегментов пути. Впрочем, в Nitro есть механизм настройки маршрутизации, так что вы не обязаны отражать в URL детали реализации.
19.4.3. Nitro и Og
Хотя библиотека объектно-реляционного отображения Og, используемая в паре с Nitro, рассматривалась в другом месте, наше изложение было бы неполным без демонстрации того, как просто добавить к приложению интерфейс с базой данных. Сначала настроим Og в файле run.rb
:
# Прямо перед вызовом Book.new :
require 'og'
Og.setup(:store => 'mysql',
:name => 'demo',
:user => 'root',
:destroy => true,
:port => 3316)
Затем изменим модель Book
:
require 'glue/timestamped'
class Book
is Timestamped
property :title, String
property :author, String
def initialize{ values = {} )
@title, @author = values[:title], values[:author]
end
end
От хранения экземпляров Book в переменных класса мы отказались. Вызовы attr_accessor
заменены обращением к методу property
, который служит нескольким целям. Он тоже создает методы доступа к переменным, но, кроме того, сообщает Og
, что этот класс должен обладать устойчивостью. Метод initialize
почти не изменяется, но затребовав файл timestamped
и поместив в класс маркер is