我正在使用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是否在一个或多个表中有子记录?基本上,有更好的方法来做到这一点:
if !foo.things.empty? or !foo.items.empty? or !foo.widgets.empty?
puts "This foo is in use!"
emd
答案 0 :(得分:8)
嗯,我认为你走的是正确的轨道,但也许只是把它作为你的Foo模型中的一种方法
class Foo < ActiveRecord::Base
def children?
things.any? || items.any? || widgets.any?
end
end
然后如果Foo实例有任何子节点,只需说Foo.first.children?
并获取true
。
答案 1 :(得分:5)
这是any?
的用途。
class Foo < ActiveRecord::Base
def children?
things.any? || items.any? || widgets.any?
end
end
由于这已经成为争论的话题,我将向您呈现:
> 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
这里的要点是,在任何情况下,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>
有关更简洁的时间,请看:
> Benchmark.measure { 1000.times {foo.items.exists?} }.total
=> 2.5299999999999994
> Benchmark.measure { 1000.times {foo.items.any?} }.total
=> 0.0
正如我所说的那样,很多时候,这取决于环境 - 你可能有很多情况下这些物品没有加载到内存中,但很多时候,它们都是。根据您的调用方式,选择最适合您的方式。
答案 2 :(得分:3)
这适用于任何给定的模型。
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
答案 3 :(得分:0)
你可以继承Thing Item和Widget。或者添加多态联接表以跟踪它。我知道,这并不理想。
你至少可以这样做,所以它会读得更好。
if foo.things.exists? || foo.items.exists? || foo.widgets.exists?
puts "This foo is in use!"
end
“空?使用'存在?'在幕后,我相信。
答案 4 :(得分: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?
更正确,并已在我之前提出。
答案 5 :(得分:0)
@Marcelo De Polli 的答案是迄今为止发布的最概括的答案。 此答案是 Rails 5 的更新版本。
模型的父类在 Rails 5 及更高版本中是 ApplicationRecord
,它曾经是 ActiveRecord::Base
直到 Rails 4(注意,原始问题被标记为 Rails 3)。
为了代码的简单性,使用:
class Foo < ApplicationRecord
def children?
self.class.reflect_on_all_associations.map{ |a| self.send(a.name).any? }.any?
end
end
当一个模型可能有很多子类时,要追求更高的运行时效率,请使用:
class Foo < ApplicationRecord
def children?
self.class.reflect_on_all_associations.each{ |a| return true if self.send(a.name).any? }
false
end
end