рельсы named_scope игнорирует нетерпеливую загрузку - PullRequest
2 голосов
/ 14 июня 2010

Две модели (Rails 2.3.8):

  • Пользователь;имя пользователя и отключенные свойства;Пользователь has_one: профиль
  • Профиль;полное_имя & скрытые свойства

Я пытаюсь создать named_scope, в котором исключены отключенные = 1 и скрытые = 1 профили пользователей.Модель User обычно используется в сочетании с моделью Profile, поэтому я пытаюсь загрузить модель Profile (: include =>: profile).

Я создал named_scope в модели User с именем 'visible':

named_scope :visible, {
  :joins => "INNER JOIN profiles ON users.id=profiles.user_id",
  :conditions => ["users.disabled = ? AND profiles.hidden = ?", false, false]
}

Я заметил, что когда я использую named_scope в запросе, инструкция быстрой загрузки игнорируется.

Вариация 1 - только модель пользователя:

 # UserController
 @users = User.find(:all)

 # User's Index view
 <% for user in @users %>
  <p><%= user.username %></p>
 <% end %>

 # generates a single query:
 SELECT * FROM `users`

Вариант 2 - использовать модель профиля в поле зрения;ленивая нагрузка Модель профиля

 # UserController
 @users = User.find(:all)

 # User's Index view
 <% for user in @users %>
  <p><%= user.username %></p>
  <p><%= user.profile.full_name %></p>
 <% end %>

 # generates multiple queries:
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 1) ORDER BY full_name ASC LIMIT 1
  SHOW FIELDS FROM `profiles`
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 2) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 3) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 5) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 6) ORDER BY full_name ASC LIMIT 1

Вариация 3 - готовая загрузка Модель профиля

  # UserController
  @users = User.find(:all, :include => :profile)

  #view; no changes

  # two queries
  SELECT * FROM `users` 
  SELECT `profiles`.* FROM `profiles` WHERE (`profiles`.user_id IN (1,2,3,4,5,6)) 

Вариация 4 - используйте name_scope, включая инструкцию по загрузке

  #UserConroller
  @users = User.visible(:include => :profile)

  #view; no changes

  # generates multiple queries
  SELECT `users`.* FROM `users` INNER JOIN profiles ON users.id=profiles.user_id WHERE (users.disabled = 0 AND profiles.hidden = 0) 
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 1) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 2) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 3) ORDER BY full_name ASC LIMIT 1
  SELECT * FROM `profiles` WHERE (`profiles`.user_id = 4) ORDER BY full_name ASC LIMIT 1

Вариация4 возвращает правильное количество записей, но также, похоже, игнорирует инструкцию по быстрой загрузке.

Это проблема с кросс-модельными именованными областями?Возможно, я не правильно его использую.

Лучше ли такая ситуация обрабатывается Rails 3?

Ответы [ 2 ]

4 голосов
/ 14 июня 2010

С railsapi.com :

Стремительная загрузка ассоциаций

[...] Поскольку загружена только одна таблицаодновременно условия или заказы не могут ссылаться на таблицы, отличные от основной .В этом случае Active Record возвращается к ранее использовавшейся стратегии на основе LEFT OUTER JOIN.Например,

Post.find(:all, :include => [ :author, :comments ], :conditions => ['comments.approved = ?', true])

приведет к одному SQL-запросу с объединениями в виде строк: LEFT OUTER JOIN comments ON comments.post_id = posts.id и LEFT OUTER JOIN авторов на авторов.id = posts.author_id.

Я полагаю, что это отвечает на ваш вопрос ... в "Варианте № 4" нет большой нагрузки, потому что вы ссылаетесь на таблицу profiles в своей named_scope.

0 голосов
/ 28 сентября 2011

Я полагаю, что следующее может дать вам то, что вы ищете:

@users = User.visible.scoped(:include => :profile)

Это помогло мне, но я не объединяюсь с другими таблицами в определениимоей именованной области.

Джим Бентон предлагает элегантный способ добавить это в ActiveRecord в своем блоге: http://autonomousmachine.com/posts/2009/10/28/add-a-scope-for-easier-eager-loading

...