2010-06-13 3 views
2

Две модели (Rails 2.3.8):рельсы named_scope пренебрегает жадной загрузки

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

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

Я создал named_scope на модели пользователя с именем «видимым»:

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?

ответ

4

От railsapi.com:

Нетерпеливый загрузка ассоциаций

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

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

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

Я считаю, что это ответ на ваш вопрос ... нет жадной загрузки в «вариационных # 4», потому что вы ссылаетесь profiles таблицу на вашем named_scope.

+0

OK. Я мог бы переместить скрытый атрибут в модель User, чтобы вообще избежать этой ситуации, но, вероятно, лучше всего найти другой подход для такого типа ситуации. Можете ли вы подумать об одном? – craig

+1

Вы можете создать другую ассоциацию: 'Пользователь has_one: visible_profile'. Затем вы вызываете @ user.visible (: include =>: visible_profile), когда 'visible' является named_scope с только этим условием:' ["disabled =?", False] '. Это похоже на пример на railsapi.com. –

+0

@j: Я добавил ассоциацию к модели пользователя - has_one: visible_profile,: class_name => 'Profile',: conditions => ["profiles.hidden =?", False]. Изменено имя пользователя user_scope - named_scope: visible, { : условия => ["disabled =?", False] } Изменено действие индекса UserController - @users = User.visible (: all,: include =>: visible_profile) , Перезагруженный сервер. Ленивая загрузка все еще происходит. Фильтр модели профиля игнорируется. Мысли? – craig

0

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

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

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

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

 Смежные вопросы

  • Нет связанных вопросов^_^