Данный гайд по связям/взаимоотношениям/ассоциациям я честно спер с ресурса rubyonrails.org, приложил некоторые усилия для перевода и оформления, так что меня пинать за недобросовестность нечего! Лучше читайте кусок полезной теории, пригодится 100%.
Это руководство поведает об особенностях ассоциативных связей в Active Record. Использовав данное руководству по назначению, можешь научится следующим полезностям:

  • определение связей между моделями Active Record;
  • понимание какие типы связей необходимо использовать в вашей задаче;
  • использование доп. методов, которые дают ассоциативные связи.

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

1. Зачем нужны ассоциативные связи?

Зачем нам нужны ассоциативные связи между моделями? Для того чтобы упростить программирование обыденных операций. К примеру, рассмотрим простое Rails-приложение, которое включает модель заказчика и модель заказа. Каждый заказчик может иметь много заказов. Без связей объявление моделей выглядело бы следующим образом:

class Customer < ActiveRecord::Base
end 
 
class Order < ActiveRecord::Base
end

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

@order = Order.create(:order_date => Time.now, :customer_id => @customer.id)

А удаляя заказчика, необходимо убедиться что и все его заказы тоже удалены:

@orders = Order.find_by_customer_id(@customer.id)
@orders.each do |order|
    order.destroy
end
@customer.destroy

Используя Active Record ассоциации, мы упрощаем эти и другие операции, показываем рельсам, что имеется связь между двумя моделями. Вот видоизмененный код моделей заказчика и заказа:

class Customer < ActiveRecord::Base
    has_many :orders, :dependent => :destroy
end
 
class Order < ActiveRecord::Base
    belongs_to :customer 
end

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

@order = @customer.orders.create(:order_date => Time.now)

А удаление заказчика и всех его заказов и того легче:

@customer.destroy

Чтобы разобраться в различных типах ассоциативных связей, стоило бы прочесть и вторую часть руководства.

2. Типы ассоциациативных связей

В Rails ассоциативные связи — есть взаимоотношение двух моделей, наследованных от Active Record. Ассоциации выполняются в стиле вызовов, что позволяет добавить функциональность в вашу модель. К примеру, объявлением что одна модель принадлежит другой, вы даете знать Rails, что необходимо включить поддержку первичных и сторонних индексных ключей между двумя объектами этих двух моделей. В нагрузку вы получаете множество полезных методов. Rails предоставляет возможность создать шесть типов ассоциативных связей:

  • belongs_to
  • has_one
  • has_many
  • has_many :through
  • has_one :through
  • has_and_belongs_to_many

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

2.1 Ассоциация belongs_to

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

class Order < ActiveRecord::Base 
    belongs_to :customer 
end

2.2 Ассоциация has_one

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

class Supplier < ActiveRecord::Base
    has_one :account 
end

2.3 Ассоциация has_many

Данная ассоциативная связь указывает на связь один к многим (1-*) двух различных моделей. Вы часто можете найти это указание на «другой стороне» ассоциаций типа belongs_to. Данная связь означает, что каждая сущность модели имеет ноль или более сущностей другой модели. К примеру, в приложении с заказчиками и заказами, заказчик может иметь множество заказов, а может и не иметь вовсе. Поэтому модель заказчика будет выглядеть следующим образом:

class Customer < ActiveRecord::Base
    has_many :orders  #обратите внимание, что order теперь во множественном числе, логика жесткая!
end

2.4 Ассоциация has_many :through

Ассоциация has_many :trough зачастую используется при связи много к многим (*-*) двух моделей. Эта ассоциативная связь означает, что описываемая модель может соответствовать нулю или более сущностям другой модели, обрабатываемых третьей моделью. К примеру, рассматривая медицинскую практику, пациенту предписания делаются доктором. Объявление соответствующей связи будет могло бы выглядеть следующим образом:

class Physician < ActiveRecord::Base
    has_many :appointments  
    has_many :patients, :through => :appointments 
end 
 
class Appointment < ActiveRecord::Base 
    belongs_to :physician  
    belongs_to :patient 
end 
 
class Patient < ActiveRecord::Base 
    has_many :appointments  
    has_many :physicians, :through => :appointments 
end


Has_many :through простейший способ связать вложенные модели. Например, если текст содержит главы, а главы включают в себя несколько параграфов, вы возможно захотите получить коллекцию всех параграфов текста. Сделать можно это так:

class Document < ActiveRecord::Base 
    has_many :sections  
    has_many :paragraphs, :through => :sections 
end 
 
class Section < ActiveRecord::Base 
    belongs_to :document  
    has_many :paragraphs 
end 
 
class Paragraph < ActiveRecord::Base 
    belongs_to :section 
end

2.5 Ассоциация has_one :through

Has_one :through ассоциативная связь устанавливается при связи один к одному (1-1) двух моделей. Эта ассоциация показывает что представленной модели может соответствовать один объект другой модели, обрабатываемый третьей моделью. К примеру каждый поставщик имеет одну учетную запись, а каждая учетная запись связана с одной историей счетов, тогда модель заказчика может выглядеть следующим образом:

class Supplier < ActiveRecord::Base 
    has_one :account  
    has_one :account_history, :through => :account 
end 
 
class Account < ActiveRecord::Base 
    belongs_to :supplier  
    has_one :account_history 
end 
 
class AccountHistory < ActiveRecord::Base 
    belongs_to :account 
end

2.6 Ассоциация вида has_and_belongs_to_many

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

class Assembly < ActiveRecord::Base 
    has_and_belongs_to_many :parts 
end 
 
class Part < ActiveRecord::Base 
    has_and_belongs_to_many :assemblies 
end

Это конечно же не всё, я уже спешу перевести остатки, но на данном этапе хорошо бы понять, какие связи есть и как они записываются, дальше – легче! Продолжение

2 Комментари(я/ев) to “Взаимоотношения моделей в Rails”

  1. Yarik Says:

    зачет! жду продолжения.

  2. /etc/reflections – размы�?ления на тему… » Blog Archive » Взаимоотно�?ение моделей в Rails, часть вторая Says:

    [...] Первая часть тут, а мы продолжаем, мвахахаха! Нам еще бы разобраться где ставить belongs_to, что выбрать has_many :through или has_and_belongs_to_many, как реализуются полиморфные ассоциации, ну и наконец, незабыть про вложенные (nested) ассоциативные связи. [...]

Leave a Reply

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