2017-10-21 100 views
0

我想了解ActiveRecord查询。来自sql背景,这有点令人困惑。我想编写一个查询来获取特定学生参加与下面的查询所有课程:建立一个有多个连接的活动记录查询

def self.courses_enrolled_in(student_id) 
    Course.joins(:sections).where(sections: {enrollment: Enrollment.where(student: Student.find_by(id: student_id))}) 
    end 

但轨道控制台提供了以下错误:

ActiveRecord::StatementInvalid: SQLite3::SQLException: no such column: sections.enrollment:

这是从拼凑一个以前的asked question,从内到外工作。我明白错误在说什么,但我想我不清楚如何将连接链接在一起,就像在sql中将一个表连接到另一个表一样。我将如何编写一个查询来提取特定学生注册的所有课程?

模式

招生

class Enrollment < ApplicationRecord 
    belongs_to :section 
    belongs_to :student 
end 

学生:

class Student < ApplicationRecord 
    has_many :enrollments 
end 

教授:

class Section < ApplicationRecord 
    has_many :enrollments 
    belongs_to :professor 
    belongs_to :course 

end 

课程:

class Course < ApplicationRecord 

    belongs_to :department 
    has_many :sections 
    has_many :professors, through: :sections 
end 

回答

0

因此,您问的是,考虑到学生在许多课程的许多部分注册,哪些课程是学生注册的?

我们会忽略教授,因为这与原始问题无关。

或者换句话说

学生1:M招生M:1个M部分:1场

或学生L:M截面。注册是学生与科之间M:M关系的加入表,不是?

所以马上我们看到,学生应该是:

rails g student name 
class Student < ApplicationRecord 
    has_many :enrollments 
    has_many :sections, through: :enrollments 
end 

扩招是一个连接表,所以它需要的学生和部分的IDS

rails g enrollment student_id section_id 
class Enrollment < ApplicationRecord 
    belongs_to :student 
    belongs_to :section 
end 

(定义属于只如果你想工作一个注册实例并与它的关系一起工作,则是必要的)

该部分

rails g section name course_id 
class Section < ApplicationRecord 
    has_many :enrollments 
    has_many :students, through: :enrollments 
    belongs_to :course 
end 

而且当然

rails g course name 
class Course < ApplicationRecord 
    has_many :sections 
end 

,并把这个在一起的时候,我们要一起工作(同样,has_manys如果你想获得就读于部分学生只需要)学生的一个实例(获得一个特定学生的所有课程注册),因此self.courses_enrolled_in(student_id)声明是错误的方法。你应该可以尝试出这一切在轨道控制台,所以你会通过让学生开始:

[9] pry(main)> student = Student.first 
    Student Load (13.8ms) SELECT `students`.* FROM `students` ORDER BY `students`.`id` ASC LIMIT 1 
=> #<Student:0x007fc40fb88b68 
id: 1, 
name: "Fred", 

现在(从控制台输出为简洁起见省略时间戳),我们有我们的学生,问它有哪些部分:

pry(main)> sections = student.sections 
    Section Load (14.1ms) SELECT `sections`.* FROM `sections` INNER JOIN `enrollments` ON `sections`.`id` = `enrollments`.`section_id` WHERE `enrollments`.`student_id` = '1' 
=> [#<Section:0x007fc40c474208 
    id: 1, 
    name: "1st period", 
    course_id: "1", 
#<Section:0x007fc40c474028 
    id: 5, 
    name: "2nd period", 
    course_id: "2", 
#<Section:0x007fc40c46fe60 
    id: 9, 
    name: "3rd period", 
    course_id: "3", 
] 

并为每个部分中,我们可以得到课程:

pry(main)> sections.first.course 
    Course Load (17.1ms) SELECT `courses`.* FROM `courses` WHERE `courses`.`id` = 1 LIMIT 1 
=> #<Course:0x007fc40f756a18 
id: 1, 
name: "English", 

这将运行每个结果集合中的,不是最优的一个单独的查询,所以我们可以用做一个热心的负载包括:

pry(main)> student.sections.includes(:course) 
     Section Load (5.9ms) SELECT `sections`.* FROM `sections` INNER JOIN `enrollments` ON `sections`.`id` = `enrollments`.`section_id` WHERE `enrollments`.`student_id` = '1' 
     Course Load (9.5ms) SELECT `courses`.* FROM `courses` WHERE `courses`.`id` IN (1, 2, 3) 
    => [#<Section:0x007fc40faa13a8 
     id: 1, 
     name: "1st period", 
     course_id: "1", 
    #<Section:0x007fc40faa11c8 
     id: 5, 
     name: "2nd period", 
     course_id: "2", 
    #<Section:0x007fc40faa0fe8 
     id: 9, 
     name: "3rd period", 
     course_id: "3", 

所以现在:

pry(main)> sections.first.course 
=> #<Course:0x007fc40f6cc570 
id: 1, 
name: "English", 

没有额外的查询。为了简化事情,我会放一个COURSE_ID场在入学表,然后添加:

rails g student name 
class Student < ApplicationRecord 
    has_many :enrollments 
    has_many :sections, through: :enrollments 
    has_many :courses, through: :enrollments 
end 

总之,至于怎么做的加入?让ActiveRecord为您做好工作,那就是它的存在。你提供的关系定义是你如何指定你想要的连接。

1

在where函数中指定连接的条件时,应该指定表名称而不是关联名称。所以你的例子可能需要使用“注册”。 Active Record Query Interface Rails指南应该可以帮助您理解使用Active Record进行查询