Настройка полиморфного отношения has_many: through - PullRequest
35 голосов
/ 04 мая 2011
rails g model Article name:string
rails g model Category name:string
rails g model Tag name:string taggable_id:integer taggable_type:string category_id:integer

Я создал свои модели, как показано в предыдущем коде.Статьи будут одной из многих моделей, которые могут иметь теги.Модель категории будет содержать все категории, которые могут быть назначены.Модель тегов будет полиморфной таблицей соединений, которая представляет помеченные отношения.

class Article < ActiveRecord::Base
  has_many :tags, :as => :taggable
  has_many :categories, :through => :taggable
end

class Category < ActiveRecord::Base
  has_many :tags, :as => :taggable
  has_many :articles, :through => :taggable
end

class Tag < ActiveRecord::Base
  belongs_to :taggable, :polymorphic => true
  belongs_to :category
end

Я не могу заставить это работать, я могу сделать это не полиморфно, но у меня должно быть что-то не так сполиморфная часть.Любые идеи?

Редактировать: Все еще не понимаю это:

class Article < ActiveRecord::Base
    has_many :taggables, :as => :tag
    has_many :categories, :through => :taggables, :source => :tag, :source_type => "Article"
end
class Category < ActiveRecord::Base
    has_many :taggables, :as => :tag
    has_many :articles, :through => :taggables, :source => :tag, :source_type => "Article"
end
class Tag < ActiveRecord::Base
  belongs_to :taggable, :polymorphic => true
  belongs_to :category
end

Ответы [ 2 ]

87 голосов
/ 16 мая 2011

Чтобы создать полиморфный has_many: through, вы должны сначала создать свои модели.Мы будем использовать «Article», «Category» и «Tag», где «Tag» - это модель соединения, а Article - один из многих объектов, которые можно «пометить» категорией.

Сначала вы создаетеваши модели «Статья» и «Категория».Это основные модели, которые пока не требуют особого внимания:

rails g model Article name:string
rails g model Category name:string

Теперь мы создадим нашу полиморфную таблицу соединений:

rails g model Tag taggable_id:integer taggable_type:string category_id:integer

Таблица соединений объединяетсядве таблицы, или в нашем случае одна таблица для многих других с помощью полиморфного поведения.Это делается путем сохранения идентификатора из двух отдельных таблиц.Это создает ссылку.Наша таблица «Category» всегда будет «Category», поэтому мы добавляем «category_id».Таблицы, на которые он ссылается, могут изменяться, поэтому мы добавляем элемент taggable_id, который содержит идентификатор любого тегируемого элемента.Затем мы используем «taggable_type», чтобы завершить ссылку, позволяющую ссылке знать, с чем она связана, например, статью.

Теперь нам нужно настроить наши модели:

class Article < ActiveRecord::Base
  has_many :tags, :as => :taggable, :dependent => :destroy
  has_many :categories, :through => :tags
end
class Category < ActiveRecord::Base
  has_many :tags, :dependent => :destroy
  has_many :articles, :through => :tags, :source => :taggable, :source_type => 'Article'
end
class Tag < ActiveRecord::Base
  belongs_to :taggable, :polymorphic => true
  belongs_to :category
end

После этого настройте базу данных, используя:

rake db:migrate

Вот и все!Теперь вы можете настроить свою базу данных с реальными данными:

Category.create :name => "Food"
Article.create :name => "Picking the right restaurant."
Article.create :name => "The perfect cherry pie!"
Article.create :name => "Foods to avoid when in a hurry!"
Category.create :name => "Kitchen"
Article.create :name => "The buyers guide to great refrigeration units."
Article.create :name => "The best stove for your money."
Category.create :name => "Beverages"
Article.create :name => "How to: Make your own soda."
Article.create :name => "How to: Fermenting fruit."

Теперь у вас есть несколько категорий и различных статей.Однако они не классифицированы по тегам.Итак, нам нужно сделать это:

a = Tag.new
a.taggable = Article.find_by_name("Picking the right restaurant.")
a.category = Category.find_by_name("Food")
a.save

Затем вы можете повторить это для каждого, это свяжет ваши категории и статьи.После этого вы сможете получить доступ к категориям каждой статьи и статьям каждой категории:

Article.first.categories
Category.first.articles

Примечания:

1) Всякий раз, когда вы хотите удалить элемент, связанный ссылкойМодель обязательно используйте «уничтожить».Когда вы уничтожаете связанный объект, он также уничтожает ссылку.Это гарантирует, что нет плохих или неработающих ссылок.Вот почему мы используем ': зависимый =>: destroy'

2) При настройке нашей модели Article, которая является одной из наших моделей taggable, она должна быть связана, используя: as.Так как в предыдущем примере мы использовали «taggable_type» и «taggable_id», мы используем: as =>: taggable.Это помогает рельсам знать, как хранить значения в базе данных.

3) При связывании категорий со статьями мы используем: has_many: article,: through =>: теги,: source =>: taggable,: source_type=> 'Article' Это говорит модели категории, что она должна иметь много тегов: article through:.Источник: taggable, по той же причине, что и выше.Тип источника - «Article», потому что модель автоматически установит taggable_type на свое имя.

15 голосов
/ 04 мая 2011

Вы просто не можете сделать таблицу соединений полиморфной, по крайней мере, Rails не поддерживает это из коробки.Решение (взято из Obie's Rails 3 way):

Если вам это действительно нужно, has_many :through возможно с полиморфными ассоциациями, но только с указанием того, какой именно тип полиморфных ассоциаций вы хотите.Для этого вы должны использовать опцию :source_type.В большинстве случаев вам придется использовать опцию :source, поскольку имя ассоциации не будет совпадать с именем интерфейса, используемым для полиморфной ассоциации:

class User < ActiveRecord::Base
  has_many :comments
  has_many :commented_timesheets, :through => :comments, :source => :commentable,
           :source_type => "Timesheet"
  has_many :commented_billable_weeks, :through => :comments, :source => :commentable,
           :source_type => "BillableWeek"

Это многословно и в целомСхема теряет свою элегантность, если вы идете по этому пути, но она работает:

User.first.commented_timesheets

Надеюсь, я помог!

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