Навигация
Шаг А2: добавление пропущенного столбца
Итак, мы показали заказчику работу кода, принадлежащего временной платформе,
объяснив ему, что это всего лишь своеобразный действующий макет. Ему было
приятно так быстро увидеть работоспособный фрагмент приложения. Но после
краткого ознакомления он заметил некоторые упущения — не были указаны
цены товаров.
Значит, мы должны добавить к таблице базы данных еще один столбец. Некоторые
разработчики (и администраторы баз данных) добавили бы столбец, запустив
утилиту и применив команду, эквивалентную следующей:
alter table products add column price decimal(8,2);
Но мы уже знаем о существовании миграций. Использование миграции для
добавления нового столбца предоставит нам возможность пользоваться хронологией
версий изменения схемы и простой способ отмены внесенных изменений.
Начнем с создания миграции. Ранее мы использовали миграцию, которая генерировалась
автоматически при создании модели product. Но на этот раз нам
нужно создать ее самостоятельно. Ей нужно дать такое имя, которое поможет даже
через год, когда мы вернемся к работе над приложением, вспомнить, для чего
предназначалась каждая миграция.
Условимся использовать глагол «create» («создать»), когда миграция создает
таблицы, и глагол «add» («добавить»), когда она добавляет столбцы к существующим
таблицам.
3epot> ruby script/generate migration add_price
exists db/migrate
create db/migrate/002_add_price.rb
Заметьте, что сгенерированный файл имеет следующий порядковый номер
префикса — 002. Rails использует порядковые номера для отслеживания примененных
и не примененных миграций (и для того, чтобы сообщить схеме порядок,
в котором миграции должны быть применены).
Откройте исходный файл миграции и отредактируйте содержимое метода up,
вставив в него столбец price (цена) для таблицы products (товары), как показано
в следующем примере кода. В методе down для удаления столбца используется
инструкция remove_column.
.Листинг файла db/migrate/002_add_price.rb
class AddPrice < ActiveRecord:Migration
def self.up
add_column :products, :price, :decimal, :precision => 8,
:scale => 2, :default => 0
end
def self.down
remove_column :products, :price
end
eid
Аргумент : p r e c i s ion предписывает базе данных хранить в столбце p r i c e
<цена) восемь значащих цифр, а аргумент : scale предписывает двум из них появляться
в виде десятичной дроби. Мы сможем хранить цены в диапазоне чисел
от -999 999,99 до +999 999,99.
В данном коде продемонстрировано еще одно полезное свойство миграций —
мы можем получать доступ к свойствам текущей базы данных для выполнения
таких задач, как установка для столбцов значений по умолчанию. По поводу
применяемого здесь синтаксиса особо волноваться не стоит: позже мы поговорим
и о нем.
Теперь мы снова можем запустить миграцию.
=epot> rake db:migrate
чп /Users/dave/Work/depot)
== AddPrice: migrating =========================================
-- add_column(:products, :price, :decimal, {:precision=>8, :scale=>2,
:default=>0})
-> 0.0258s
= AddPrice: migrated (0.0264s) ================================
Rails знает, что текущая версия базы данных — 001, поэтому она применит
только вновь созданную миграцию под номером 002.
__________________________________________________________________
ЦЕНЫ, ДОЛЛАРЫ И ЦЕНТЫ
Когда мы определяли формат схемы хранения данных, мы решили хранить цену товара в десятичном
столбце, отказавшись от варианта с плавающей запятой. На то были свои причины. Числа
с плавающей запятой склонны к ошибкам округления: если в покупательской корзине окажется
достаточно много товаров, то в итоге может получиться сумма не 235,00, а 234,99. Десятичные
числа хранятся и в базе данных, и в Ruby-переменных как масштабируемые целые числа, и, следовательно,
они имеют точное представление.
__________________________________________________________________
А теперь настало время удивляться. Перейдите в окно браузера, содержащее
наше приложение, щелкните на кнопке Refresh (Обновить), и вы увидите столбец
price (цена), вставленный в перечень товаров.
Помните, мы говорили, что модель product обращается к таблице products,
чтобы определить, какие свойства она должна иметь. В режиме разработки Rails
перезагружает файлы модели при каждой отправке браузером запроса, поэтому
модель всегда будет отражать текущую схему базы данных. Вместе с тем объявление
scaffold в коде контроллера будет выполняться для каждого запроса (поскольку
контроллер тоже перезагружается), поэтому запрос может использовать
информацию, содержащуюся в модели для обновления отображаемых страниц.
С технической точки зрения в этом нет ничего особенного. Тем не менее эта
возможность оказывает большое влияние на процесс разработки. Вам, наверное,
приходилось сталкиваться с ситуацией, когда заказчик, которому вы демонстрировали
окончательную версию работающего приложения, созданного в точном
соответствии с его запросами, говорил лишь: «Это не то, что я имел в виду»?
Для многих проще понять суть идеи, когда ее можно опробовать в деле. Скорость,
с которой вы можете в Rails превращать слова в работающее приложение, положительно
сказывается на возможности заказчика поработать с этим приложением.
Короткие циклы обратной связи позволяют и вам, и вашему заказчику как
можно раньше оценить реальные свойства приложения и существенно сократить
время, затрачиваемое на различные переделки.