Amm*_*mar 1 scope nested associations ruby-on-rails-3.1
# student.rb
has_and_belongs_to_many :courses
# course.rb
has_and_belongs_to_many :students
Run Code Online (Sandbox Code Playgroud)
我正在尝试在学生模型中创建一个范围,以检查他们是否注册了课程.
我提出的最好的是:
scope :unenrolled, where(Student.courses.count => 0)
Run Code Online (Sandbox Code Playgroud)
但后来我得到了错误信息
未定义的方法`课程'
有人提出任何建议吗?
好吧那么.所以这是你的代码:
scope :unenrolled, where(Student.courses.count => 0)
Run Code Online (Sandbox Code Playgroud)
这里的第一个问题是导致错误的事情:你在类上调用实例方法.顾名思义,您只能在类的实例上调用实例方法,而不能在类本身上调用.例如:courses Student
jim = Student.find(123)
jims_courses = jim.courses
Run Code Online (Sandbox Code Playgroud)
但这里是踢球者:当你scope在类上下文中调用时,即代码不在实例方法中,因此在首次声明模型时会调用它.当时没有实例,所以你不能courses像在一个Student实例方法中那样调用.
但这有点没有实际意义,因为你有点误解了它是如何where运作的.您给出的参数where应该是与您在SQL查询中放置的内容相对应的条件WHERE.例如where(:eye_color => 'brown')将变成一个WHERE类似的SQL 子句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`;
Run Code Online (Sandbox Code Playgroud)
这大致转换为ActiveRecord查询,如下所示:Student.joins(:courses).// AR courses通过courses_students
select('students.,COUNT(courses.)AS courses_count')自动加入.where('courses_count = 0').组( 'ID')
你可以将它直接插入你的范围:
scope :unenrolled, joins(:courses).
select('students.*, COUNT(courses.*) AS courses_count').
where('courses_count = 0').
group('courses.course_id')
Run Code Online (Sandbox Code Playgroud)
注意:这些查询有点偏僻,可能需要稍微调整一下.构建复杂的ActiveRecord查询的最简单方法是将它们直接输入Rails控制台,直到获得所需的结果.
希望有用!