如何避免重复在has_many:通过关系?
-
11-07-2019 - |
题
我怎么能实现以下?我有两个模型(博客和读者)和参加表,这将允许我有个N:M之间的关系:
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
什么我现在要做的,就是添加的读者不同的博客。条件,虽然是我可以仅仅增加一个读到博客一次。所以也不能被任何重复(一样 readerID
, ,同 blogID
)在 BlogsReaders
表。我如何可以实现这一目标?
第二个问题是,如何获得一个名单的博客的读者不是订阅已经(例如填写一下选择清单,然后可以用来增加读者的另一个博客)?
解决方案
约什么:
Blog.find(:all,
:conditions => ['id NOT IN (?)', the_reader.blog_ids])
Rails的负责IDS的收集我们与关联方法! :)
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ ClassMethods.html
其他提示
简单的解决方案,是内置到Rails:
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
呼叫。
此外,你可能要考虑has_and_belongs_to_many
博客和读者之间,除非你有你想对加盟模式的一些其他属性(你不这样做,目前)。该方法也有一个:uniq
opiton。
请注意,这并不妨碍你创建的表中的条目,但它确实保证当你查询集合你只有每个对象之一。
<强>更新强>
在轨道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
<强>更新为Rails 5 强>
在范围块的用途uniq
的将导致错误NoMethodError: undefined method 'extensions' for []:Array
。使用distinct
代替:
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
这应该把你的第一个问题的护理:
class BlogsReaders < ActiveRecord::Base
belongs_to :blog
belongs_to :reader
validates_uniqueness_of :reader_id, :scope => :blog_id
end
<强> 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
答案在这一链接表示了如何复盖"<<"方法来实现你在找什么没有提出例外情况或创建一个单独的方法: 轨成语,以避免重复在has_many:通过
我想有人会比这更好的答案一起去。
the_reader = Reader.find(:first, :include => :blogs)
Blog.find(:all,
:conditions => ['id NOT IN (?)', the_reader.blogs.map(&:id)])
[编辑]
请参见下面乔希的答案。这是要走的路。 (我知道有一种更好的方式在那里;)
在顶部答案目前说在proc使用uniq
:
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
最简单的方法是序列的关系到一个数组:
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]
当分配关系这种方式,重复被自动删除。