<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://wiki2.linuxformat.ru/skins/common/feed.css?97"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title>LXF109:Flickr - История изменений</title>
		<link>http://wiki2.linuxformat.ru/index.php?title=LXF109:Flickr&amp;action=history</link>
		<description>История изменений этой страницы в вики</description>
		<language>ru</language>
		<generator>MediaWiki 1.11.1</generator>
		<lastBuildDate>Wed, 13 May 2026 21:01:35 GMT</lastBuildDate>
		<item>
			<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
			<link>http://wiki2.linuxformat.ru/index.php?title=LXF109:Flickr&amp;diff=8645&amp;oldid=prev</link>
			<description>&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая статья&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: '''Rails''' Устройте на своем сайте личную фотогалерею с нужными вам функциями [[Категория:Учебники]]&lt;br /&gt;
&lt;br /&gt;
==Rails: Добавим функции Web 2.0==&lt;br /&gt;
&lt;br /&gt;
: '''Часть 2''' Простейшие возможности галереи реализованы; '''Алекс Янг''' приобщит вас к Web 2.0 через супер-технологии ''Ajax'' и вспомогательные классы ''Rails''.&lt;br /&gt;
&lt;br /&gt;
На данном этапе наша галерея на ''Rails'' поддерживает регистрацию пользователей и загрузку фотографий (считая, что вы прошли урок [[LXF108:Rails|прошлого номера]]), но в ней кое-чего не хватает – нет нумерации страниц, нет модульного тестирования и нет ''Ajax'', столь любимого Web 2.0-сайтами типа Flickr. Чтобы восполнить пробелы, я расскажу вам о тестировании моделей ''Rails'', использовании вспомогательных классов ''Rails'' и крутых технологиях JavaScript,&lt;br /&gt;
делающих интерфейс более дружелюбным.&lt;br /&gt;
&lt;br /&gt;
Данный урок основан на коде из предыдущей статьи, найти который можно в PDF-файле в разделе '''Журнал/Rails''' нашего DVD. Класс&lt;br /&gt;
редактирования на месте средствами JavaScript может пригодиться вам и в других проектах.&lt;br /&gt;
&lt;br /&gt;
===Часть 1 Тесты===&lt;br /&gt;
&lt;br /&gt;
Тестирование – неотъемлемая часть процесса разработки на ''Ruby on Rails''. Написание тестов во время изучения ''Rails'' также помогает исследовать эту среду, экспериментировать с различными подходами&lt;br /&gt;
и в конечном счете получить лучший код. Создатели ''Rails'' вложили в&lt;br /&gt;
пакет все необходимое для обучения тестированию, включая несколько&lt;br /&gt;
задач ''Rake''. До запуска тестов выполните из каталога проекта следующую команду:&lt;br /&gt;
&lt;br /&gt;
 rake db:test:prepare&lt;br /&gt;
&lt;br /&gt;
Она подготовит базу данных ''SQLite'' в каталоге '''db/test.sqlite3''' и скопирует схему для нашего проекта. Если вы измените БД посредством миграции, не забудьте выполнить команду ''rake db:test:clone_structure''&lt;br /&gt;
до прогона тестов.&lt;br /&gt;
&lt;br /&gt;
Чтобы запустить все тесты, наберите:&lt;br /&gt;
&lt;br /&gt;
 rake test:units&lt;br /&gt;
&lt;br /&gt;
Когда вы создаете модели и контроллеры с помощью скрипта&lt;br /&gt;
'''generate''', ''Rails'' автоматически генерирует заглушки для тестов в каталоге '''test/'''. Модульные тесты предназначены для моделей, а функциональные – для контроллеров. Первые позволяют проверить, что модели работают как ожидается. Это невероятно удобно, если проект меняется с течением времени: при модификации модели можно убедиться,&lt;br /&gt;
что сопутствующая система не затронута.&lt;br /&gt;
&lt;br /&gt;
Для тестовых данных ''Rails'' использует наработки ['''fixtures''']. По умолчанию они пишутся на YAML и хранятся в каталоге '''test/fixtures/'''. Наработки могут даже содержать фрагменты на ''Ruby'', как HTML-шаблоны ''Rails'':&lt;br /&gt;
&lt;br /&gt;
 quentin:&lt;br /&gt;
 id: 1&lt;br /&gt;
 login: quentin&lt;br /&gt;
 email: quentin@example.com&lt;br /&gt;
 salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd&lt;br /&gt;
 crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b&lt;br /&gt;
 1 # test&lt;br /&gt;
 created_at: &amp;lt;%= 5.days.ago.to_s :db %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пример взят из '''test/fixtures/users.yml''' – обратите внимание, что мы&lt;br /&gt;
добавили дату при помощи ''Ruby'', с тэгами '''&amp;lt;%= %&amp;gt;'''.&lt;br /&gt;
&lt;br /&gt;
Покамест фотографии добавляются без заголовков – а какая же&lt;br /&gt;
галерея без них? Чтобы решить проблему, добавим новую валидацию&lt;br /&gt;
в '''Photo''' и протестируем ее. Откройте файл '''app/models/photo.rb''' и впишите в него строку:&lt;br /&gt;
&lt;br /&gt;
  validates_presence_of :title, :if =&amp;gt; Proc.new { |photo| photo.thumbnail.nil? }&lt;br /&gt;
&lt;br /&gt;
Валидация включает блок проверки, не является ли фото миниатюрой – потому что они спокойно сохраняются и без заголовков: так уж&lt;br /&gt;
устроен модуль '''attachment_fu'''. Давайте проверим, что все работает как&lt;br /&gt;
надо: откройте файл '''test/unit/photo_test.rb'''. Мы добавим туда несколько новых тестов и удалим заглушку, сгенерированную ''Rails'':&lt;br /&gt;
&lt;br /&gt;
  require File.dirname(__FILE__) + ‘/../test_helper’&lt;br /&gt;
  class PhotoTest &amp;lt; ActiveSupport::TestCase&lt;br /&gt;
   fixtures :photos&lt;br /&gt;
     def test_titles_are_required_on_create&lt;br /&gt;
       assert Photo.create.errors.on(:title)&lt;br /&gt;
     end&lt;br /&gt;
     def test_titles_are_required_on_update&lt;br /&gt;
       photo = photos(:one)&lt;br /&gt;
       photo.title = nil&lt;br /&gt;
       photo.save&lt;br /&gt;
       assert photo.errors.on(:title)&lt;br /&gt;
     end&lt;br /&gt;
     def test_titles_are_not_required_for_thumbnails&lt;br /&gt;
       assert photos(:thumbnail).valid?&lt;br /&gt;
     end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что все тестовые методы имеют префикс '''test_''' и включают один или несколько вызовов '''assert'''. Все методы, имя которых начинается с '''test_''', запускаются тестовым пакетом автоматически.&lt;br /&gt;
&lt;br /&gt;
Теперь нам недостает лишь распознавания миниатюр. Откройте файл&lt;br /&gt;
'''test/fixtures/photos.yml''' и дополните его следующим кодом YAML:&lt;br /&gt;
&lt;br /&gt;
  thumbnail:&lt;br /&gt;
  description: MyText&lt;br /&gt;
  filename: MyString&lt;br /&gt;
  content_type: MyString&lt;br /&gt;
  size: 1&lt;br /&gt;
  user_id: 1&lt;br /&gt;
  width: 1&lt;br /&gt;
  height: 1&lt;br /&gt;
  thumbnail: example.png&lt;br /&gt;
  content_type: image/png&lt;br /&gt;
&lt;br /&gt;
Чтобы тест завершился успешно, все утверждения ['''assertions''']&lt;br /&gt;
должны быть истинными. Многие из них предоставляются как ''Rails'', так&lt;br /&gt;
и библиотекой '''Ruby Test::Unit'''. Мы взяли простейшее: оно проверяет,&lt;br /&gt;
что выражение не возвращает '''nil''' или '''false'''. Строка с '''fixtures''' использует&lt;br /&gt;
файл '''test/fixtures/photos.yml''' для создания фотографий в базе данных.&lt;br /&gt;
Доступ к «наработке» обеспечивается методом '''photos()''' – он любезно сгенерирован для нас. В примере выше используется '''photos(:one)'''.&lt;br /&gt;
Тесты фото вызываются командной строкой ''ruby test/unit/photo_test.rb'', а можно запустить все модульные тесты сразу, набрав команду &lt;br /&gt;
&lt;br /&gt;
  rake:test:units.&lt;br /&gt;
&lt;br /&gt;
===Часть 2 ''Ajax'' и вспомогательные классы ''Rails''===&lt;br /&gt;
&lt;br /&gt;
{{Врезка | Заголовок=Скорая помощь | Содержание=Использование блоков '''respond_to''' в контроллерах позволяет ''Rails'' разумно отвечать на запросы различных форматов. Они лежат в основе XML Rest API и респондеров ''Ajax''.| Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Нашим приложением было бы проще пользоваться, имей оно пару&lt;br /&gt;
функций, реализованных на JavaScript. ''Rails'' предоставляет богатый&lt;br /&gt;
функционал для работы с JavaScript через каркас '''Prototype''' и библиотеку '''Scriptaculous'''. Обработка текста и HTML реализуется библиотеками '''Ruby ActiveSupport''' и '''ActionView''', поставляемыми с ''Rails''.&lt;br /&gt;
Воспользуемся вспомогательными классами ''Rails'' для создания удобных дат, а также заголовков и описаний с редактированием на месте, как во Flickr. Выводом при просмотре тоже будут управлять вспомогательные классы. На прошлом уроке вы могли заметить вызовы '''link_to''', '''image_tag''' и '''form_for'''. Эти методы предоставляются различными вспомогательными классами внутри '''ActionView::Helpers'''. Прежде чем самим писать вспомогательные функции, всегда полезно проверить, нет ли их&lt;br /&gt;
в '''ActionView''', так как в ''Rails'' их сотни.&lt;br /&gt;
&lt;br /&gt;
В нашей галерее фотографии отображаются без всяких дат, поэтому откройте файл, касающийся фото ('''app/views/photos/_photo.html.erb'''), и добавьте следующую строку после тэга заголовка &amp;lt;nowiki&amp;gt;&amp;lt;h2&amp;gt;&amp;lt;/nowiki&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;h3&amp;gt;Added on &amp;lt;%= photo.created_at %&amp;gt;&amp;lt;/h3&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
К сожалению, это выглядит не очень хорошо. Дата содержит&lt;br /&gt;
информацию о времени и часовом поясе, а хватило бы только числа,&lt;br /&gt;
месяца и года. Измените эту строку на такую:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;h3&amp;gt;Added on &amp;lt;%= photo.created_at.to_date.to_s :long %&amp;gt;&amp;lt;/h3&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Теперь дата отображается в британском полном формате: Месяц&lt;br /&gt;
День, Год. Это работает благодаря методу ''Rails'' '''to_formatted_s''', с синонимом '''to_s'''. И даты, и времена работают подобным образом, поэтому значение, сохраняемое в '''created_at''', преобразуется в дату, а время размещения фото игнорируется.&lt;br /&gt;
&lt;br /&gt;
Чтобы узнать больше о форматах даты и о том, как добавить свой&lt;br /&gt;
собственный, выполните следующую команду для вывода документации ''Ruby'' по теме:&lt;br /&gt;
&lt;br /&gt;
  ri ActiveSupport::CoreExtensions::Date::Conversions&lt;br /&gt;
&lt;br /&gt;
====Живые заголовки====&lt;br /&gt;
&lt;br /&gt;
Хотя функция «Редактировать на месте» выглядит весьма продвинутой, реализовать ее довольно просто. Большую часть работы сделает библиотека '''Scriptaculous''', по умолчанию поставляемая с ''Rails'', но&lt;br /&gt;
'''PhotosController''' нужно немного адаптировать, чтобы он смог работать&lt;br /&gt;
с тем, чего ожидает '''Scriptaculous'''. Во-первых, нужно приспособить действие '''PhotosController#update''' для работы с JavaScript. Отредактируйте действие обновления в файле '''app/controllers/photos_controller.rb''':&lt;br /&gt;
&lt;br /&gt;
 def update&lt;br /&gt;
   @photo = current_user.photo&lt;br /&gt;
    respond_to do |format|&lt;br /&gt;
   if @photo.update_attributes params[:photo]&lt;br /&gt;
    format.html do&lt;br /&gt;
     flash[:notice] = ‘Photo was successfully updated.’&lt;br /&gt;
     redirect_to(@photo)&lt;br /&gt;
    end&lt;br /&gt;
    format.xml { head :ok }&lt;br /&gt;
    format.js do&lt;br /&gt;
     if params[:field]&lt;br /&gt;
      render :inline =&amp;gt; ‘&amp;lt;%= h photo.attributes[params[:field]]} %&amp;gt;’&lt;br /&gt;
     else&lt;br /&gt;
      head :ok&lt;br /&gt;
     end&lt;br /&gt;
    end&lt;br /&gt;
   else&lt;br /&gt;
    format.html { render :action =&amp;gt; “edit” }&lt;br /&gt;
    format.xml { render :xml =&amp;gt; @photo.errors, :status =&amp;gt; :  unprocessable_entity }&lt;br /&gt;
    format.js { render :text =&amp;gt; @photo.errors.full_messages, :status =&amp;gt; :unprocessable_entity }&lt;br /&gt;
   end&lt;br /&gt;
  end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Этот код делает кое-что новое. Обработка запросов JavaScript поддерживается в '''format.js''' в блоке '''respond_to'''. Когда фотография успешно сохранена и используется JavaScript, выводится заголовок, поскольку&lt;br /&gt;
'''Ajax.InPlaceEditor''', предоставляемый библиотекой ''Scriptaculous'', ожидает, что сервер возвратит обновленный текст. Обратите внимание, что для этого используется '''render :inline''', позволяя контроллеру вызвать&lt;br /&gt;
вспомогательный метод. Текст экранируется, чтобы избежать опасных&lt;br /&gt;
метасимволов. Также добавьте в начало контроллера (после строки '''before_filter''') следующую строку:&lt;br /&gt;
&lt;br /&gt;
  skip_before_filter :verify_authenticity_token, :only =&amp;gt; [ :update ]&lt;br /&gt;
&lt;br /&gt;
По соображениям безопасности в ''Rails'' используется механизм&lt;br /&gt;
аутентификации, порождающий проблемы при обновлении с помощью&lt;br /&gt;
JavaScript, и пока мы его отключим.&lt;br /&gt;
&lt;br /&gt;
====Позаботимся о редактировании====&lt;br /&gt;
&lt;br /&gt;
Нам надо, чтобы редактирование на месте предоставлялось только&lt;br /&gt;
зарегистрированным пользователям, но чтобы проверить это, не будем&lt;br /&gt;
забивать наш файл выражениями с '''if''', а создадим новый вспомогательный класс. Откройте файл '''app/helpers/application_helper.rb''' и добавьте следующий метод:&lt;br /&gt;
&lt;br /&gt;
  def in_place_editor_if(condition, object, field, &amp;amp;block)&lt;br /&gt;
    if condition&lt;br /&gt;
      object_id = “#{object.class.name.downcase}_#{field}_#{object.id}”&lt;br /&gt;
      in_place_class = “in_place_#{field}”&lt;br /&gt;
      concat ‘&amp;lt;span id=”%s” class=”%s”&amp;gt;’ % [object_id, in_place_class], block.binding&lt;br /&gt;
      yield&lt;br /&gt;
  concat ‘&amp;lt;/span&amp;gt;’, block.binding&lt;br /&gt;
   else&lt;br /&gt;
      yield&lt;br /&gt;
   end&lt;br /&gt;
 end&lt;br /&gt;
&lt;br /&gt;
Это довольно-таки продвинутый ''Ruby'' – ничего страшного, если&lt;br /&gt;
понять его сейчас трудно, но обязательно вернитесь к нему позже! Его&lt;br /&gt;
нужно использовать примерно так:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;% in_place_editor_if current_user, photo, :title do %&amp;gt;&amp;lt;%= h photo.title %&amp;gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Если переменная '''current_user''' установлена, заголовок фото будет&lt;br /&gt;
обернут в тэг '''&amp;lt;nowiki&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/nowiki&amp;gt;''' с атрибутами '''id''' и '''class''', для упрощения ссылок на&lt;br /&gt;
него из JavaScript. У незарегистрированных пользователей заголовок&lt;br /&gt;
будет выводиться без тэга '''&amp;lt;nowiki&amp;gt;&amp;lt;span&amp;gt;&amp;lt;/nowiki&amp;gt;''', а значит, JavaScript его проигнорирует. В данном фрагменте кода заголовок упрятан в блок с синтаксисом скобок '''do ... end'''. Таким образом, этот вспомогательный класс&lt;br /&gt;
может инкапсулировать все, даже многострочный HTML. Внутри вспомогательного класса для доступа к этому HTML-коду и добавления в&lt;br /&gt;
него дополнительного текста вызываются '''yield''' и '''concat'''.&lt;br /&gt;
&lt;br /&gt;
Хотя это уже высший пилотаж, настоятельно рекомендую вам применять его и в других вспомогательных методах, которые вы соберетесь писать. Отредактируйте файл '''app/views/photos/_photo.html.erb''',&lt;br /&gt;
чтобы употребить в нем этот хитрый вспомогательный класс для изменения способа отображения заголовков:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;h2&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;% in_place_editor_if current_user, photo, :title do %&amp;gt;&amp;lt;%= h photo.title %&amp;gt;&amp;lt;% end %&amp;gt;&lt;br /&gt;
 &amp;lt;%= link_to ‘Edit’, edit_photo_path(photo) %&amp;gt;&lt;br /&gt;
 &amp;lt;%= link_to ‘Delete’, photo, :confirm =&amp;gt; ‘Are you sure?’, :method =&amp;gt; :delete %&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;/h2&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Это упростит поиск HTML в JavaScript и применит редакторы к каждому заголовку.&lt;br /&gt;
&lt;br /&gt;
====Добавим редактирование через JavaScript====&lt;br /&gt;
&lt;br /&gt;
Последний кусочек мозаики – код JavaScript для редактирования на&lt;br /&gt;
месте. Прежде чем писать его, поправим HTML-код основного файла и&lt;br /&gt;
подключим туда наши скрипты. В ''Rails'' для этого есть вспомогательный&lt;br /&gt;
класс '''javascript_include_tag''' – добавьте его в секцию '''&amp;lt;nowiki&amp;gt;&amp;lt;head&amp;gt;&amp;lt;/nowiki&amp;gt;''' файла '''app/views/layouts/application.html.erb''':&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;%= javascript_include_tag :all %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Добавьте следующий код в файл '''public/javascripts/application.js''':&lt;br /&gt;
&lt;br /&gt;
 var EditorGenerator = Class.create({&lt;br /&gt;
  initialize: function(class_name, url_base, error_message) {&lt;br /&gt;
   this.item_selector = ‘.’ + class_name&lt;br /&gt;
   this.update_url = ‘/’ + url_base + ‘/update/’&lt;br /&gt;
   this.error_message = error_message&lt;br /&gt;
   this.field = class_name.replace(/in_place_/, ‘’)&lt;br /&gt;
   this.create_editors()&lt;br /&gt;
  },&lt;br /&gt;
     create_editors: function() {&lt;br /&gt;
     $$(this.item_selector).each(function(element) {&lt;br /&gt;
      var item_id = element.id.match(/_(\d+)$/)[1]&lt;br /&gt;
      this.create_editor(element, item_id)&lt;br /&gt;
     }.bind(this))&lt;br /&gt;
   },&lt;br /&gt;
  create_editor: function(element, item_id) {&lt;br /&gt;
   new Ajax.InPlaceEditor(element, this.update_url + item_id + ‘?field=’ + this.field, {&lt;br /&gt;
     onFailure: this.onFailure.bind(this),&lt;br /&gt;
   callback: function(form, value) { return ‘photo[‘ + this.field + ‘]=’ + escape(value) }.bind(this)&lt;br /&gt;
     })&lt;br /&gt;
  },&lt;br /&gt;
   onFailure: function(editor, transport) {&lt;br /&gt;
   alert(this.error_message + ‘: ‘ + transport.responseText)&lt;br /&gt;
   }&lt;br /&gt;
  })&lt;br /&gt;
   document.observe(‘dom:loaded’, function() {&lt;br /&gt;
     var title_generator = new EditorGenerator(‘in_place_title’, ‘photos’, ‘Error saving photo’)&lt;br /&gt;
  })&lt;br /&gt;
&lt;br /&gt;
Этот код создает класс JavaScript, применяющий редактор '''Ajax.InPlaceEditor''' к заданным HTML-элементам. Функционал, который здесь используется, предоставляется библиотеками JavaScript '''Scriptaculous''' и&lt;br /&gt;
'''Prototype''' – они у нас есть. Класс инициализируется вызовом '''document.observe(‘dom:loaded’, ...)''', который ждет готовности браузера, прежде чем выполнить какой-либо JavaScript. Как только класс '''EditorGenerator'''&lt;br /&gt;
будет создан, он добавит '''Ajax.InPlaceEditor''' в каждый из span’ов, которые сгенерировал наш вспомогательный класс. Другая интересная строка кода – это итератор, используемый в цикле для прохода по&lt;br /&gt;
каждому заголовку:&lt;br /&gt;
&lt;br /&gt;
  $$(this.item_selector).each(function(element) { ...&lt;br /&gt;
&lt;br /&gt;
В нем используется функция '''Prototype $$()''' для выбора списка элементов на основе селектора CSS. Он хранится в свойстве '''this.item_selector''', устанавливаемом при инициализации класса. Функция '''$$()''' возвращает массив элементов, и, значит, для прохода по нему можно использовать метод '''each()''', также предоставляемый '''Prototype'''.&lt;br /&gt;
Это итератор, и он считается лучше читаемым по сравнению с обычным циклом.&lt;br /&gt;
&lt;br /&gt;
{{Врезка | Заголовок=Скорая помощь | Содержание= Для отладки JavaScript или даже исследования объектной модели документа DOM или CSS страницы, настоятельно рекомендую модуль расширения ''Firefox'' под названием ''Firebug'' (https://addons.mozilla.org/en-US/firefox/addon/1843). Без него причины ошибок в JavaScript будет понять очень трудно.| Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Теперь можно добавить редактируемые поля всюду, где отображаются заголовки. В качестве примера откроем файл '''app/views/photos/&lt;br /&gt;
show.html.erb''' и изменим его заголовок на этот:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;h2&amp;gt;&amp;lt;% in_place_editor_if current_user, @photo, :title do %&amp;gt;&amp;lt;%= h @photo.title %&amp;gt;&amp;lt;% end %&amp;gt;&amp;lt;/h2&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Другой хороший кандидат на редактирование – описания. Измените их в '''app/views/photos/show.html.erb''' таким образом:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;p&amp;gt;&amp;lt;% in_place_editor_if current_user, @photo, :description do&lt;br /&gt;
 %&amp;gt;&amp;lt;%= textilize_without_paragraph h(@photo.description) %&amp;gt;&amp;lt;% end %&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Потом замените описание в файле '''app/views/photos/_photo.rhtml'''&lt;br /&gt;
на следующее:&lt;br /&gt;
&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;&amp;lt;p&amp;gt;&amp;lt;% in_place_editor_if current_user, photo, :description do&lt;br /&gt;
 %&amp;gt;&amp;lt;%= textilize_without_paragraph h(photo.description) %&amp;gt;&amp;lt;% end %&amp;gt;&amp;lt;/p&amp;gt;&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Затем добавьте еще один объект '''EditorGenerator''' в '''public/javascripts/application.js''', после '''title_generator''':&lt;br /&gt;
&lt;br /&gt;
 var description_generator = new EditorGenerator(‘in_place_description’, ‘photos’, ‘Error saving photo’)&lt;br /&gt;
&lt;br /&gt;
То же самое можно сделать с любым другим полем. Есть лишь&lt;br /&gt;
небольшая загвоздка: если кликнуть по ссылке для редактирования&lt;br /&gt;
описания, текст будет представлен в виде HTML-кода. Это можно&lt;br /&gt;
поправить, добавив в '''Ajax.InPlaceEditor''' параметр '''loadingText''', указывающий на действие в '''PhotosController''', которое удалит ненужную разметку.&lt;br /&gt;
&lt;br /&gt;
===Часть 3 Разбивка на страницы===&lt;br /&gt;
&lt;br /&gt;
Чтобы достойно завершить наш второй урок по разработке галереи,&lt;br /&gt;
добавим функцию постраничного вывода. Как ни странно, решение&lt;br /&gt;
этой задачи в web-приложениях сопряжено с трудностями, так как&lt;br /&gt;
случайно написать увесистый SQL-запрос очень просто. К счастью,&lt;br /&gt;
Мислав Марохнич [Mislav Marohnic] создал невероятно простой модуль&lt;br /&gt;
расширения '''will_paginage''', удовлетворяющий требованиям большинства приложений.&lt;br /&gt;
&lt;br /&gt;
Предпочтительный метод установки – с помощью ''gem'':&lt;br /&gt;
&lt;br /&gt;
  sudo gem1.8 install mislav-will_paginate --source http://gems.github.com/&lt;br /&gt;
&lt;br /&gt;
Теперь откройте файл '''config/environment.rb''' и добавьте в него следующие строки в конце:&lt;br /&gt;
&lt;br /&gt;
  gem ‘mislav-will_paginate’, ‘~&amp;gt; 2.2’&lt;br /&gt;
  require ‘will_paginate’&lt;br /&gt;
&lt;br /&gt;
Перезапустите сервер, чтобы приложение загрузило модуль.&lt;br /&gt;
&lt;br /&gt;
Пользоваться им очень просто. Откройте '''app/controllers/photos_controller.rb''' и измените индексирование при загрузке фотографий таким образом:&lt;br /&gt;
&lt;br /&gt;
  @photos = Photo.paginate :all, :conditions =&amp;gt; ‘thumbnail is&lt;br /&gt;
  NULL’, :page =&amp;gt; params[:page], :order =&amp;gt; ‘created_at DESC’&lt;br /&gt;
&lt;br /&gt;
Теперь откройте файл '''app/views/photos/index.html.erb''' и добавьте туда строку:&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;%= will_paginate @photos %&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Все почти готово, но чтобы разбивка на страницы хорошо читалась,&lt;br /&gt;
нужно немного приятного CSS. Добавьте следующий код в файл '''public/stylesheets/screen.css''':&lt;br /&gt;
&lt;br /&gt;
  .pagination { text-align: center; padding: .3em; clear: both; margintop:&lt;br /&gt;
  1em; width: 100%; float: left; }&lt;br /&gt;
  .pagination a, .pagination span { padding: .2em .5em; }&lt;br /&gt;
  .pagination span.disabled { color: #AAA; }&lt;br /&gt;
  .pagination span.current { font-weight: bold; color: #FF0084; }&lt;br /&gt;
  .pagination a { border: 1px solid #DDDDDD; color: #0063DC;&lt;br /&gt;
 textdecoration: none; }&lt;br /&gt;
 .pagination a:hover, .pagination a:focus { border-color: #003366;&lt;br /&gt;
 background: #0063DC; color: white; }&lt;br /&gt;
 .pagination .page_info { color: #aaa; padding-top: .8em; }&lt;br /&gt;
 .pagination .prev_page, .pagination .next_page { border-width: 2px; }&lt;br /&gt;
 .pagination .prev_page { margin-right: 1em; }&lt;br /&gt;
 .pagination .next_page { margin-left: 1em; }&lt;br /&gt;
&lt;br /&gt;
Пока вы не добавите не менее 30 фотографий, номеров страниц&lt;br /&gt;
вам не видать. Для тестовых целей добавьте опцию '''per_page''' в действие '''index''':&lt;br /&gt;
&lt;br /&gt;
 @photos = Photo.paginate :all,&lt;br /&gt;
 :conditions =&amp;gt; ‘thumbnail is NULL’,&lt;br /&gt;
 :page =&amp;gt; params[:page],&lt;br /&gt;
 :per_page =&amp;gt; 5&lt;br /&gt;
 :order =&amp;gt; ‘created_at DESC’&lt;br /&gt;
&lt;br /&gt;
Итак, мы изучили основы модульных тестов, разбивки на страницы, ''Ajax'' и объектно-ориентированный JavaScript; можете применить&lt;br /&gt;
эти технологии в своих проектах. Библиотеки JavaScript '''Scriptaculous'''&lt;br /&gt;
и '''Prototype''' имеют стабильное API, поэтому у вас будет возможность&lt;br /&gt;
взять пример редактирования на месте и создать на его основе более&lt;br /&gt;
сложные элементы управления. Модульное тестирование ''Rails'' поможет убедиться в работоспособности вашего кода. Вы почти полностью вооружены для профессиональной разработки на ''Rails''! '''LXF'''&lt;br /&gt;
&lt;br /&gt;
===Комплект библиотек JavaScript===&lt;br /&gt;
&lt;br /&gt;
''Rails'' поставляется с библиотеками '''Prototype''' и '''Scriptaculous'''. '''Scriptaculous''' (http://script.aculo.us) построена на '''Prototype''' (http://prototypejs.org). На сайтах обеих библиотек есть подробная документация. '''Prototype''' упрощает использование JavaScript на различных платформах, а также включает средства объектно-ориентированной разработки, библиотеку ''Ajax'' и абстракцию DOM для упрощения навигации в&lt;br /&gt;
HTML-документах из ваших программ.&lt;br /&gt;
'''Scriptaculous''' предоставляет средства для анимации, эффектов, drag and drop, сложные элементы управления ''Ajax'' и модульное тестирование.&lt;br /&gt;
&lt;br /&gt;
===Вспомогательные классы Rails: Быстрая справка===&lt;br /&gt;
&lt;br /&gt;
{|class=wikitable border=1 cellpadding=5|+ table name&lt;br /&gt;
|-&lt;br /&gt;
! textilize text &lt;br /&gt;
| Конвертирует текст в HTML с помощью '''Textile''' (установите gem-пакет ''RedCloth'', чтобы получить эту функциональность).&lt;br /&gt;
|-&lt;br /&gt;
! truncate text, length&lt;br /&gt;
| Если текст длиннее, чем '''length''', он будет обрезан и дополнен ‘...’.&lt;br /&gt;
|-&lt;br /&gt;
! tag name &lt;br /&gt;
| Создает HTML-тэг, самозакрывающийся, если это необходимо.&lt;br /&gt;
|-&lt;br /&gt;
! content_tag name, content &lt;br /&gt;
| Создает блок с тэгом HTML, например:'''content_tag :p, “Example”'''&lt;br /&gt;
|-&lt;br /&gt;
! number_to_human_size size&lt;br /&gt;
| Преобразует размер файла в байтах в читаемый формат, при необходимости добавляя KB, MB, GB.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;/div&gt;</description>
			<pubDate>Tue, 01 Sep 2009 10:14:52 GMT</pubDate>			<dc:creator>Crazy Rebel</dc:creator>			<comments>http://wiki2.linuxformat.ru/index.php/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:LXF109:Flickr</comments>		</item>
	</channel>
</rss>