我有一组通过ActiveRecord的对象,需要迭代它们以识别一组条件。
def get_smith_listings
Listing.joins(:spec).where('specs.broker ilike ?', '%smith%')
end
@listings = Listings.all #actually a built query
@listings.sort_by { |item| item.get_smith_listings? ? 0 : 1 }
=> EXPLAIN for: SELECT "listings".* FROM "listings" INNER JOIN "specs" ON "specs"."listing_id" = "listings"."id" WHERE (specs.agent ilike '%smith%')
QUERY PLAN
--------------------------------------------------------------------------------------
Nested Loop (cost=0.28..848.56 rows=1 width=668)
-> Seq Scan on specs (cost=0.00..840.25 rows=1 width=4)
Filter: ((agent)::text ~~* '%smith%'::text)
-> Index Scan using listings_pkey on listings (cost=0.28..8.30 rows=1 width=668)
Index Cond: (id = specs.listing_id)
(问题的性质已经略有改变,因为我已经对所需的方法进行了调整)
我无法以这样的方式构建它:a)我的方法被识别(对助手来说是新的)并设置查询以使用布尔值进行排序。
更新:为了寻求澄清,这是我试图解决这个问题的方向:https://www.mateoclarke.com/blog/2015/10/14/what-i-learned-boolean-ruby/
答案 0 :(得分:2)
Enumerable#partition这样做:它产生一个包含2个数组的数组。第一个包含块为true的所有项目,第二个包含falses。
答案 1 :(得分:1)
你可以这样做:
group = Listings.all.joins(:spec).where('specs.agent ilike ?', '%smith%') +
Listings.all.joins(:spec).where.not('specs.agent ilike ?', '%smith%')
所以它会先将组变量放在符合条件的组变量上,然后再将那些变量放在组变量上
编辑: 我不知道为什么你需要一个单独的方法来做到这一点(因为我之前展示的方式无论如何都会给你正确的顺序)。但是您在编辑时显示的语法存在问题:您正在尝试调用调用整个ActiveRecord方法的实例方法(与steenslag的答案相同)。如果你想按照你提出的方式行事,我认为这种方式应该更好:
#this method should be on Listing model
def get_smith_listings?
self.spec.broker.to_s.include?("smith")
end
@listings = Listings.includes(:spec).all #important to avoid n+1 queries
# here the 0 or 1 position will depende the true/false order you want
@listings.sort_by { |item| item.get_smith_listings? ? 0 : 1 }
我仍然不知道为什么你想这样做,并猜测那可能是一个更好的方式来做你想要的......但是现在我不能帮助更多。祝你好运!