【问题标题】:Rails 3 multiple model queryRails 3 多模型查询
【发布时间】:2011-05-30 16:28:05
【问题描述】:

我有以下模型:

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 对象。

如何使用 one 查询来实现这一点?并且还可以通过 location_item 对象中的关联项目和位置访问距离和排名属性。

我似乎无法链接范围,因为它们仅适用于 Item 和 Location,而不适用于 LocationItem,

例如,下面的表达式不起作用

LocationItem.joins(:items, locations).search('keyword').near('Toronto, ON', 100)

希望我对我正在尝试做的事情的描述是有意义的。你有什么主意吗?非常感谢!

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3 activerecord join model


    【解决方案1】:

    基本上,您将无法在一个查询中完成您想做的所有事情并保留您正在寻找的正常 LocationItem#location 和 LocationItem#item 界面。我将假设您使用的是 Postgres 的全文搜索,因为如果您使用的是 Solr 或 Sphinx**,这个问题就没有意义*。

    如果你想要一个查询,但不介意放弃返回元素的 belongs_to 接口:ActiveRecord::Base 自动从查询的 SELECT 部分(如果提供)分配属性,如下所示:@ 987654322@ 这样您就可以利用它来发挥自己的优势,并创建具有 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,它已经支持 searching by geographical distance,但您必须以不同方式定义索引并以不同方式调用 LocationItem#search。

    【讨论】:

    • 感谢 Tim 的回复、示例代码和您的时间。这正是我正在寻找的。在我尝试之后,我发现似乎我需要在加入'INNER JOIN'之后添加才能使查询工作。比如:LocationItem.joins("INNER JOIN (#{Item.search(keyword).to_sql}) as matching_items on matching_items.id = location_items.item_id")
    • 哦,谢谢,我忘记了那部分。答案现已更新。很高兴能提供帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-08
    • 1970-01-01
    相关资源
    最近更新 更多