Rails 3 множественный модельный запрос - PullRequest
4 голосов
/ 30 мая 2011

У меня есть модели ниже:

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 ('keyword') - 'search' - это область действия, предоставляемая гемом для получения всех элементов с ключевым словом, совпадающим с именем или описанием, к результату добавляется атрибут 'rank' для релевантности соответствия

У меня также есть гео-поиск (из драгоценного камня) для модели местоположения, я могу сделать Location.near ('Toronto. ON', 100) --- 'near' - это область действия, предоставляемая гемом, чтобы получить все местоположения в пределах 100 км от Торонто, в результирующее местоположение добавляется атрибут 'distance' для расстояния от заданного местоположение - Торонто в этом примере

Итак, теперь я пытаюсь получить список объектов location_item, местоположение которых соответствует определенному данному местоположению, а элемент соответствует данному ключевому слову. Например, выполните поиск объектов location_item, соответствующих «ключевому слову», в пределах 100 км от Торонто.

Как мне добиться этого с помощью одного запроса? а также может иметь доступ к атрибутам расстояния и ранга через связанный элемент и местоположение внутри объекта location_item.

Я не могу связать область видимости, поскольку они работают только с Item и Location, а не с LocationItem,

Например, приведенное ниже выражение не будет работать

LocationItem.joins (: элементы, местоположения) .search ('ключевое слово'). Рядом ('Торонто, ON', 100)

Надеюсь, мое описание того, что я пытаюсь сделать, имеет смысл. Есть ли у вас какие-либо идеи? Большое спасибо!

1 Ответ

2 голосов
/ 30 мая 2011

По сути, вы не сможете делать все, что хотите, в одном запросе И сохранять обычный интерфейс LocationItem # location и LocationItem # item, который вы ищете.Я собираюсь предположить, что вы используете полнотекстовый поиск Postgres, потому что вопрос не имеет смысла *, если вы используете Solr или Sphinx **.

Если вы хотите один запрос, ноне возражаете отказаться от интерфейса принадлежащих вам возвращаемых элементов: ActiveRecord :: Base автоматически назначает атрибуты из того, какой была часть запроса SELECT, если она была предоставлена, например: 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 #искать по-другому.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...