我想让我的代码块更有效率。我有两个模型和一个连接表。他们都有has_many :through
的关系。有些部分属于多个组,有些只属于一个。我需要以最有效的方式获取属于 一个组的记录,因为有数千个部分。这是我的模特:
part.rb
class Part < ActiveRecord::Base
attr_accessible :name,
:group_ids
has_many :part_groups, dependent: :destroy
has_many :groups, through: :part_groups, select: 'groups.*, part_groups.*'
end
group.rb
class Group < ActiveRecord::Base
attr_accessible :name,
:part_ids
has_many :part_groups, dependent: :destroy
has_many :parts, through: :part_groups, select: 'parts.*, part_groups.*'
end
part_group.rb
class PartGroup < ActiveRecord::Base
attr_accessible :part_id,
:group_id
belongs_to :part
belongs_to :group
end
我希望能够获得的所有部分仅属于Group A
且仅属于Group B
,而不是属于A&amp; A的所有部分。 B.经过几个小时的挣扎并无处可去之后,我将其用作止损:
@groupA = []
@groupB = []
Part.all.each do |part|
if part.group_ids.length == 1
if part.group_ids.first == 1
@groupA.push(part)
elsif part.group_ids.first == 2
@groupB.push(part)
end
end
end
这显然不具备可扩展性,因为会有很多团体。我尝试过各种join
和include
的方法,我一直在谷歌上搜索,但到目前为止还没有任何工作。
答案 0 :(得分:0)
我也是rails的新手,所以据我所知,这是你桌子的结构。
部分
Id | Name
基
Id | Name
<强> part_groups 强>
Id | part_id | group_id
所以你可以做到以下几点,
Group.find(1).parts // Parts belong to group A
Group.find(2).parts // Parts belong to group B
所以这可能会给出属于其他组的部分。 目标是获得仅属于A组的零件,仅属于B组
尝试
Group.find(1).parts.collect{|row| row if row.groups.count==1}.flatten
我认为这比你的方法更好,因为我只遍历那些属于group1的部分。
答案 1 :(得分:0)
这个原始sql看起来像
select parts.* from parts
inner join part_groups on parts.id = part_groups.part_id
left outer join part_groups as group_b on group_b.part_id = parts.id and group_b.group_id = 456
where group_b.id is null and part_groups.group_id = 123
假设组a的id为123,组b的id为456。
这样做是尝试连接part_groups表两次(因此需要第二次使用别名),一旦group_id匹配组A,一次匹配组B.使用左连接允许我们要求第二个连接(对B)不产生任何行。
Activerecord没有为此提供太多帮助,除了允许您将任意sql片段传递给joins
之外,所以你最终会得到像
Part.select("parts.*").
.joins(:part_groups).
.joins("left outer join part_groups as group_b on group_b.group_id = #{groupb.id} and group_b.part_id = parts.id").
.where(:part_groups => {:group_id => groupa.id}).where("group_b.id is null")
Arel(支持活动记录的查询生成部分)可以生成此类查询,但不会直接公开。