рельсы выбрать и включить - PullRequest
16 голосов
/ 13 ноября 2010

Может кто-нибудь объяснить это?

Project.includes([:user, :company])

Выполняется 3 запроса: один для извлечения проектов, один для извлечения пользователей для этих проектов и один для извлечения компаний.

Project.select("name").includes([:user, :company])

Выполняет 3 запроса и полностью игнорирует бит выбора.

Project.select("user.name").includes([:user, :company])

Выполняет 1 запрос с правильными левыми соединениями. И все же полностью игнорирует выбор.

Мне кажется, что rails игнорирует select с include. Хорошо, хорошо, но почему, когда я помещаю связанную модель в select, она переключается с выдачи 3 запросов на выдачу 1 запроса?

Обратите внимание, что 1 запрос - это то, что я хочу, я просто не могу представить, что это правильный способ получить его, и почему он работает, но я не уверен, как еще получить результаты в одном запросе (.joins Кажется, используется только INNER JOIN, которого я на самом деле не хочу, и когда я вручную задаю условия соединения для .joins, мы используем freaks для поиска, поскольку он пытается повторно добавить объединения с тем же именем).

Ответы [ 5 ]

25 голосов
/ 26 июля 2012

У меня была такая же проблема с select и include. Для быстрой загрузки связанных моделей я использовал собственную область Rails 'preload' http://apidock.com/rails/ActiveRecord/QueryMethods/preload Он обеспечивает активную загрузку без пропуска 'select' в цепочке областей действия.

Я нашел это здесь https://github.com/rails/rails/pull/2303#issuecomment-3889821

Надеюсь, этот совет будет полезен для кого-то, так как он был полезен для меня.

8 голосов
/ 20 ноября 2010

Хорошо, вот что я придумала ...

.joins("LEFT JOIN companies companies2 ON companies2.id = projects.company_id LEFT JOIN project_types project_types2 ON project_types2.id = projects.project_type_id LEFT JOIN users users2 ON users2.id = projects.user_id") \
.select("six, fields, I, want")

Работает, боль в заднице, но она получает только те данные, которые мне нужны в одном запросе. Единственная паршивая часть - я должен дать всем псевдоним model2, так как мы используем meta_search, который, кажется, не может выяснить, что таблица уже объединена, когда вы указываете свои собственные условия соединения.

2 голосов
/ 13 ноября 2010

Rails всегда игнорировал аргумент (ы) select при использовании include или includes. Если вы хотите использовать аргумент select, используйте вместо этого joins.

У вас могут быть проблемы с гемом запроса, о котором вы говорите, но вы также можете включить фрагменты sql, используя метод joins.

Project.select("name").joins(['some sql fragement for users', 'left join companies c on c.id = projects.company_id'])

Я не знаю вашу схему, поэтому мне придется угадывать точные отношения, но это должно помочь вам начать.

0 голосов
/ 09 апреля 2015

Я хотел эту функцию сам, поэтому, пожалуйста, используйте ее. Включите этот метод в ваш класс

# ПРИНИМАЕТ аргументы в строковом формате "ASSOCIATION_NAME: COLUMN_NAME-COLUMN_NAME"

def self.includes_with_select(*m)
    association_arr = []
    m.each do |part|
      parts = part.split(':')
      association = parts[0].to_sym
      select_columns = parts[1].split('-')
      association_macro = (self.reflect_on_association(association).macro)
      association_arr << association.to_sym
      class_name = self.reflect_on_association(association).class_name 
      self.send(association_macro, association, -> {select *select_columns}, class_name: "#{class_name.to_sym}")
    end
    self.includes(*association_arr)
  end

И вы сможете вызывать как: Contract.includes_with_select ('user: id-name-status', 'translation: valid-id'), и он выберет указанные столбцы.

0 голосов
/ 13 ноября 2010

Я мог бы что-то здесь упустить, но select и include не являются частью ActiveRecord.Обычный способ сделать то, что вы пытаетесь сделать, выглядит следующим образом:

Project.find(:all, :select => "users.name", :include => [:user, :company], :joins => "LEFT JOIN users on projects.user_id = users.id")

Посмотрите на документацию API для большего количества примеров.Иногда мне приходилось идти вручную и использовать find_by_sql:

Project.find_by_sql("select users.name from projects left join users on projects.user_id = users.id")

Надеюсь, это укажет вам правильное направление.

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