Навигация
Создание формы для ввода информации о заказе
Теперь, когда у нас есть таблицы и модели, можно приступать к процессу оформления заказа. Сначала нам нужно добавить к корзине кнопку Оформить заказ и свя¬жет, ее в контроллере магазина (store) с действием оформления заказа (checkout).
Лсгинг файла app/views/store/_cart.rhtml
class="cart-title" >Ваша Kop3HHa «tafile>
<%= render(:partial => "cart_item" , collection => cart.items) %>
<%=
<%= button_to "Оформить заказ" , <%= button_to "Очистить корзину" number_to_currency(cart.total_price)
%>
Мы хотим, чтобы действие checkout предоставляло пользователю форм}', приглашающую его к вводу информации о его имени, почтовом и электронном адресе и способе оплаты в таблицу заказов orders. Значит, нам где-то нужно со¬здать Rails-шаблон, содержащий эту форму. Поля ввода информации должны быть связаны с соответствующими свойствами в объектах Rails-модели, поэтому нам нужно создать в действии checkout пустой объект модели, чтобы этим по¬лям было с чем работать1. (Нам также следует найти текущую корзину в том виде, в каком она отображается в макете. Поиск корзины в начале каждого действия начинает утомлять; как избавиться от повторения, мы увидим чуть позже.)
Листинг файла app/controllers/store_controller.rb
def checkout
@cart = find_cart
if @cart.iterns.empty?
redirect_to_index("Ваша корзина пуста" )
else
@order = Order.new
end
end
Обратите внимание на проверку наполнения корзины. Она предотвращает пе¬реход пользователей к оформлению и созданию пустых заказов.
Теперь займемся непосредственно шаблоном. Для получения информации о поль¬зователе мы используем форму. Нужно выполнить обычную для HTML-форм задачу: заполнить начальными значениями поля формы, а затем извлечь эти значе¬ния в наше приложение, когда пользователь щелкнет на кнопке передачи данных
Для ссылки на новый модельный объект Order мы объявим в контроллере пе¬ременную экземпляра @order. Наши действия обусловлены тем, что представле¬ние заполняет форму, используя данные этого объекта. Само по себе это обстоя¬тельство не представляет интереса: поскольку модель новая, все поля будут пусты¬ми. Но рассмотрим какой-нибудь общий случай.
Возможно, нам захочется отредактировать существующую модель. Или поль¬зователь может попытаться подтвердить заказ, но его данные не пройдут провер¬ку. В таких случаях нам захочется, чтобы данные, существующие в модели, были показаны пользователю при отображении формы. Передача на данной стадии пустого модельного объекта сохраняет совместимость со всеми этими случаями — представление всегда сможет иметь доступ к этому объекту модели.
Затем, когда пользователь щелкнет на кнопке передачи информации, жела¬тельно, чтобы новые данные извлекались из формы и, возвращаясь контроллеру, передавались в объект модели.
И опять-таки, если вы следите за повествованием, то должны вспомнить, что это дейст¬вие нужно разместить в контроллере до ключевого слова private.
Нам повезло, поскольку Rails со всем этим довольно легко справляется. Она предоставляет в наше распоряжение массу вспомогательных методов. Эти помощ-мки взаимодействуют с контроллером и с моделями для осуществления общего решения по обработке формы. Перед тем как приступить к созданию окончатель¬ного варианта формы, рассмотрим простой пример:
lw»e 1 <% form_for :order, :url => { :action => :save_order } do |form| %>
Ф.И.О.: <%= form.text_field :name, :size => 40 %>
5
<% end %>
В данном коде есть две интересные особенности. Начнем с того, что помощник *ar«_f or в первой строке формирует стандартную HTML-форму. Но он дела¬ет ие только это. Первый параметр, : order, сообщает методу, что он имеет дело с объектом, на который указывает переменная экземпляра под названием @order. эщник использует эту информацию при создании имен полей и при органи-передачи значений этих полей обратно контроллеру. Параметр : url сообщает помощнику, что делать, когда пользователь щелкает ш кнопке передачи. В данном случае у нас генерируется HTTP-запрос POST, который в конечном итоге обрабатывается в действии контроллера save_order.
Заметьте, что f orm_f or открывает Ruby-блок (который заканчивается на шес-шй строке). В этот блок можно поместить обычное содержимое шаблона (к приме-цр. тег <р>). Но параметр блока (в данном случае form) вы также можете исполь-. для ссылки на содержимое формы. Мы воспользовались этим в четвертой е, чтобы добавить в форму текстовое поле. Поскольку текстовое поле создано в вонтексте f orm_f or, оно автоматически связывается с данными объекта ©order.
"Dave"
В этих взаимосвязях нетрудно запутаться. Важно запомнить, что для связи еввделью Rails нужно знать и имена полей, и их значения. Комбинация form_ н различных помощников, предназначенных для работы с полями (таки-как text_f ield), предоставляет ей эту информацию.
Теперь мы можем создать шаблон, предназначенный для формы, которая собирает данные о клиенте, необходимые для оформления заказа. Его вызов будет осуществляться действием checkout в контроллере магазина (store), по¬этому файл шаблона должен называться checkout, rhtml и находиться в каталоге app/views/store.
В Rails имеются помощники для разных HTML-элементов формы. В сле¬дующем примере программного кода для сбора сведений об имени, электронном и почтовом адресе клиента мы пользуемся помощниками text_f ield и text_area.
Листинг файла depot_p/app/views/store/checkout. rhtml
<%= error_messages_for 'order' %>
no)KanyucTa, введите свои flaHHbie
<% form_for -.order, :url => { taction => :save_order } do |form| %>
Ф.И.О.: <%= form.text_field :name, :size => 40 %>
Адрес:
<%= form.text area raddress, :rows => 3. :cols => 40 %>
Эл.почта: <%= form.text field :email, :size => 40 %>
Способ оплаты: <%=
form.select :pay_type,
Order::PAYMENT_TYPES,
prompt => "Выберите способ оплаты"
%>
<%= submit_tag "Подтверждение заказа" , :class => "submit" %> <% end %>
Единственная имеющаяся здесь недосказанность относится к коду, связанно¬му со списком выбора. Мы подразумеваем, что список возможных способов оп¬латы является свойством модели заказов Order и должен быть массивом масси¬вов в файле модели. Первым элементом каждого подмассива является строка,'отображаемая в списке выбора, а вторым — значение, которое сохраняется в базе данных1. Пока мы не забыли, определим массив выбора в файле модели order.rb.
Листинг файла depot_p/app/models/order.rb
lass Order < ActiveRecord::Base PAYMENT_TYPES = [
# Отображается сохраняется a
[ "Чек", "check"
[ "Кредитная карта", "cc" ],
[ "Наложенный платеж", "ро" ]
]
базе данных ]
В шаблоне мы передаем этот массив выбора способов оплаты помощнику select. Ему передается и параметр : prompt, который добавляет пустую строку жмбора, содержащую текст приглашения.
Добавим немного магии CSS (см. листинг в приложении В), и с нашей фор-шой можно будет немного поиграть. Положите что-нибудь в корзину и щелкните ш кнопке Оформить заказ.
Вы должны увидеть картинку, изображенную на рис. 10.2. Рассмотрите ее как следует. Но если вы щелкнете на кнопке Подтверждение заказа, вас поприветству¬ют сообщения о том, что это действие системе не знакомо и никакое действие на save_order не откликнулось:
nown action
в action responded to save_order
Перед тем как перейти к этому новому действию, давайте все же закончим рабо¬ту над действием checkout, дополнив его несколькими проверочными функциями. Мы внесем изменения в модель заказов Order, чтобы проверить, во все ли поля клиент ввел данные (включая раскрывающийся список). К тому же мы должны убедиться, что способ оплаты представляет собой одно из приемлемых значений2.
Листинг файла app/models/order.rb class Order < ActiveRecord::Base PAYMENT_TYPES = [
# Отображается
сохраняется в базе данных
[ "Чек", "check" ]
[ "Кредитная карта", "сс" ],
[ "Наложенный платеж", "ро" ]
]
validates_presence_of .name, :address, :email, :pay_type validates_inclusion_of :pay_type,
:in => PAYHENT_TYPES.map {|disp, value| value}
if ...
Заметьте, что в начале отображаемой страницы уже был вызван помощник error_messages_f or. Тем самым получение отчета об ошибках, связанных с про¬веркой данных, обеспечено (но только после того, как мы напишем еще одну пор¬цию программного кода).