Rails 3 - Стремительная загрузка с условиями - PullRequest
10 голосов
/ 16 ноября 2010

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

Category.rb:

belongs_to :parent, :class_name => "Category", :foreign_key => "parent_id"
has_many   :children, :class_name => "Category", :foreign_key => "parent_id"
has_many :pages, :documents, :galleries

Page.rb

belongs_to :category

Модель страницы также имеет: is_published, поэтому я тоже пытаюсь отфильтровать это. Я не хочу публиковать свои слабые попытки запроса, но не вижу другого решения, кроме как умолять намного умнее людей:

(self - @current_website)

self.categories.includes(:children, :pages).where('pages.is_published = 1')

Это возвращает в основном то, что мне нужно, но не родительские категории без опубликованных страниц. Например, это прекрасно работает, если у меня есть:

Parent Category
- Published Page
- Child Category
-- Published Page

Где это терпит неудачу, когда у меня нет опубликованных страниц в родительском, как это:

Parent Category
- Child Category
-- Published Page
- Child Category
-- Published Page

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

ОБНОВЛЕНИЕ: Реализация предложения Кандада Боггу дала гораздо лучшие результаты, это было добавлено в Category.rb

  has_many :published_pages, :class_name => "Page",
                             :conditions => {:is_published => true}

Однако при использовании следующего:

self.categories.where(:parent_id => nil).includes({:children => :published_pages},
                                                   :published_pages)

Я получаю результаты, которые мне нужны, но я также получаю пустые Родительские категории (нет опубликованных_страниц, дочерних категорий с опубликованными страницами. Пример:

- Parent Category
-- Published Page
- Parent Category
-- NOTHING

Мое временное исправление заключалось в добавлении запроса с помощью:

reject{|category| category.pages.empty? && category.children.empty?}

Еще раз спасибо за вашу помощь.

1 Ответ

14 голосов
/ 17 ноября 2010

Добавьте новую ассоциацию с именем published_pages (кроме ваших текущих ассоциаций)

class Category

  has_many   :children,        :class_name => "Category", 
               :foreign_key => "parent_id"
  has_many   :published_pages, :class_name => "Page", 
               :conditions  => { :is_published => true }

end

Теперь вы можете получить все категории следующим образом:

self.categories.includes(:children, :published_pages)

Если вы заинтересованычтобы узнать, почему ваш подход не сработал, прочитайте документацию Rails (прокрутите 10-15 строк после раздела Eager loading of associations).Ниже приведен соответствующий фрагмент кода:

Например,

Post.includes([:author, :comments]).where(['comments.approved = ?', true]).all

Это приведет к одному SQL-запросу с объединениями в виде строк:

LEFT OUTER JOIN comments ON comments.post_id = posts.id and 
LEFT OUTER JOIN authors  ON authors.id = posts.author_id. 

Обратите внимание, что использование таких условий может иметь непредвиденные последствия.В приведенном выше примере сообщения с одобренными комментариями вообще не возвращаются, поскольку условия применяются к оператору SQL в целом, а не только к ассоциации.Вы должны устранить неоднозначность ссылок на столбцы, чтобы этот запасной вариант имел место, например: order => «author.name DESC» будет работать, но: order => «name DESC» не будет.строки ассоциации, используйте ассоциацию с условиями:

class Post < ActiveRecord::Base
  has_many :approved_comments, :class_name => 'Comment', 
             :conditions => ['approved = ?', true]
end

Post.find(:all, :include => :approved_comments)
...