Реализация оперативного просмотра
Проблема
Хотелось бы дать пользователям возможность оперативного просмотра данных в процессе редактирования, чтобы не получалось так, что после отправки из формы данные появились в испорченном формате (когда речь идет, к примеру, о дневниковой записи, которую собираются выставить на всеобщее обозрение).
Решение
Оперативный просмотр легко осуществить с помощью встроенных в Rails помощников JavaScript. Для данного рецепта мы обойдемся созданием оперативного просмотра простейшей формы, предназначенной для создания дневниковой записи.
Первым делом при создании любого Rails-эффекта, связанного с использованием Ajax, нужно обеспечить включение в код нужных JavaScript-библиотек. Для достижения эффекта оперативного просмотра требуется включить лишь одну библиотеку — Prototype. Я рекомендую сделать это в главном шаблоне приложения (в нашем случае — в файле layouts/standard.rhtml):
-
<html>
-
<head>
-
<%= javascript_include_tag "prototype" %>
-
</head>
-
<body>
-
….
-
</body>
-
</html>
Теперь, обеспечив загрузку требуемых JavaScript-библиотек, нужно создать модель и контроллер, которые будут поддерживать ввод дневниковых записей. Мы будем вызывать класс модели Entry, передавая ему свойства title и body. Если хотите продолжать работу, не определяя соответствующей таблицы Active Record, то файл app/models/entry.rb должен приобрести следующий вид:
-
class Entry
-
attr_accessor :title, :body
-
end
Контроллер будет называться DiaryController. Мы создадим его в файле app/control-lers/diary_controller.rb. Давайте придерживаться основ, и назовем действие по созданию новой записи new( ):
-
def new
-
@entry = Entry.new
-
end
Теперь настал черед самой функции. В представлении, созданном для этого действия, и будет твориться все наше волшебство. Создайте файл app/views/diary/new.rhtml и придайте ему следующий вид:
-
<% form_tag ({:action => "save"}, :id=> "entry-form") do %>
-
<%= text_field :entry, :title %> <br />
-
<%= text_area :entry, :body %> <br />
-
<%= submit_tag "Save" %>
-
<% end -%>
-
-
<%= observe_form "entry-form",
-
:frequency=>2,
-
:update=>"live-preview",
-
:complete=>"Element.show(‘live-preview’)",
-
:url=> {:action => "preview"} %>
-
-
<div id="live-preview" style="display:none; border:1px solid"></div>
Мы создали стандартную, универсальную форму с id, имеющим значение entry-form, поэтому на нее можно ссылаться из всего остального кода. За определением формы следует вызов помощника observe_form( ), который генерирует требуемый JavaScript-код для опроса каждого элемента формы, выведенной на странице (ссылаясь на нее по id), и поиска изменений. Опрос будет вестись через интервалы времени (в секундах), заданные параметром frequency. Как только будут замечены изменения, на URL, определенный параметром :url, будет направлен вызов, которому в качестве параметров будут переданы данные формы. Параметр :update определяет HTML-элемент (опять же по его id), который будет обновлен результатами URL-вызова. В данном случае содержимое элемента <div>, который используется для оперативного просмотра, будет обновлено тем, что в конечном счете будет отправлено в результате вызова действия preview( ).
Чтобы сделать элемент оперативного просмотра невидимым при первоначальной загрузке страницы, мы воспользовались встроенным CSS. Пока пользователь не введет какие-либо данные, в элементе оперативного просмотра нечего будет показывать. Параметр :complete, передаваемый помощнику observe_form( ), предписывает после завершения вызова действия preview( ) выполнение фрагмента JavaScript, который включит отображение элемента оперативного просмотра.
Если в оперативном просмотре нужно отобразить всего лишь одно поле, то мы можем взамен воспользоваться помощником observe_field( ).
Теперь осталось только обеспечить выполнение действия preview( ). Вот его код, взятый из контроллера:
-
def preview
-
render :layout => false
-
end
Единственная задача, выполняемая кодом действия, — это «закорачивание» обычной схемы отправки данных, используемой в приложении. Поскольку мы собираемся обновлять элемент оперативного просмотра на странице создания ежедневных дневниковых записей и использовать для этого лишь результаты, возвращаемые действием preview( ), возвращать целиком всю HTML-страницу не требуется. Нам нужен лишь отрывок, имеющий определенный смысл в составе более объемного содержимого экрана.
Представление, предназначенное для действия preview( ), находится в файле app/views/diary/preview.rhtml и должно иметь следующий вид:
-
<h2>Preview:</h2><br />
-
<h3><%= params[:entry][:title] %></h3>
-
<%= textilize params[:entry][:body] %>
Вот и все! Это представление использует HTML-заголовок для названия записи, а затем, используя метод textilize( ), генерирует HTML-выход. Внутри этого метода используется библиотека RedCloth для преобразования простой текстовой разметки в HTML.
Теперь можно загрузить форму ввода дневниковой записи и посмотреть, как обычный текст преобразуется в HTML еще до того, как будет сделан щелчок на кнопке Save.
P.S.
Параметру frequency, использующемуся в методах observe_field( ) и observe_form( ), можно присвоить нулевое или отрицательное значение, что приведет к обзору поля в реальном масштабе времени. Казалось бы, что может быть плохого в мгновенной реакции пользовательского интерфейса, но на самом деле она будет подавлена, не говоря уже о дополнительной тяжелой нагрузке на серверы. При отслеживании изменений в реальном масштабе времени каждое изменение вызовет отправку запроса на сервер, от которого нужно дождаться результата, чтобы увидеть обновление на экране. Изменения становятся в очередь, в результате чего обновления оперативного просмотра медленно следуют за ними, ожидая очередного перехвата.

Как связаться с автором?
можете написать мне на мыло leopard_ne[at]inbox.ru ([at] замените на собаку)
Так зачитался, что пропустил любимую передачу)