设置一个多态has_many:through关系

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 

我已经创build了我的模型,如上面的代码所示。 文章将是可以有标签的许多模型之一。 类别模型将包含可能分配的所有类别。 标记模型将是一个多态的连接表,它代表标记的关系。

 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 

要创build一个多态has_many:through,你必须先创build你的模型。 “标签”是连接模型,“物品”是“物品”,“类别”和“标签”,物品是可以用类别“标记”的许多物品之一。

首先,创build“文章”和“类别”模型。 这些都是基本的模式,不需要特别的关注,

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

现在,我们将创build我们的多态连接表:

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

连接表通过多态行为将两个表连接在一起,或者在我们的案例中将一个表连接到许多其他表。 它通过存储两个独立表的ID来完成。 这创build了一个链接。 我们的“类别”表将始终是“类别”,因此我们添加了“category_id”。 它链接到的表格会有所不同,所以我们添加一个包含任何可标记项目的标识的项目“taggable_id”。 然后,我们使用“taggable_type”来完成链接,让链接知道链接的内容,如文章。

现在,我们需要build立我们的模型:

 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)每当你想删除一个链接模型链接的项目,一定要使用“销毁”。 当你销毁一个链接的对象时,它也会破坏链接。 这确保没有不良或死链接。 这就是为什么我们使用':dependent =>:destroy'

2)在build立我们'标签'模型的'文章'模型时,它必须使用:as来链接。 由于在前面的例子中,我们使用了'taggable_type'和'taggable_id':as =>:taggable。 这有助于rails知道如何将值存储在数据库中。

3)将类别链接到文章时,我们使用:has_many:articles,:through =>:tags,:source =>:taggable,:source_type =>'Article'通过以下方式告诉类别模型:标签。 来源是:taggable,出于与上述相同的原因。 源types是“Article”,因为模型会自动将taggable_type设置为自己的名称。

你只是不能使联接表多态,至lessRails不支持这个开箱即用。 解决办法是(取自Obie's Rails 3的方法):

如果你真的需要它, has_many :through可以用多态关联,但只能通过指定你想要的types的多态关联。 为此,您必须使用: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 

我希望我帮助!