Ruby on Rails 3: Ассоциации между моделями ч. 2
апреля 26, 2012 | Published in Ruby on Rails, Ruby on Rails 3, Базы данных
Ассоциации между моделями ч. 1. В этой статьи мы поговорим об интересных параметрах и возможностях ассоциаций моделей.
Псевдонимы
Часто бывает необходимо или желательно использовать отличное от имени модели имя ассоциации. Например у нас есть две модели Store и User и у Store имеется владелец (seller — продавец). store.user выглядит не очень красиво, как буд-то речь идет о пользователе магазина, а не о его владельце (продавце), кроме того, у нас может быть несколько ассоциаций с моделью User, например у нас может быть buyer и seller.
Чтобы реализовать такие псевдонимы и множественные ассоциации между двумя моделями мы можем воспользоваться следующим кодом:
class User < ActiveRecord::Base if seller? has_one: :store, foreign_key: seller_id, dependent: :destroy elsif buyer? belongs_to :store end def seller?; role == 'seller'; end def buyer?; role == 'buyer'; end end class Store < ActiveRecord::Base has_many :buyers, class_name: 'User' belongs_to :seller, class_name: 'User' end
Полиморфизм
Полиморфные ассоциации — это ассоциации, где несколько различных сущностей (моделей) в контексте ассоциации представляются как одна единственная. Примером полиморфных ассоциаций могут служить комментарии. Единственная сущность Comment может принадлежать как статьям — Article, топикам — Topic и собственно другим комментариям, если разрешены вложенные комментарии. Пример:
class Article < ActiveRecord::Base has_many :comments, as: :commentable, dependent: :destroy end class Topic < ActiveRecord::Base has_many :comments, as: :commentable, dependent: :destroy end class Comment < ActiveRecord::Base has_many :comments, as: :commentable, dependent: :destroy belongs_to :commentable, polymorphic: true end
В данном случае все три сущности Article, Topic и Comment для комментариев превращаются в одну — Commentable (комментируемое). В таблице comments помимо поля commentsble_id должно также присутствовать поле commentable_type, которое хранит тип комментируемой сущности, соответственно Article, Topic или Comment.
Счетчики
Чтобы сократить число запросов рекомендуется использовать counter_cache. Рассмотрим пример, когда вам необходимо показать число комментариев к статье.
class Article < ActiveRecord::Base has_many :comments, dependent: :destroy end class Comment < ActiveRecord::Base belongs_to :article, counter_cache: true end
У таблицы articles при этом должно присутствовать поле comments_count, для которого значение по умолчанию установлено в 0. Значение хранимое в этом поле будет приращиваться или убывать соответственно при создании или удалении комментария.
Теперь в представлениях статей мы можем использовать что-то вроде следующего slim-кода:
- if article.comments_count > 0 = render article.comments - else Нет комментариев
Удачи в освоении Ruby и Rails!