我有以下型号:
class Location < ActiveRecord::Base
has_many :location_items
has_many :items, :through=>:location_items
end
class Item < ActiveRecord::Base
has_many :location_items
has_many :locations, :through=>:location_items
end
class LocationItem < ActiveRecord::Base
belongs_to :item
belongs_to :location
end
此外,我还为项目模型启用了全文搜索(从gem),我可以Item.search('keyword')--'search'是gem提供的一个范围,用于获取名称或描述与关键字匹配的所有项目,结果项目添加了匹配相关性的'rank'属性
我还为位置模型启用了地理搜索(来自gem),我可以Location.near('Toronto.ON',100)---"near"是gem提供的一个范围,用于获取距离多伦多100公里内的所有位置,结果位置添加了一个"distance"属性,表示与给定位置的距离-本例中为多伦多
所以现在我要做的是得到一个location_item对象的列表,这些对象的位置与特定的给定位置匹配,项目与给定的关键字匹配。例如,搜索与"关键字"匹配且距离多伦多100公里以内的location_item对象。
如何使用一个查询实现这一点?并且还可以通过location_ item对象内的相关项目和位置来访问距离和等级属性。
我似乎无法链接范围,因为他们只处理项目和位置,而不是LocationItem、
例如,下面的表达式不适用于
LocationItem.joins(:items,locations).search('keyword').near('Toronto,ON',100)
希望我对我正在努力做的事情的描述有意义。你知道吗?非常感谢!
基本上,您将无法在一个查询中完成所有您想做的事情,并保留您要查找的正常LocationItem#位置和LocationItem#item接口。我假设您使用的是Postgres的全文搜索,因为如果您使用Solr或Sphinx**,这个问题就没有意义了。
如果您想要一个查询,但不介意放弃返回元素的belongs_to接口:如果提供了查询的SELECT部分,ActiveRecord::Base会自动从中分配属性,比如:Location.select('id+1 as more_id').first.more_id #=> 2
,这样您就可以利用它,并创建具有location和item、item_rank和location_dist适当部分的属性。
class LocationItem < ActiveRecord::Base
#This presumes that your geo and search gems actually return scopes that
# properly respond to to_sql (which they should if you're using rails 3).
def self.local_matching_items(text, dist=100)
LocationItem
.joins("INNER JOIN #{Item.search(text).to_sql} as matching_items
on matching_items.id
= location_items.item_id")
.joins("INNER JOIN #{Location.near(dist).to_sql} as nearby_locations
on nearby_locations.id
= location_items.location_id")
.select("location_items.id, nearby_locations.distance, matching_items.rank,
nearby_locations.other_field_you_might_want as
location_other_field_you_might_want,
matching_items.name as item_name, etc")
#returns LocationItems with #id, #distance, #rank,
# location_other_field_you_might_want, #item_name, etc
#It might be most helpful to distinguish between these
# and normal location_item's by storing them in variables with a
# different naming convention like nearby_item_matches.
end
end
*因为那时你要做两个查询,一个通过搜索提供商匹配关键词,另一个从数据库获取记录。
**如果你使用的是ThinkingSphinx,它已经支持按地理距离搜索,但你必须以不同的方式定义索引,并以不同的方法调用LocationItem#search。