如何让Parent-Child-Parent范围保持在Parent之内?

时间:2014-05-01 14:30:58

标签: ruby-on-rails ruby activerecord ruby-on-rails-4

我有模特爸爸,妈妈和小孩。我的妈妈有一个名为is_online的布尔属性。现在我正在做一个这样的分页链:

def show
  @dad = Dad.find(params[:dad_id])
  @kids =  @dad.kids.online.paginate(:page => params[:page])
end

请允许我查看爸爸妈妈在线的孩子名单。

我的模型设置如下:

class Kid < ActiveRecord::Base
  belongs_to :dad
  belongs_to :mom

  scope :online, joins(:mom).where("moms.is_online = ?", true)
end

class Dad < ActiveRecord::Base
  has_many :kids
end

class Mom < ActiveRecord::Base
  has_many :kids
end

我遇到的问题是,这并没有让这个爸爸的孩子和在线妈妈一起回来,而是回归所有爸爸。如何才能使范围正确?

修改

SELECT DISTINCT "kids"."dad_id" FROM "kids"
 => [14, 25, 27, 8, 12, 17, 28, 1, 15, 10, 26, 11, 4, 18, 30, 16, 6, 19, 29, 2, 21, 3, 23, 31, 20, 5, 13, 22, 9, 7, 24]

Kid Load (1.5ms)  SELECT "kids".* FROM "kids" INNER JOIN "moms" ON "moms"."id" = "kids"."mom_id" WHERE (moms.is_online = 't')
 => #<ActiveRecord::Relation [
 #<Kid id: 7, dad_id: 1, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 21, dad_id: 2, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 35, dad_id: 3, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 49, dad_id: 4, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 63, dad_id: 5, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 77, dad_id: 6, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 91, dad_id: 7, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 105, dad_id: 8, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 119, dad_id: 9, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, 
 #<Kid id: 133, dad_id: 10, mom_id: 5, created_at: "2014-04-28 16:10:48", updated_at: "2014-04-28 16:10:48">, ...]> 

3 个答案:

答案 0 :(得分:3)

修改

正如 @KirtiThorat 所提到的,OP的范围方法无效的真正的原因是由于Rails 4的发布导致ActiveRecord范围定义发生了变化具体来说,根据upgrading Rails guide

  

Rails 4.0要求范围使用可调用对象,例如Proc或lambda

考虑到这一点,只需重新定义lambda中的:online范围定义就可以解决问题:

scope :online, -> {joins(:mom).where("mom.is_online = ?", true)}

原始回答:

您最好的选择是使用merge方法:

def show
 @dad = Dad.find(params[:dad_id])
 @kids = @dad.kids.merge(Kid.online)
end

由于ActiveRecord文档定义merge

  

合并other公开
  如果other是ActiveRecord :: Relation,则合并来自other的条件。如果other是数组,则返回表示结果记录与<{1}}的交集的数组。

因此,由于other找到两个数组的交集,在这种情况下,merge的孩子和@dad的数组在线Kid s ,这将产生包含Mom作为Kid的所有@dadDad Mom的数组。

也很高兴知道也可以使用数组交集速记方法is_online

&

答案 1 :(得分:3)

更改您的scope,如下所示:

scope :online, -> { joins(:mom).where("moms.is_online = ?", true) }

不知何故,在Rails 4中,您的范围online未被链接到使用@dad.kids形成的查询。以上是定义 Scope in Rails 4

的正确方法

答案 2 :(得分:1)

我不确定它是否会起作用,但您可以尝试以下方法::

class Dad < ActiveRecord::Base
  has_many :kids
  has_many :kids_with_online_mom, class_name: `Kid`, through: :mom,  joins(:mom).where("moms.is_online = ?", true)
end

如果有效,只需@dad.kids_with_online_mom,您就可以获得所需的输出。