Ruby on rails 3 Rails:如何判断一条记录在其任何一个子表中是否有子记录?

Ruby on rails 3 Rails:如何判断一条记录在其任何一个子表中是否有子记录?,ruby-on-rails-3,rails-activerecord,Ruby On Rails 3,Rails Activerecord,我在Rails 3中工作,有一个包含多个子表的表,例如 class Foo < ActiveRecord::Base has_many :things has_many :items has_many :widgets end class Thing < ActiveRecord::Base belongs_to :foo end class Item < ActiveRecord::Base belongs_to :foo end class Wid

我在Rails 3中工作,有一个包含多个子表的表,例如

class Foo < ActiveRecord::Base
  has_many :things
  has_many :items
  has_many :widgets
end

class Thing < ActiveRecord::Base
  belongs_to :foo
end

class Item < ActiveRecord::Base
  belongs_to :foo
end

class Widget < ActiveRecord::Base
  belongs_to :foo
end

好吧,我认为你的思路是对的,但也许只是把它作为一种方法放在你的Foo模型中

class Foo < ActiveRecord::Base
  def children?
    things.any? || items.any? || widgets.any?
  end
end
class Foo

然后只要说,
Foo.first.children?
并获得
true
,如果Foo实例有任何子实例。

您可以将Thing Item和Widget子类化。或者添加一个多态联接表来跟踪它。不太理想,我知道

你至少可以这样做,这样读起来会好一点

if foo.things.exists? || foo.items.exists? || foo.widgets.exists?
  puts "This foo is in use!"
end

“空的?”我相信是在幕后使用“存在的”。

这就是
any?
的用途

class Foo < ActiveRecord::Base
  def children?
    things.any? || items.any? || widgets.any?
  end
end
这里的要点是,在任何情况下,
存在
进行DB调用,如果总是将
空格
加载到内存中,则as
any?
不会进行调用。正如我说过的,很多时候,重要的不是DB调用的效率(是的,SQL调用
存在?
使得效率更高),而是
any?
不一定会调用DB,这是一个巨大的优势。寻找你自己:

[20] pry(main)> Benchmark.measure { foo.item.exists? }
  Item Exists (0.5ms)  SELECT 1 AS one FROM "items" ...
=> #<Benchmark::Tms:0x007fc1f28a8638
 @cstime=0.0,
 @cutime=0.0,
 @label="",
 @real=0.002927,
 @stime=0.0,
 @total=0.00999999999999801,
 @utime=0.00999999999999801>
[21] pry(main)> Benchmark.measure { foo.items.any? }
=> #<Benchmark::Tms:0x007fc1f29d1aa0
 @cstime=0.0,
 @cutime=0.0,
 @label="",
 @real=7.6e-05,
 @stime=0.0,
 @total=0.0,
 @utime=0.0>

正如我所说,很多时候,这取决于环境——在很多情况下,这些项目可能不会加载到内存中,但很多时候,它们会加载到内存中。根据您的调用方式选择最适合您的关联。

假设所有关联都加载到内存中:

class Foo < ActiveRecord::Base
  has_many :things
  has_many :items
  has_many :widgets

  def in_use?
    [things, items, widgets].flatten.any?
  end
end

更正确,并且已经在我之前提出。

这应该适用于任何给定的模型

class Foo < ActiveRecord::Base
  def children?
    has_associated_records = self.class.reflect_on_all_associations.map { |a| self.send(a.name).any? }
    has_associated_records.include?(true)
  end
end
class Foo
我会使用
any?
,因为
present?
有一组不必要的字符串空检查,而且也不必要地检查
[]
是否为
nil
。注意:
foo.things
将始终返回一个数组,尽管有时返回一个空数组。@veritas您仍然是错的-我认为您没有完全理解活动记录集合。他们并不是在所有情况下都急于加载。things不会总是返回数组。在任何情况下?还是存在?它不会加载ruby对象。任何是否计数并与比现有值慢的零进行比较?它只是在数据库中查找id。@Swards如果
foo.things
没有返回数组,则表明您的AR关系设置错误、直接且简单。我鼓励你看看我更新的答案。你只是不理解这里的一些东西,或者浏览我的答案,或者其他什么。看看我的答案,看看我是否真的完全正确。@veritas-这正是我要说的:foo.things在某些情况下不返回数组(例如在附加“.exists?”时)。你可以自己确认——这可能会改变你的答案。这与将作用域附加到集合的方式非常相似。是否存在?将选择“1”,是否有?将执行选择计数(*)。任何在我的测试中慢了一点。没那么快。如果将任何
事物
项目
小部件
加载到内存中,
存在?
仍会对其中每一项执行查询<代码>有吗?
没有。这取决于用例,但考虑到OP的问题,这些模型很可能会加载到内存中,因此
any?
将更有效。它们不会加载到内存中。但重要的是,您必须使用
exists?
对数据库进行>=1次调用,而使用
any?
,您可以进行潜在的0次调用,并且通常比
存在的次数要少得多(正如我所说,这取决于具体情况)。对数据库的调用比对内存的调用慢得多。“存在吗?”在mysql中生成一个sql“选择“1”,并测试是否找到任何结果“任何?”将执行“选择计数(*)”。它们都执行一个SQL调用和任何SQL调用?稍微慢一点。你自己试试。OP不会预加载收藏,然后测试是否存在。是的,我一直在说的。哦,nvm,我想你说的是
如果OP不会预加载…
。OP从未指定,它很可能会根据情况预加载。任何涉及
的内容都包括
语句等。
> Benchmark.measure { 1000.times {foo.items.exists?} }.total
=> 2.5299999999999994
> Benchmark.measure { 1000.times {foo.items.any?} }.total
=> 0.0
class Foo < ActiveRecord::Base
  has_many :things
  has_many :items
  has_many :widgets

  def in_use?
    [things, items, widgets].flatten.any?
  end
end
things.any? || items.any? || widgets.any?
class Foo < ActiveRecord::Base
  def children?
    has_associated_records = self.class.reflect_on_all_associations.map { |a| self.send(a.name).any? }
    has_associated_records.include?(true)
  end
end