пятница, 19 июня 2009 г.

Связи в моделях. Один к одному

Я давно хотел написать серию публикаций о связях в моделях, все не доходили руки. Этой статьей я начну серию статей которая раскроет суть взаимодействия моделей в Ruby on Rails.
Связь один к одному
Если у читателей был опыт разработки с использованием БД, то вероятно вам уже известно, как создавать SQL запросы на выборку из разных таблиц. В Ruby on Rails все выглядит немного более привлекательно. Так как Active Record является полноценной ORM, то вполне понятно, что работа со связанными таблицами может быть гораздо удобнее.

Как уже вы знаете, каждой таблице в БД, в ROR(ActiveRecord) сопоставляет одноименный обьект (модель), правда стоит учитывать, что имя таблицы должно быть во множественном числе, в отличии от имени обьекта(модели). Также для доступа к каждому полю таблицы существует одноименный метод в модели (Например таблица users содержит поле name, то в модели оно доступно, как obj.name, где obj - объект класса User). Потому и говорят что таблица "мапится" моделью - что и есть основным принципом ORM. Детальнее тут.

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

Так как вместо таблиц мы используем модели, то нам хотелось бы написать что-то типа такого:
user.address.street - где User и Adress єкземпляры классов соответствующих моделей, а street - свойство экземпляра класса адреса. Заманчиво, не правда ли?

Для того, чтобы написать подобное, использем SQL:

SELECT addresses.name
FROM addresses INNER JOIN users on users.id = addresses.user_id
нам бы пришлось выполнить запрос и достать из него нужное поле... Как по мне, то немного неудобно.

Так как же, все-таки, изменить модели, чтобы мы могли так ими оперировать?
Именно это и является темой данной статьи. Давайте рассмотрим запрос на SQL более детально, так как нам надо выяснить для себе некоторые моменты.

Для того, чтобы связать две таблицы как "1 к 1", нам необходимо выяснить для себя - какая таблица является родительской, а какая подчиненной.

Оказывается, это довольно-таки просто: рассмотрим 2 строку запроса, а именно условие обьеденения
users.id = address.user_id
Таблица Addresses содержит первичный ключ таблицы Users, что автоматически делает ее подчиненной.

Сформулируем словами связи между таблицами: таблица Users содержит таблицу Addresses с одной стороны, таблица Addresses относится к таблице Users - с другой стороны. Все вполне логично. Теперь посмотрим, как все выше сказанное реализовать в моделях RoR:

class Address < ActiveRecord::Base
   belongs_to :user
   # дальше идет код который описывает управление данными модели
end
class User < ActiveRecord::Base
   has_one :address
   # дальше идет код который описывает управление данными модели
end

В самом начале описания модели, мы указываем как она связана с другими моделями. Для реализации связи "1 к 1", достаточно "сказать" модели User - что она has_one (содержит один) Address, а Address в свою очередь belongs_to(содержит) User. Вот и все!

Что мы получили в результате
С этого момента модели являются связанными между собой, и при построении запросов типа: user.address.street ActiveRecord автоматически будет добавлять связи.

Теперь возможно, используя связи, пользоваться подчиненной моделью (таблицей) как частью таблицы родителя(свойством модели родителя), ну думая о том, что на самом деле данные разнесены по разным таблицам.

Имеем полное право вычитать адресные данные пользователя:

User.address.find(:all)

street = User.find_by_id(id).address.street

Комментариев нет:

Отправить комментарий