2011-05-30 82 views
4

我有以下型號: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 

另外我有一個完整的文本搜索(由創業板)啓用的項目模型,我可以做 Item.search(「關鍵字」) - 'search'是由gem提供的範圍,用於獲取所有具有名稱或說明匹配關鍵字的項目,結果項目添加了'rank'屬性以用於匹配的相關性

我還有Geo搜索(來自gem)啓用位置模型,我可以做 Location.near('Toronto。ON',100)---'near'是由寶石提供的範圍,用於獲取距離Tor 100公里內的所有位置結果位置添加距離給定位置的距離'距離'屬性 - 多倫多在這個例子中

所以現在我想要做的是獲得位置匹配某個給定位置的location_item對象的列表和項目匹配給定的關鍵字。 例如,搜索匹配「關鍵字」且位於多倫多100公里範圍內的location_item對象。

我該如何做到這一點查詢?並且還可以通過location_item對象內的相關項目和位置訪問距離和等級屬性。

我似乎無法對鏈,他們只對項目和地點工作的範圍,不LocationItem,

例如,下面的表達式將無法正常工作

LocationItem.joins(:項目, (''關鍵字')。near('Toronto,ON',100)

希望我對我所做的事情的描述很有意義。你有什麼主意嗎?非常感謝你!

回答

2

基本上,您將無法在一個查詢中完成所有您想要的操作,並保留您正在尋找的正常LocationItem#位置和LocationItem#項接口。我假設你正在使用Postgres的全文搜索,因爲如果你使用Solr或Sphinx **,這個問題沒有意義。

如果您想要一個查詢,但不介意放棄返回元素的belongs_to接口:ActiveRecord :: Base會自動從查詢的SELECT部分​​提供的屬性中分配屬性,如下所示: Location.select('id+1 as more_id').first.more_id #=> 2所以你可以使用它來創造你的優勢,並創建具有位置和項目以及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 

*因爲那麼你會做兩個查詢,一個用於通過搜索提供程序匹配關鍵字,一個用於從db獲取記錄。

**如果您正在使用ThinkingSphinx,它已經支持searching by geographical distance,但您必須以不同的方式定義您的索引並以不同的方式調用LocationItem#搜索。

+0

感謝蒂姆的回覆,示例代碼和你的時間。這正是我正在尋找的。在我嘗試之後,發現似乎我需要在連接'INNER JOIN'後添加以使查詢工作。例如:LocationItem.joins(「INNER JOIN(#{Item.search(keyword).to_sql}) as matching_items on matching_items.id = location_items.item_id」) – gifkins 2011-06-01 02:33:37

+0

哦,謝謝,我已經忘記了那部分。答案現在已更新。樂意效勞。 – 2011-06-01 20:57:38