У цьому посібнику ми розглянемо один-до-одного асоціації в Rails за допомогою has_one
та belongs_to
. Ми охопимо:
1️⃣ Вступ
2️⃣ Коли використовувати has_one
та belongs_to
3️⃣ Налаштування один-до-одного асоціації
4️⃣ Визначення асоціацій
5️⃣ Створення та доступ до даних
6️⃣ Налаштування асоціацій
7️⃣ Запит один-до-одного асоціацій
8️⃣ Обробка видалення (dependent
опція)
9️⃣ Повний приклад з міграціями
🔟 Висновок
1️⃣ Вступ
У Rails один-до-одного відношення означає, що один запис в таблиці пов'язаний з рівно одним записом в іншій таблиці.
Це реалізовано за допомогою has_one
та belongs_to
.
2️⃣ Коли використовувати has_one
та belongs_to
| Асоціація | Модель | Чужий ключ? | Мета |
| --- | --- | --- | --- |
| belongs_to
| Дочірня модель | ✅ Так | Вказує, що модель належить іншій моделі. |
| has_one
| Батьківська модель | ❌ Ні | Вказує, що модель має один пов'язаний запис. |
Приклад: Користувач та Профіль
- Користувач має один профіль (
has_one
) - Профіль належить користувачу (
belongs_to
і зберігає чужий ключuser_id
)
3️⃣ Налаштування один-до-одного асоціації
Крок 1: Створення моделей
Запустіть наступну команду для генерації моделей User
та Profile
:
rails g model User name:string email:string
rails g model Profile bio:text user:references
user:references
автоматично додає чужий ключ user_id
до таблиці profiles
.
Крок 2: Міграція бази даних
rails db:migrate
4️⃣ Визначення асоціацій
Модель Користувача (has_one
)
class User < ApplicationRecord
has_one :profile, dependent: :destroy
end
has_one :profile
→ Користувач має один профіль.dependent: :destroy
→ Видаляє профіль, коли користувач видаляється.
Модель Профілю (belongs_to
)
class Profile < ApplicationRecord
belongs_to :user
end
belongs_to :user
→ Профіль належить користувачу (містить чужий ключ user_id
).
5️⃣ Створення та доступ до даних
Створення користувача з профілем
user = User.create(name: "Alice", email: "[email protected]")
profile = Profile.create(bio: "Software Developer", user: user)
або за допомогою Active Record Association Helper:
user.create_profile(bio: "Software Developer")
Доступ до пов'язаних записів
user.profile.update(bio: "Senior Developer")
Видалення пов'язаних записів
user.destroy # Видаляє користувача та пов'язаний профіль завдяки `dependent: :destroy`
6️⃣ Налаштування асоціацій
Користувацький чужий ключ
За замовчуванням, Rails використовує {model}_id
(наприклад, user_id
), але ви можете змінити його:
class Profile < ApplicationRecord
belongs_to :user, foreign_key: "account_id"
end
class User < ApplicationRecord
has_one :profile, foreign_key: "account_id"
end
Користувацька назва таблиці
Якщо назва таблиці не відповідає стандартам Rails, вкажіть її вручну:
class Profile < ApplicationRecord
self.table_name = "user_profiles"
end
Користувацький первинний ключ
Якщо User
використовує uuid
замість id
як первинний ключ:
class User < ApplicationRecord
self.primary_key = "uuid"
has_one :profile, foreign_key: "user_uuid"
end
class Profile < ApplicationRecord
belongs_to :user, foreign_key: "user_uuid", primary_key: "uuid"
end
7️⃣ Запит один-до-одного асоціацій
Попереднє завантаження даних (includes
)
Уникайте запитів типу N+1:
User.includes(:profile).where(profiles: { bio: "Developer" })
Об'єднання таблиць (joins
)
User.joins(:profile).where(profiles: { bio: "Developer" })
Пошук пов'язаних записів
User.find(1).profile
Profile.find(1).user
8️⃣ Обробка видалення (dependent
опція)
| Опція | Поведінка |
| --- | --- |
| dependent: :destroy
| Видаляє пов'язаний профіль, коли користувач видаляється |
| dependent: :nullify
| Встановлює user_id
у profiles
на NULL
|
| dependent: :restrict_with_error
| Запобігає видаленню користувача, якщо профіль існує |
Приклад:
class User < ApplicationRecord
has_one :profile, dependent: :nullify
end
9️⃣ Повний приклад з міграціями
Міграція для users
class CreateUsers < ActiveRecord::Migration[7.0]
def change
create_table :users do |t|
t.string :name
t.string :email
t.timestamps
end
end
end
Міграція для profiles
class CreateProfiles < ActiveRecord::Migration[7.0]
def change
create_table :profiles do |t|
t.text :bio
t.references :user, null: false, foreign_key: true
t.timestamps
end
end
end
🔟 Висновок
✅ Основні моменти
- Використовуйте
has_one
на батьківській моделі (не зберігає чужий ключ). - Використовуйте
belongs_to
на дочірній моделі (зберігає чужий ключ). - Налаштуйте чужі ключі, назви таблиць та первинні ключі, якщо це необхідно.
- Використовуйте
dependent: :destroy
для управління видаленням. - Оптимізуйте запити за допомогою
includes
,joins
, та попереднього завантаження (eager loading).
Перекладено з: Ruby on Rails One-to-One Association (hasone & belongsto) - Complete Guide