Rails:如何判断一条记录在其子表中是否有子记录?

abe*_*ger 9 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 Widget < ActiveRecord::Base
  belongs_to :foo
end
Run Code Online (Sandbox Code Playgroud)

有一种简单的方法让我检查给定的Foo是否在一个或多个表中有子记录?基本上,有更好的方法来做到这一点:

if !foo.things.empty? or !foo.items.empty? or !foo.widgets.empty?
  puts "This foo is in use!"
emd
Run Code Online (Sandbox Code Playgroud)

Abr*_*ram 8

嗯,我认为你走的是正确的轨道,但也许只是把它作为你的Foo模型中的一种方法

class Foo < ActiveRecord::Base
  def children?
    things.any? || items.any? || widgets.any?
  end
end
Run Code Online (Sandbox Code Playgroud)

然后只是说,Foo.first.children?并获得true当富实例有任何孩子.


var*_*tis 6

any?是为了什么.

class Foo < ActiveRecord::Base
  def children?
    things.any? || items.any? || widgets.any?
  end
end
Run Code Online (Sandbox Code Playgroud)

由于这已成为争论的话题,我向您呈现:

> foo = Foo.last
Foo Load (0.6ms)  SELECT "foos"......
> foo.items
Item Load (0.9ms)  SELECT "items".*.......
> foo.items.any?
=> true #OH, WHAT's that? NO SQL CALLS? GEE WILLICKERS
> foo.items.exists?
Item Exists (0.5ms) #Hmmmmmm....
=> true
Run Code Online (Sandbox Code Playgroud)

这里的要点是,在任何情况下,如果总是加载到内存中,exists则进行数据库调用,any?而不进行数组调用spaces.正如我所说,很多时候,重要的不是数据库调用的效率(AND YES,SQL调用exists?使效率更高),但事实上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>
Run Code Online (Sandbox Code Playgroud)

有关更简洁的时间,请查看以下内容:

> Benchmark.measure { 1000.times {foo.items.exists?} }.total
=> 2.5299999999999994
> Benchmark.measure { 1000.times {foo.items.any?} }.total
=> 0.0
Run Code Online (Sandbox Code Playgroud)

就像我说的那样,很多时候,它取决于环境 - 你可能有很多情况下这些物品没有加载到内存中,但很多时候,它们都是.根据您的调用方式,选择最适合您的方法.


dep*_*epa 5

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

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
Run Code Online (Sandbox Code Playgroud)