设置多态has_many:通过关系

时间:2011-05-04 16:34:27

标签: ruby-on-rails-3 polymorphism

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 个答案:

答案 0 :(得分:87)

要创建多态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

join-table将两个表连接在一起,或者在我们的例子中通过多态行为将一个表连接到许多其他表。它通过存储来自两个单独表的ID来实现。这会创建一个链接。我们的“类别”表将始终为“类别”,因此我们包含“category_id”。它链接的表格各不相同,因此我们添加了一个“taggable_id”项,它包含任何可标记项的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 =&gt; :破坏'

2)在设置我们的'文章'模型时,我们的'可标记'模型,必须使用:as链接。由于在前面的例子中我们使用'taggable_type'和'taggable_id',我们使用:as =&gt; :加标签。这有助于rails了解如何将值存储在数据库中。

3)将类别链接到文章时,我们使用: has_many:articles,:through =&gt; :tags,:source =&gt; :taggable,:source_type =&gt; '文章' 这告诉类别模型它应该有很多:文章到:标签。源是:可标记的,原因与上述相同。 source-type是“Article”,因为模型会自动将taggable_type设置为自己的名称。

答案 1 :(得分:15)

你根本无法使连接表具有多态性,至少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

我希望我帮忙!

相关问题