2011-05-04 96 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