2008-11-24 41 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