2008-11-24 29 views
26

我該如何實現以下目標?我有兩個模型(博客和讀者)和連接表,讓我有一個N:他們m之間的關係:如何避免has_many:through關係中的重複?

class Blog < ActiveRecord::Base 
    has_many :blogs_readers, :dependent => :destroy 
    has_many :readers, :through => :blogs_readers 
end 

class Reader < ActiveRecord::Base 
    has_many :blogs_readers, :dependent => :destroy 
    has_many :blogs, :through => :blogs_readers 
end 

class BlogsReaders < ActiveRecord::Base 
    belongs_to :blog 
    belongs_to :reader 
end 

我想現在要做的,就是添加讀者不同的博客。但是,條件是我只能將一個讀者添加到博客ONCE。因此BlogsReaders表中不得有任何重複項(readerID,相同blogID)。我怎樣才能做到這一點?

第二個問題是,我如何獲得讀者未訂閱的博客列表(例如填充下拉選擇列表,然後可以將讀者添加到另一個博客) ?

回答

5

什麼:

Blog.find(:all, 
      :conditions => ['id NOT IN (?)', the_reader.blog_ids]) 

Rails的負責IDS的收集我們與關聯方法! :)它內建到Rails

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

+0

此外,我想提到這可能是更好的方法,因爲接受的答案選擇行中的所有數據(例如the_reader.blogs),而我的答案只選擇行中的id(例如the_reader。 blog_ids)。這是一個很大的表現! – 2008-11-25 15:20:10

32

這應該把你的第一個問題的護理:

class BlogsReaders < ActiveRecord::Base 
    belongs_to :blog 
    belongs_to :reader 

    validates_uniqueness_of :reader_id, :scope => :blog_id 
end 
+0

我一直在試圖弄清楚這一點很長一段時間了,這我從來就沒想到!好的解決方案謝謝! – Arel 2013-09-11 16:29:17

+1

請仔細閱讀有關併發性和完整性的信息http://apidock.com/rails/ActiveRecord/Validations/ClassMethods/validates_uniqueness_of – 2016-11-11 20:28:26

1

我想會有人來一起比這更好的答案。

the_reader = Reader.find(:first, :include => :blogs) 

Blog.find(:all, 
      :conditions => ['id NOT IN (?)', the_reader.blogs.map(&:id)]) 

[編輯]

請參考下面喬希的答案。這是要走的路。 (我知道有出有更好的辦法;)

+0

您也可以使用find_by_sql在一條語句中執行此操作。 – 2008-11-25 01:01:28

+0

太棒了!這完美的作品!非常感謝!! – Sebastian 2008-11-25 07:47:04

69

簡單的解決辦法:

class Blog < ActiveRecord::Base 
    has_many :blogs_readers, :dependent => :destroy 
    has_many :readers, :through => :blogs_readers, :uniq => true 
    end 

    class Reader < ActiveRecord::Base 
    has_many :blogs_readers, :dependent => :destroy 
    has_many :blogs, :through => :blogs_readers, :uniq => true 
    end 

    class BlogsReaders < ActiveRecord::Base 
     belongs_to :blog 
     belongs_to :reader 
    end 

注意添加:uniq => true選項的has_many通話。

另外你也可能想在Blog和Reader之間考慮has_and_belongs_to_many,除非你有一些其他的屬性,你想在連接模型上(你目前沒有)。該方法也有一個:uniq opiton。

請注意,這並不妨礙您在表中創建條目,但它確實可以確保在查詢集合時,您只能獲得每個對象中的一個。

更新

在Rails 4做是通過範圍塊的方式。以上更改爲。

class Blog < ActiveRecord::Base 
has_many :blogs_readers, dependent: :destroy 
has_many :readers, -> { uniq }, through: :blogs_readers 
end 

class Reader < ActiveRecord::Base 
has_many :blogs_readers, dependent: :destroy 
has_many :blogs, -> { uniq }, through: :blogs_readers 
end 

class BlogsReaders < ActiveRecord::Base 
    belongs_to :blog 
    belongs_to :reader 
end 
0

最簡單方法是序列化的關係到一個數組:

class Blog < ActiveRecord::Base 
    has_many :blogs_readers, :dependent => :destroy 
    has_many :readers, :through => :blogs_readers 
    serialize :reader_ids, Array 
end 

然後,以饗讀者賦值時,您將它們作爲

blog.reader_ids = [1,2,3,4] 

以這種方式分配關係時,會自動刪除重複項。

14

Rails的5.1方式

class Blog < ActiveRecord::Base 
has_many :blogs_readers, dependent: :destroy 
has_many :readers, -> { distinct }, through: :blogs_readers 
end 

class Reader < ActiveRecord::Base 
has_many :blogs_readers, dependent: :destroy 
has_many :blogs, -> { distinct }, through: :blogs_readers 
end 

class BlogsReaders < ActiveRecord::Base 
    belongs_to :blog 
    belongs_to :reader 
end 
0

頂端回答目前表示使用uniq在proc:

class Blog < ActiveRecord::Base 
has_many :blogs_readers, dependent: :destroy 
has_many :readers, -> { uniq }, through: :blogs_readers 
end 

然而,這踢的關係到一個數組,可以打破的東西都是期望在關係上執行操作,而不是數組。

如果使用distinct它保持它作爲一個關係:

class Blog < ActiveRecord::Base 
has_many :blogs_readers, dependent: :destroy 
has_many :readers, -> { distinct }, through: :blogs_readers 
end