Для моего третьего проекта во Flatiron я решил, что хочу расширить то, что я создал с помощью Sinatra. Ruby on Rails (или сокращенно Rails) — это название фреймворка, который мы изучали в течение последнего месяца или около того. Rails — довольно впечатляющее программное обеспечение, позволяющее быстро создавать необходимые представления, контроллеры и базы данных. Я обнаружил, что процесс повторного посещения предыдущего проекта с этим новым набором инструментов и моими расширенными знаниями был увлекательным, мотивирующим, а также очень познавательным.
С Sourdough Tracker пользователи не могли взаимодействовать друг с другом. Ингредиенты, рецепты и выпечка каждого пользователя были отдельными и разными, чтобы их мог видеть только отдельный пользователь, которому они принадлежали. В этом проекте я хотел расширить возможности, чтобы обеспечить базовое социальное взаимодействие между учетными записями. Я хотел, чтобы пользователи могли обмениваться рецептами или делиться своими успехами с мукой конкретной мельницы или производителя (сам я фанат муки Janie’s Mill). Из этого следует, что пользователи должны иметь возможность оставлять комментарии, делясь своим опытом использования определенного рецепта или ингредиента.
Отображение отношений
Первым шагом к тому, чтобы воплотить это в жизнь, было составление схемы моих моделей и их различных взаимосвязей. Структура, скелет вашего приложения, на самом деле возникает из того, как вы настраиваете свою базу данных, и поэтому я потратил много времени на обдумывание того, как все должно быть связано.
Несколько запутанная схема, которую вы видите выше, — это то, на чем я остановился. Многое происходит, но вы можете видеть, что некоторые модели должны быть общедоступными, доступными для любого пользователя, в то время как я хотел, чтобы другая информация строго принадлежала пользователю, который ее создал. Важно отметить, что я хотел, чтобы пользователи могли сохранять ингредиенты или рецепты, которые они сочли полезными, чтобы они могли легко ссылаться на них без необходимости искать каждый ингредиент или каждый рецепт, размещенный на сайте.
Хорошо, я делал это раньше. Это отношение has_many
к has_many
. Все, что мне нужно сделать, это настроить таблицу соединений и сообщить ActiveRecord об отношениях, и все готово. Конечно, мне нужно настроить таблицу users_ingredients
и таблицу users_recipes
, но это не страшно.
Фу. Ждать…
Комментарии являются также связующей таблицей между пользователем и объектом, но комментарии могут относиться к сообщению, и ингредиенту, и рецепту. И я также хотел добавить возможность «лайкать» вещи, чтобы каждый Like
функционировал как таблица соединений между User
и любым понравившимся объектом?? На данный момент я просматриваю несколько таблиц соединения для каждого объекта, что начинает казаться довольно повторяющимся. Должен быть более простой способ, верно?
Введите полиморфные ассоциации
Как бы заманчиво это ни было, я не создал независимую таблицу соединения между каждой моделью и моими пользователями. Вместо этого я использовал функцию Rails под названием полиморфные ассоциации. Полиморфные ассоциации позволяют вам создать таблицу соединений, которая может относиться к нескольким классам, радикально упрощая ваш код и обеспечивая определенную степень модульности, которую я нашел довольно изящной.
Обычная таблица соединений имеет два столбца, по одному для каждой отслеживаемой модели. Каждый столбец назван в честь модели, которую он отслеживает, и каждая строка содержит различные индексы, каждый из которых является внешним ключом, извлеченным из другой таблицы. Короче говоря, в обычной таблице соединений в столбце указано, какие модели задействованы, а в строке — какие конкретные экземпляры связаны.
При полиморфных ассоциациях индекс и тип связанной модели хранится в одной строке. Столбцы просто отслеживают, какой столбец является индексным, а какой столбцом типа модели.
Это позволило мне создать модель Bookmark
, которая могла бы связать User
с несколькими объектами без необходимости в таблице соединений для каждого отношения модели!
Миграция для моей таблицы Bookmarks выглядит следующим образом:
create_table :bookmarks do |t| t.belongs_to :user t.bigint :bookmarkable_id t.string :bookmarkable_type t.timestamps end
И соответствующие модельные отношения:
class User < ApplicationRecord has_many :bookmarks end class Bookmark < ApplicationRecord belongs_to :user belongs_to :bookmarkable, polymorphic: true end class Recipe < ApplicationRecord has_many :bookmarks, as: :bookmarkable end
Самым интересным было то, что пользователи могли отслеживать рецепты, которые они создали, в дополнение крецептам, которые они хотели добавить в закладки. И эта же модель может позволить User
«отмечать» посты, ингредиенты или любую будущую модель, добавленную в базу данных!
Эта модульность сделала добавление или удаление функций относительно легким. Допустим, я добавляю возможность загружать изображения и хочу, чтобы пользователи могли лайкать любое изображение. Все, что я должен написать, это то, что изображение has_many :likes, as: :likeable
и я отправляюсь на гонки.
Это оказалось особенно удобным с возможностью абстрагировать части ваших представлений в частичные. Как только я написал код для отображения комментариев или добавления кнопки «Нравится», было относительно легко разместить его там, где это было необходимо, поскольку объект, который отслеживал все, был одним и тем же, и вся информация хранилась в одной базе данных!
Вот книга хлеба
Я весьма доволен тем, какие полиморфные ассоциации и Rails в целом позволили мне построить в ходе этого проекта. Возвращение к предыдущей идее проекта с новыми навыками и знаниями, которые я приобрел за последний месяц, было очень полезным опытом. Трудно поверить, что в октябре я едва умел программировать.
Ниже видео-обзор сайта, который я создал. Не стесняйтесь проверить код на Github и, пожалуйста, не стесняйтесь обращаться к нам, если у вас есть какие-либо вопросы или предложения о том, как я могу улучшить!