Rails 4可以找到没有孩子的父母

Mat*_*att 34 ruby-on-rails rails-activerecord

我找到了一个答案,其中有一些可用的having例子可以找到有n孩子的父母,但同样不能用于找到没有孩子的父母(大概是因为连接不包括他们).

scope :with_children, joins(:children).group("child_join_table.parent_id").having("count(child_join_table.parent_id) > 0")
Run Code Online (Sandbox Code Playgroud)

谁能指出我正确的方向?

MrY*_*iji 67

这应该做你想要的工作:

Rails 3和4

scope :without_children, includes(:children).where(:children => { :id => nil })
Run Code Online (Sandbox Code Playgroud)

这里的最大区别是joins成为a includes:一个include加载所有关系,如果它们存在,则join将仅加载关联的对象并忽略没有关系的对象.

事实上,scope :with_children, joins(:children)应该足以让父母至少回到1个孩子.试试看!

Rails 5

请参阅下面的@ Anson的回答


正如@MauroDias所指出的,如果它是你父母和孩子之间的自我指涉关系,那么上面的代码将不起作用.

通过一些研究,我发现了如何做到这一点:

考虑这个模型:

class Item < ActiveRecord::Base
  has_many :children, :class_name => 'Item', :foreign_key => 'parent_id'
Run Code Online (Sandbox Code Playgroud)

如何返回没有孩子的所有项目(ren):

Item.includes(:children).where(children_items: { id: nil })
Run Code Online (Sandbox Code Playgroud)

我怎么找那张children_items桌子的?

Item.joins(:children) 生成以下SQL:

SELECT "items".* 
FROM "items" 
 INNER JOIN "items" "children_items" 
 ON "children_items"."parent_id" = "items"."id"
Run Code Online (Sandbox Code Playgroud)

所以我猜测Rails在自引用的情况下需要JOIN时使用表.


类似的问题:


Ans*_*son 21

@MrYoshiji有一个坚实的Rails 4答案,但是对于那些来到Rails 5的人来说,你有更多的选择.

使用Rails 5:

从Rails 5开始,您还可以使用left_outer_joins来避免加载关联.它是在拉取请求#12071中引入的.

scope :without_children, left_outer_joins(:children).where(children: { id: nil })
Run Code Online (Sandbox Code Playgroud)

对于有孩子的父母,MrYoshiji的Rails 4解决方案仍然可以使用:

scope :with_children, joins(:children)
Run Code Online (Sandbox Code Playgroud)

  • 我相信你需要把它包装起来,这样它就可以调用了。例如:`scope :with_children, -&gt; { joins(:children) }` (2认同)