0Pricing
Ruby Academy · Урок

Связи

has_many и belongs_to

«Связи» — бесплатный урок Ruby Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Ruby Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Ruby Academy содержит 4 уроков всего.

Что такое ассоциации

Ассоциации описывают отношения между моделями, чтобы Active Record мог самостоятельно переходить к связанным строкам. Вместо написания SQL-запросов с объединением таблиц Вы вызываете такие методы, как user.posts.

  • Они отражают внешние ключи в базе данных.
  • Они автоматически создают вспомогательные методы.
  • Благодаря им код читается как описание предметной области.

belongs_to

belongs_to означает, что эта модель хранит внешний ключ, указывающий на другую модель. Объект Comment, принадлежащий Post, содержит столбец post_id.

class Comment < ApplicationRecord
  belongs_to :post
end

# comment.post returns the parent Post
# Requires a post_id column on comments

has_many

has_many — это другая сторона связи: одна запись владеет множеством записей другого типа. У объекта Post есть много записей Comment. Внешний ключ хранится на стороне множества.

class Post < ApplicationRecord
  has_many :comments
end

# post.comments returns all related comments
# post.comments.create(body: "Nice!")

Где хранится внешний ключ

Модель, которая использует belongs_to, хранит внешний ключ. Для Post и Comment таблица comments содержит post_id. Настройте это в миграции с помощью t.references :post или add_reference.

create_table :comments do |t|
  t.references :post, foreign_key: true
  t.text :body
  t.timestamps
end

Создаваемые методы

Связь has_many :comments предоставляет коллекцию с удобными методами:

  • post.comments — для чтения.
  • post.comments.create(...) — для добавления связанной записи.
  • post.comments.count — для подсчёта.
  • post.comment_ids — для получения идентификаторов.
post = Post.find(1)
post.comments.create(body: "First!")
puts post.comments.count

has_one

has_one описывает связь один-к-одному, например связь User с одним объектом Profile. Внешний ключ по-прежнему хранится в другой модели (profiles.user_id).

class User < ApplicationRecord
  has_one :profile
end

class Profile < ApplicationRecord
  belongs_to :user
end

Связь многие-ко-многим через промежуточную модель

Для связи многие-ко-многим используйте промежуточную модель и has_many through. У объекта Student есть много записей Course, связанных через строки Enrollment.

class Student < ApplicationRecord
  has_many :enrollments
  has_many :courses, through: :enrollments
end

class Enrollment < ApplicationRecord
  belongs_to :student
  belongs_to :course
end

Параметры зависимостей

С помощью dependent определите, что произойдёт с дочерними записями при удалении родительской:

  • dependent: :destroy также удаляет дочерние записи.
  • dependent: :nullify очищает их внешний ключ.
  • dependent: :restrict_with_error блокирует удаление.
class Post < ApplicationRecord
  has_many :comments, dependent: :destroy
end

Проблема запроса N+1

Обход записей в цикле и обращение к ассоциации может запускать отдельный запрос для каждой записи — печально известную проблему N+1. Загрузка 10 публикаций, а затем их комментариев может выполнить 11 запросов вместо 2.

По мере роста объёма данных это незаметно замедляет приложения.

# N+1: one query per post for comments
Post.all.each do |post|
  puts post.comments.count
end

Исправление N+1 с помощью includes

includes указывает Active Record заранее загрузить ассоциацию за несколько запросов вместо множества. Это стандартное исправление проблемы N+1.

Post.includes(:comments).each do |post|
  puts post.comments.count
end

Пользовательские имена с помощью class_name

Если имя ассоциации не совпадает с именем модели, используйте такие параметры, как class_name и foreign_key. Например, ассоциацию author, связанную с моделью User.

class Post < ApplicationRecord
  belongs_to :author, class_name: "User"
end

Быстрая проверка

Проверьте, насколько хорошо Вы поняли ассоциации.

Итоги: ассоциации

Вы научились связывать модели:

  • belongs_to хранит внешний ключ, а has_many и has_one представляют другую сторону связи.
  • has_many through описывает связь многие-ко-многим.
  • dependent управляет каскадным удалением.
  • Избегайте запросов N+1 с помощью includes.

Далее Вы обеспечите целостность данных с помощью проверок и научитесь выполнять запросы.

Часто задаваемые вопросы

Урок «Связи» бесплатный?

Да — полный текст урока «Связи» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Ruby Academy, подпишись на CoddyKit PRO. Курс Ruby Academy содержит 4 уроков всего.

Чему я научусь в уроке «Связи»?

has_many и belongs_to Ты практикуешь Ruby Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать Ruby Academy?

Предыдущий опыт не требуется. Ruby Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.

Сколько времени занимает урок «Связи»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке Ruby Academy?

Да. Каждый урок Ruby Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы Active Record
  2. Миграции
  3. Связи
  4. Проверки и запросы
← Назад к Ruby Academy