Rails 3.1 - Использование областей для поиска неподписанных студентов - PullRequest
1 голос
/ 07 октября 2011
# student.rb
has_and_belongs_to_many :courses

# course.rb
has_and_belongs_to_many :students

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

Лучшее, что я придумал, это:

scope :unenrolled, where(Student.courses.count => 0)

Но тогда я получаю сообщение об ошибке

неопределенный метод `курсы '

Кто-нибудь предлагает какие-либо предложения?

1 Ответ

5 голосов
/ 07 октября 2011

Хорошо, тогда. Итак, вот ваш код:

scope :unenrolled, where(Student.courses.count => 0)

Первая проблема здесь - это то, что вызывает ошибку: вы вызываете экземпляр метод courses для класса Student. Как следует из названия, вы можете вызывать метод экземпляра только для экземпляра класса, но не для самого класса. Например:

jim = Student.find(123)
jims_courses = jim.courses

Но вот что важно: когда вы вызываете scope, вы находитесь в контексте class , то есть код не находится внутри метода экземпляра, поэтому он вызывается при первом объявлении вашей модели. В то время экземпляра нет, поэтому вы не можете просто вызвать courses, как если бы вы были внутри одного из методов экземпляра Student.

Но это спорный вопрос, поскольку вы немного неправильно поняли, как работает where. Аргумент (ы), который вы указываете where, должен быть условиями , которые соответствуют тому, что вы бы поставили после WHERE в запросе SQL. Например, where(:eye_color => 'brown') будет преобразован в предложение SQL WHERE, например WHERE eye_color = 'brown'. :eye_color => 'brown' - это просто хэш с ключом :eye_color, значение которого 'brown'. Вызов функции в левой части => не имеет смысла, если функция не возвращает имя столбца / атрибута в вашей модели, которое ActiveRecord поймет.

Итак, теперь давайте выясним, что вы должны сделать. Если бы вы писали SQL-запрос, он бы выглядел примерно так:

SELECT `students`.*, COUNT(`courses_students`.*) AS `courses_count`
  FROM `students`
  JOIN `courses_students` ON `students`.`id` = `courses_students`.`student_id`
 WHERE `courses_count` = '0'
 GROUP BY `courses_students`.`student_id`;

Это примерно соответствует запросу ActiveRecord, например так: Student.joins (: курсы). // AR автоматически присоединяется courses хотя courses_students выберите («студенты. , COUNT (курсы. ) AS courses_count»). где ('courses_count = 0'). группа ( 'ID')

И вы можете вставить это прямо в вашу сферу:

scope :unenrolled,  joins(:courses).
                    select('students.*, COUNT(courses.*) AS courses_count').
                    where('courses_count = 0').
                    group('courses.course_id')

Примечание: Эти запросы немного запутаны и могут потребовать небольшой доработки. Самый простой способ создать сложные запросы ActiveRecord - вводить их непосредственно в консоль Rails до тех пор, пока вы не получите желаемые результаты.

Надеюсь, это полезно!

...