我有2个这样的模型:
class Country < ActiveRecord::Base
has_many :cities
end
class City < ActiveRecord::Base
belongs_to :country
scope :big, where("population > 1000000")
end
然后,在代码中我加载一个带有城市的国家,如下:
country = Country.include(:cities).find(id)
但是当我执行时:
country.cities.big
使用此查询命中数据库:
SELECT * FROM cities where country_id = 1 AND population > 1000000
哪种方法很好,但是由于所有已经加载的城市都包含在内,因此没有必要。 如果关联已经加载,有没有办法告诉范围没有命中db?
我可以使用关联扩展来实现,但不适用于常规范围。在扩展上我做了类似的事情:
has_many :cities do
def big
if loaded?
detect {|city| city.population > 1000000}
else
where("population > 1000000")
end
end
end
但这会在2个地方重复范围,我想在城市模型上重复使用范围。
答案 0 :(得分:1)
范围逻辑使用了与Arel一起使用的方法,并且ruby Enumerables不知道如何使用它们。您可以将逻辑重构为可以转换为使用Arel或Enumerable方法的抽象,但这并不总是可行的:
def self.build_scope(abstracted)
where(abstracted.map(&:to_s).join(' '))
end
def self.build_enum(abstracted)
select{|city| city.send(abstracted[0]).send(*abstracted[1..2]) }
end
def self.abstract_big
[:population, ">", 10000]
end
scope :big_scope, build_scope(abstract_big)
def self.big_enum
build_enum abstract_big
end
然后你可以这样做:
country.cities.big_enum
更好的想法是只根据你想要的范围急切加载(如果你事先知道的话):
country = Country.include(:cities).merge(City.big).find(id)