2011-05-04 177 views
35
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 

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

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 
+1

去试试看今天有点看看我是否完全理解如何做到这一点。 – Serodis 2011-05-05 12:28:25

回答

87

要创建多态has_many:through,您必须先创建模型。我们将使用'文章','类别'和'标签',其中'标签'是连接模型,文章是可以用类别“标记”的许多对象之一。

首先创建'文章'和'类别'模型。这些都是不需要任何特别注意的基本款,只是尚未:现在

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 

的连接表连接在一起的两个表,或在我们的案例中,通过多态行为可以为其他许多人提供表格它通过存储来自两个独立表的ID来执行此操作。这创建了一个链接。我们的“类别”表格将始终是“类别”,因此我们添加了“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 

然后你可以重复这个,这将链接你的类别和文章。这样做了以后,你将能够访问每篇文章的类别和每个categorie的文章:

Article.first.categories 
Category.first.articles 

注:

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

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

3)当链接类别的文章中,我们使用: 的has_many:文章:通过=>:标签,:源=>:加标签,:SOURCE_TYPE => '文章' 这告诉类型模型,它应有许多文章:标签。来源是:taggable,出于与上述相同的原因。源类型是“Article”,因为模型会自动将taggable_type设置为自己的名称。

+2

您能否包含迁移中的最佳索引? – ajbraus 2013-09-13 15:37:11

+0

该视图如何工作?我可以让它渲染,但不保存到数据库。我尝试过: '<%= f.collection_select:tags,Category.all,:id,:name,{:prompt =>'Select up to 3'},{:class =>'o-input - quiet '}%>' – Erica 2015-08-23 16:56:00

14

你根本无法使连接表多态,至少Rails不支持这个开箱即用。该解决方案(从奥比的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 

我希望我帮助!

+0

我已更新,在整个设置上仍然有点困惑。 – Serodis 2011-05-07 22:46:54

+0

使我的一天! – 2015-03-06 10:19:15