Rails 3多模型查询



我有以下型号:

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。

相关内容

  • 没有找到相关文章

最新更新