Проект: Основы Active Record

Не забывайте использовать Git для фиксации изменений в ваших проектах!

В этом проекте вы проведете довольно много времени, работая с моделями. Ruby on Rails Tutorial даст вам возможность применить некоторые полученные знания в подготовленной среде, а затем дополнительный проект предоставит шанс проделать это целиком самому.

Подготовка: Сперва обдумай данные

Первый шаг для построения хорошей модели данных как правило не связан с сидением за компьютером. Вам потребуется найти минутку и обдумать, что же вам необходимо. Возможно, в начале вы и не знаете всего, но планирование пути подхода имеет решающее значение для избежания последующих дорогостоящих ошибок.

В подготовке вам будет дано несколько сценариев и предложено спланировать как будут выглядеть модели данных для каждого из них. Вы можете сделать это с помощью ручки и листа бумаги или доски, если вам посчастливилось иметь ее под рукой. Существует несколько общепринятых подходов планирования моделей и связей (ассоциаций), но сейчас просто выполните это естественным для вас способом. Одним из способов является составление списка моделей, другим - создание графических диаграмм, где каждая модель представлена блоком, а вы соединяете их соответствующими стрелками.

Для каждого сценария вам потребуется описать данные, ассоциации и проверки (валидации), необходимые для их построения. Под этим понимается то, какие модели (таблицы с данными) будут необходимы для хранения данных (и какие столбцы вам понадобятся), какие поля этих таблиц станут объектами валидации (например, минимальная длина пароля или уникальность имени пользователя). Не волнуйтесь, если не до конца уверены как реализовать ту или иную вещь, главное сейчас начать обдумывать как будут храниться данные.

Например: вы создаете блог для вашего стартапа, который будут вести несколько авторов, и каждый из них может писать множество постов.

Решение может выглядеть примерно так:

Примечание: Здесь явно описаны столбцы :id, :created_at и :updated_at, но вы можете смело полагать, что они будут созданы и без этого, ведь Rails или база данных предоставляют их вам автоматически

  • Authors

    username:string [unique, 4-12 chars, present]
    email:string [unique, present]
    password:string [6-16 chars, present]
    id:integer
    created_at:datetime
    updated_at:datetime
    
    has_many posts
    
  • Posts

    title:string [unique, present]
    body:text [present]
    author_id:integer [present]
    id:integer
    created_at:datetime
    updated_at:datetime
    
    belongs_to author
    

Используйте любой удобный вам формат.

Ваша задача

Для каждого из последующих сценариев опишите модели, столбцы, валидации и ассоциации, которые вы могли бы использовать для реализации. Некоторые из них сложнее других, и вам потребуется проявить немного творчества, решая, какие столбцы могут потребоваться, чтобы воплотить сценарий в жизнь.

Сложность в том, чтобы определить, что должно стать отдельными моделями, и как эти модели будут взаимодействовать друг с другом с помощью простых ассоциаций (все нижеописанные имеют отношения has_many, has_one и/или belongs_to). Если вы не совсем понимаете, как это должно выглядеть, держите сценарий в голове проходя следующие пару уроков.

Запомните, если вы чувствуете, что собираетесь повторять одни и те же данные несколько раз, возможно это знак, что вам необходимо создать отдельную таблицу. Типичный пример - адресная информация - вы можете явно прописывать город и регион каждого пользователя. Но как насчет разделения моделей City(город) и State(регион) и создания отношения между ними?

  1. Вы создаете online-платформу для обучения (вроде этой!). У вас есть множество разных курсов, каждый с заголовком и описанием, и каждый курс содержит несколько уроков. Содержимое урока состоит из заголовка и основного текста.
  2. Вы создаете вкладку профиля для нового пользователя вашего сайта. Вы уже храните имя и email пользователя, но теперь вы хотите собирать демографическую информацию вроде города, региона, страны, возраста и пола. Задумайтесь - как много профилей должен иметь пользователь? Как вы можете соотнести это с моделью User(пользователь)?
  3. Вы хотите создать виртуальную доску объявлений, значит у вас будут пользователи платформы, способные создавать объявления. Каждое объявление будет содержать URL изображения в сети. Пользователи могут оставлять комментарии к объявлениям (но не могут комментировать сами комментарии).
  4. Вы хотите создать доску сообщений вроде Hacker News. Пользователь может прикреплять ссылки. Другие пользователи могут оставлять комментарии к этим материалам или комментариям. Как вы убедитесь, что комментарий "знает"" в каком месте иерархии он находится?

Проект 1: Ruby on Rails Tutorial

Эта глава руководства даст вам возможность начать работать с базой данных и моделями. Она проведет вас через создание и настройку ваших первых миграций и валидаций для проверки корректности пользовательского ввода, а так же добавление безопасного пароля в вашу модель User.

Ваша задача

  1. Пройдите главу 6 Ruby on Rails Tutorial, "Моделирование пользователей".

Проект 2: Микро-Reddit

Давайте создадим свой Reddit. Ну, скорее, его детскую версию, так называемый микро-reddit. В этом проекте вы построите структуры данных, необходимые для возможности делиться ссылками и комментировать. Мы не будем создавать "фронтенд" для этой задачи, потому что это нам не требуется... вы можете использовать консоль Rails для работы с моделями, не прибегая к излишествам вроде отправки HTTP-запросов и создания контроллеров и представлений.

Ваша задача

Приступаем

  1. Прямо как в подготовке, спланируйте модели данных, которые вам потребуются, чтобы позволить пользователям посещать сайт (пока не беспокойтесь насчет авторизации и безопасности паролей), отправлять ссылки ("посты") и комментировать ссылки. Пользователям НЕ требуется возможность комментировать другие комментарии... каждый комментарий относится к посту (Post).
  2. Создайте новое rails-приложение из командной строки ($ rails new micro-reddit) и откройте его. Мы будем использовать стандартную базу данных SQLite3, так что вам не потребуется изменять что-либо в этом плане.
  3. Создайте вашу модель User(пользователь) и заполните миграцию желаемыми столбцами.
  4. Запустите миграцию командой $ rake db:migrate. Вы можете использовать команду $ rake db:rollback если осознали, что забыли что-то, или просто создать новую миграцию для исправления (которая может включать вызов методов #add_column #remove_column или #change_column). Посетите страницу документации Rails API для дополнительной информации о синтаксисе и доступных методах.

Работа с валидациями

  1. В новой вкладке терминала введите $ rails console. Попробуйте запросить список всех пользователей с помощью команды User.all. В ответ вам должен прийти пустой массив (ведь пользователей пока нет!). Теперь создайте нового пустого пользователя сохраните его в переменную с помощью u = User.new. Этот пользователь был создан в пространстве памяти Ruby, но пока что не сохранен в базу данных. Запомните, если бы вы использовали метод #create вместо метода #new, то он бы просто пошел дальше и попытался сохранить нового пользователя сразу. Сейчас вместо этого, мы поработаем с несохраненным пользователем.
  2. Проверьте, является ли ваш новый пользователь корректным (иначе говоря, будет ли он действительно сохранен, если мы попытаемся это сделать). Команда u.valid? запустит все валидации. Она возвращает нам true... сюрприз! Мы пока не написали ни одной валидации, так что это было ожидаемо. Это так же становится проблемой, ведь мы не хотим иметь пользователей с пустыми именами.
  3. Реализуйте валидации пользователя, которые пришли вам в голову, в файле app/models/user.rb. Они могут включать ограничения на длину имени пользователя и необходимость его существования (иначе у вас потенциально могут появиться безымянные пользователи!), а так же уникальность имени.
  4. Перезагрузите вашу консоль с помощью reload!. Вам потребуется совершать это действие каждый раз, когда вы вносите изменения в свое приложение, чтобы консоль могла перезагрузить текущую версию. Если она до сих пор не работает, просто пропишите quit для выхода из нее, а затем запустите заново (иногда #reload! не приносит ожидаемого эффекта). Создайте еще одного нового пользователя, не сохраняя его, с помощью u2 = User.new. Снова выполните u2.valid? для запуска валидаций, и теперь результатом должно быть false. Отлично.
  5. Как мы можем узнать, что же пошло не так? Rails очень полезен, потому что он прикрепляет сообщения об ошибках прямо к вашему объекту пользователя, когда он не проходит валидации, так, чтобы вы могли прочесть их с помощью метода #errors. Попробуйте выполнить u.errors, чтобы увидеть ошибки, или, что еще лучше, u.errors.full_messages, чтобы вернуть дружелюбный массив сообщений об ошибках. Если вы определили собственные сообщения к своим валидациям, они так же появятся в этом массиве.
  6. Создайте пользователя, который может быть сохранен, с помощью u3 = User.new(your_attributes_here) и запустите валидации. Они дожны вернуть true. Сохраните вашего пользователя с помощью метода #save, и теперь у вас есть свой первый пользователь в базе данных.

Работа с ассоциациями

  1. Создайте модель Post в соответствии с вашей схемой хранения данных из первого шага выше, выполните миграции к базе данных, добавьте ей валидации.
  2. Проверьте свои валидации из консоли, не забывая перезагружать или перезапускать ее после внесения изменений.
  3. Теперь задайте ассоциацию между моделями User и Post. Вы не забыли включить столбец с внешним ключом (user_id) в вашу таблицу постов (posts)? Если все же забыли, просто создайте новую миграцию ($ rails generate migration yourmigrationname) и используйте метод #add_column, упомянутый ранее.
  4. Если вы верно задали ассоциации, то у вас должна появиться возможность использовать еще несколько методов в консоли, включая поиск постов пользователя и поиск пользователя-автора поста. Сперва проверьте поиск постов вашего одинокого пользователя - User.first.posts. Он должен вернуть пустой массив, ведь вы еще не создали постов, но он не должен выбрасывать вам ошибку.
  5. Создайте (но пока не сохраняйте) новый пост из консоли, назовите его p1, это должно выглядеть примерно так p1 = Post.new(your_attributes_here). Не забудьте включить идентификатор (ID) пользователя в поле user_id!
  6. Теперь создайте пост, используя ассоциацию с пользователем, - замените метод #new на #build и вызовите его через ассоциацию - p2 = User.first.posts.build. Пока не заполняйте никаких полей. Изучите созданный объект, и вы увидите, что поле ID уже заполнено без вашего вмешательства, круто! Подробнее об этом ловком трюке вы узнаете в уроке по ассоциациям.
  7. Сохраните ваш новый пост p1, чтобы ваш пользователь официально создал свою первую запись. Проверьте, что вы можете использовать обратную ассоциацию, с помощью команды Post.first.user, которая должна вернуть изначальный объект User, чей ID вы указывали при создании поста. Круг замкнулся!

Добавление комментирования

  1. У вас уже есть модели User и Post, соединенные друг с другом. Комментирование будет выглядеть схоже с моделью Post, однако будет связано не только с "родительским" постом, но и с пользователем, который является автором комментария. Для вашей модели Comment(комментарий) создайте миграции и выполните их к базе данных.
  2. Как и ранее, добавьте валидации к модели и проверьте их через консоль (не забывайте обновлять ее!). Убедитесь, что вы требуете обязательного заполнения 2 внешних ключей (для постов и для пользователей), иначе у вас могут появиться "осиротевшие" записи (их нельзя будет отнести к посту и/или пользователю). У вас не должно быть возможности сохранить некорректный комментарий, в то же время комментарий без ошибок должен сохраняться.
  3. Создайте второго пользователя и новый комментарий, который представляет собой мнение этого пользователя по поводу поста первого пользователя.
  4. Как и ранее, добавьте необходимые ассоциации между пользователями, постами и комментариями. Вам потребуется возможность успешно вызывать следующие методы из консоли (учитывая, что ваш второй пользователь имеет ID равный 2)

    1. u2 = User.find(2)
    2. c1 = u2.comments.first должно вернуть комментарий этого пользователя. #comments возвращает массив комментариев, поэтому нам необходимо использовать #first, чтобы получить сам комментарий.
    3. c1.user должно вернуть пользователя-автора комментария (u2).
    4. p1 = Post.first
    5. p1.comments.first должно вернуть комментарий c1.
    6. c1.post должно вернуть пост p1.

Если какой-либо из них не работает, дважды проверьте ваши ассоциации. Иногда сообщения об ошибках могут привести вас к решению каких ассоциаций вам не хватает.

Решения студентов

Дополнительные ресурсы

Этот раздел содержит полезные ссылки на дополнительные материалы. Они не обязательны, так что расценивайте их как нечто полезное, если вы хотите поглубже погрузиться в тему

  • Rails API содержит хорошую документацию в дополнение к вещам, о которых вы уже читали в Edge Guides. Часто проще искать в Google нужную страницу документации, нежели пользоваться навигацией сайта (например, попробуйте "rails api has_many").
  • Страничка JumpstartLab об отношениях между моделями содержит полезную информацию о подходах к оптимизации типичных ассоциаций.

Поделиться уроком: