Сортировать запрос на основе связи 2 или более уровней - PullRequest
6 голосов
/ 03 августа 2011

У меня есть следующие модели

class Post < ActiveRecord::Base
  belongs_to :user, :counter_cache => true
  belongs_to :subtopic      
end


class Subtopic < ActiveRecord::Base
  belongs_to :category
  has_many :posts, :dependent => :destroy
end

class Category < ActiveRecord::Base
  has_many :posts, :through => :subtopics
  has_many :subtopics, :dependent => :destroy
end

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

  • атрибуты поста
    • название подтемы
      • название категории

Я хочу, чтобы в столбце «Категория» таблицы можно было кликать, чтобы я мог отображать все сообщения, отсортированные по их категориям. К сожалению, когда я создаю часть запроса "order by", я не могу заставить что-либо работать для имени категории. Я могу пройти один уровень глубоко с

@posts = Post.includes(:user, :subtopic => :category).paginate(:page =>1, :order => 'subtopics.name ASC')

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

@posts = Post.includes(:user, :subtopic => :category).paginate(:page =>1, :order => 'subtopic.categories.name ASC')

Я получаю PGError: ERROR: schema "subtopic" does not exist. Плюрализм подтемы дает ту же ошибку. Я чувствую, что упускаю что-то очевидное. Кто-нибудь может указать на это?

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


ОБНОВЛЕНИЕ 8/3 : ActiveRecord или PostgreSQL вызывает другую ошибку в действии контроллера. Следующий оператор действителен в консоли базы данных:
SELECT * from "posts" LEFT OUTER JOIN "users" ON "users"."id" = "posts"."user_id" LEFT OUTER JOIN "subtopics" ON "subtopics"."id" = "posts"."subtopic_id" LEFT OUTER JOIN "categories" ON "categories"."id" = "subtopics"."category_id" ORDER BY categories.name ASC LIMIT 30;

Выражение SQL выше приблизительно , что сгенерировано из выражения ниже. Приведенный ниже код направляющих действителен в rails console, но не в действии моего контроллера для Post#index

 @posts = Post.includes(:user, :subtopic => :category).paginate(:page =>1, :order => 'categories.category_name ASC', :conditions => ["posts.flags_count < ?", Flag.flag_threshold] )

Ошибка: https://gist.github.com/1124135

Эта ошибка возникает для :order => 'categories. ...' и :order => 'subtopics. ...', но не для :order => (column in posts). Это похоже на проблему с оператором JOIN, который генерирует ActiveRecord, но фактический оператор SQL выглядит так, как будто он должен работать для меня.


Обновление 8/4 : Когда я включаю ведение журнала SQL в своей среде (используя сценарий оболочки ), я вижу, что запросы SQL, которые ActiveRecord генерирует в rails console и (контроллер в) rails server разные.

В частности, на сервере AR добавляет к столбцам столбец 'post.', Например posts.users.display_name вместо users.display_name. Это происходит только на сервере , и только когда я включаю в запрос :order => (non-posts column) ASC/DESC

1 Ответ

4 голосов
/ 04 августа 2011

Строка в вашем предложении order вставляется в результирующий SQL в значительной степени как есть. Таким образом, результирующий запрос выглядит примерно так:

Select...order by subtopic.categories.name ASC

И база данных не знает, что это значит. Вы хотите сделать заказ по 'category.name ASC'.

ОБНОВЛЕНИЕ : Хорошо, теперь will_paginate задыхается от объединения. Я бы сделал что-то вроде этого:

@posts = Post.includes(:user, :subtopic => :category).where(["posts.flags_count < ?", Flag.flag_threshold]).order('categories.category_name ASC').paginate(:page =>1)

Это должно помочь вам. Далее я бы очистил свой контроллер, переместив все эти искатели в модель, вероятно, в виде области с именем «by_category_order» или чего-то еще. Тогда мой код контроллера будет красивым и похожим на:

@posts = Post.by_category_order.paginate(:page => params[:page])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...