Подтвердить что ты не робот

Настройка полиморфного has_many: через отношения

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
4b9b3361

Ответ 1

Чтобы создать полиморфный has_many: через, вы должны сначала создать свои модели. Мы будем использовать "Аргумент", "Категория" и "Тег", где "Тег" - это модель объединения, а статья - один из многих объектов, которые могут быть "помечены" категорией.

Сначала вы создаете свои модели "Article" и "Category". Это основные модели, которые пока не требуют особого внимания:

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_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". Когда вы уничтожаете связанный объект, он также уничтожит ссылку. Это гарантирует, что нет плохих или мертвых ссылок. Вот почему мы используем ': dependent = > : destroy'

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

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

Ответ 2

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

Если вам это действительно нужно, 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

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