【发布时间】:2015-01-03 23:08:37
【问题描述】:
在 Rails ( 4.1.5 / ruby 2.0.0p481 / win64 ) 应用程序中,Student 和 Course 之间存在多对多关系以及连接模型StudentCourse 表示关联,并且有一个附加属性,称为started(默认设置为“false”)。
我还在由 student_id 和 course_id 组成的连接表中添加了一个索引,并对其设置了唯一检查,如下所示
t.index [:student_id, :course_id], :unique => true, :name => 'by_student_and_course'
我希望它是一个复合主键,但由于在 rails 中没有复合主键(不使用 gem),我还添加了一个名为 id 的主键:
t.column :id, :primary_key
现在我看到关联是通过以下任一方式创建的:
Student.first.courses.create(:name => "english")
或
Course.first.students << Student.first
这很好,我想这是预期的行为。
也就是说,我正在努力围绕 ActiveRecord 查询中的关联解决方案。让我更好地解释一下:
作为参考,Student.all、Course.all 和 StudentCourses.all 将返回如下表格:
学生.all
+----+-----------+
| id | name |
+----+-----------+
| 1 | Aidan |
| 2 | Alison |
| 3 | Elizabeth |
+----+-----------+
课程.all
+----+----------+------------------+
| id | name | description |
+----+----------+------------------+
| 1 | english | desc. here |
| 2 | music | desc. here |
| 3 | dance | desc. here |
| 4 | science | desc. here |
| 5 | french | desc. here |
| 6 | arts | desc. here |
+----+----------+------------------+
StudentCourse.all
+-------------+------------+------------+----+
| course_id | student_id | started | id |
+-------------+------------+------------+----+
| 1 | 1 | false | 1 |
| 2 | 1 | false | 2 |
| 3 | 1 | false | 3 |
| 1 | 2 | true | 4 |
| 2 | 2 | true | 5 |
| 4 | 3 | false | 6 |
| 5 | 2 | false | 7 |
| 5 | 1 | true | 8 |
| 6 | 2 | false | 9 |
+-------------+------------+------------+----+
到目前为止,我可以愉快地渲染所有课程的 json 对象,以及每门课程的所有学生的姓名,如下所示:
render json: Course.all.to_json(:include => {:students => {:only => :name}})
我还可以轻松呈现学生正在或即将参加的所有课程
render json: @student.courses.to_json(:include => {:students => {:only => :name}})
其中还包括参加这些课程的其他学生。
但假设我想渲染一个学生尚未开始的课程,以及正在学习该课程的所有其他学生(已开始或未开始该课程) [请阅读下面的更新部分,实际上我正在寻找相反的东西!]
我认为最简单的方法是查询连接表,例如:
StudentCourse.all.where(student_id: @student.id, started: false)
+-------------+------------+------------+----+
| course_id | student_id | started | id |
+-------------+------------+------------+----+
| 5 | 2 | false | 7 |
| 6 | 2 | false | 9 |
+-------------+------------+------------+----+
但是我如何从这个结果表(关联对象)中继续获得一个带有课程名称(和所有其他属性)以及 包括学生的打包好的 json 对象,就像我对:Course.all.to_json(:include => {:students => {:only => :name}}) 所做的那样?
我认为我在这里缺少一些重要关键概念的基本知识,但此时我什至无法识别它们,非常感谢一些帮助......谢谢。
更新:
我刚刚意识到以下部分是我最初想要做的。这是相反的事情。在所有这些细节中,我迷路了。我希望我在这里添加它就可以了。
因此,给定一个学生(我们称他为 Aiden),我需要返回一个 JSON 对象,其中仅包含他所参加的课程以及 他已经开始,只 当此类课程中有其他学生尚未开始他们时,它还必须包括每门课程的学生姓名。
所以...
我现在有:
aiden_started_courses = Student(1).courses.where(:student_courses => {:started => true } )
对于 student 而言,它采用所有在连接表“started”列中具有“true”值的 courses。 (同样,在连接表中,每个 student-course 记录都是“复合”唯一的,因此给定的 student_id 和 course_id 只能有一个唯一记录。
通过下一个查询,对于 one 的“aiden_started_courses”,我可以取消所有在“started”上具有错误值的相关 student-courses 关联
aiden_started_courses[0].student_courses.where(:started => false).includes(:student).to_json(:include => :student)
+-------------+------------+------------+----+
| course_id | student_id | started | id |
+-------------+------------+------------+----+
| 1 | 2 | false | 4 |
+-------------+------------+------------+----+
| 1 | 9 | false | 5 |
+-------------+------------+------------+----+
所以问题就在这里:我已经设法为 aiden_started_courses 数组中的一门课程获得了这个,但是我如何能够构建一个查询来返回此数据em>所有艾登开始的课程?
是否有可能在一行中做到这一点?我知道我可能可以使用 Ruby 枚举器循环,但我有点觉得我会在 Rails 编码约定级别和性能级别上打破一些模式? (再次遇到 N+1 问题?) ...
到目前为止我能做到的:
我想出了这个方法,我可以在其中找到所有尚未开始给定用户已经开始的课程的学生:
Student.includes(:student_courses).
where(:student_courses => { :started => false, :course_id => aiden.courses.where
(:student_courses => {started: true}).ids } )
或者这个:
Course.includes(:students).where(:student_courses => {:started => false,
:course_id => aiden.courses.where(:student_courses => {:started =>true}).ids })
如果这些课程包括尚未开始的学生,则查找给定学生已开始的所有课程
但我真正需要的是获得这样的 JSON 对象:
[
{
"id": 1,
"name": "english",
"students": [
{"name": "ALison"},
{"name": "Robert"}]
},
{
"id": 2,
"name": "music",
"description": null,
"students": [
{"name": "Robert"},
{"name": "Kate"}]
}
]
我可以在其中看到给定学生正在上和已经开始的课程,但只有那些还有其他学生尚未开始的课程,以及这些学生的名字......
我在想,我可能无法通过常规的 AR 查询来获得它,所以也许应该手动构建 JSON?但我怎么能这样做呢?
谢谢你的建议。我为冗长道歉..但希望它会有所帮助..
【问题讨论】:
-
在末尾追加
.to_json:StudentCourse.all.where(student_id: @student.id, started: false).to_json。 -
这不能回答我的问题。我已经到了这个(确切的)点。我知道添加“to_json”会呈现 JSON ......但我想要呈现的不仅仅是那个!请仔细阅读问题的最后部分。
-
是的,对不起。要自动填充学生/课程,您应该在各自的
ActiveRecords 上指定:belongs_to和:has_many属性,如下所示:api.rubyonrails.org/classes/ActiveRecord/Associations/… -
这已经完成了!我在第一行说这个! “我在学生和课程之间有多对多的关系”......这意味着模型中的
has_many ... :through ...s 和belongs_tos。如果您真的必须发表评论,请您更加注意阅读问题吗?谢谢。
标签: ruby-on-rails ruby json activerecord custom-object