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
要创建多态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",其中包含任何可标记项目的 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)每当要删除由链接模型链接的项目时,请确保使用"销毁"。销毁链接对象时,也会销毁链接。这可确保没有不良链接或死链接。这就是为什么我们使用':d ependent => :d estroy'
2)在设置我们的"文章"模型(这是我们的"可标记"模型之一)时,必须使用 :as 进行链接。由于在前面的示例中,我们使用了"taggable_type"和"taggable_id",因此我们使用 :as => :taggable。这有助于 rails 知道如何在数据库中存储值。
3)将类别链接到文章时,我们使用:has_many :文章, :通过 => :标签, :来源 => :可标记, :source_type => '文章'这告诉类别模型它应该通过 :tags 包含许多 :articles 。来源是:taggable,原因与上述相同。源类型为"文章",因为模型会自动将taggable_type设置为自己的名称。
你根本无法使连接表成为多态的,至少 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
我希望我有帮助!