jj_*_*jj_ 9 ruby activerecord json ruby-on-rails custom-object
在Rails(4.1.5/ruby 2.0.0p481/win64)应用程序中,我在Student和Course之间存在多对多关系,并且有一个表示关联的连接模型StudentCourse,并且有一个名为started 的附加属性(默认设置)在"假").
我还在student_id和course_id组成的join-table中添加了一个索引,并设置了一个唯一的检查,就像这样
t.index [:student_id, :course_id], :unique => true, :name => 'by_student_and_course'
Run Code Online (Sandbox Code Playgroud)
我希望它是一个复合主键,但由于在rails中没有复合主键(不使用gem),我还添加了一个名为id的主键:
t.column :id, :primary_key
Run Code Online (Sandbox Code Playgroud)
现在我看到关联是通过以下方式创建的:
Student.first.courses.create(:name => "english")
Run Code Online (Sandbox Code Playgroud)
要么
Course.first.students << Student.first
Run Code Online (Sandbox Code Playgroud)
我认为这很好,这是预期的行为.
作为参考,Student.all,Course.all和StudentCourses.all将返回如下表格:
Student.all
+----+-----------+
| id | name |
+----+-----------+
| 1 | Aidan |
| 2 | Alison |
| 3 | Elizabeth |
+----+-----------+
Run Code Online (Sandbox Code Playgroud)
Course.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 |
+----+----------+------------------+
Run Code Online (Sandbox Code Playgroud)
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 |
+-------------+------------+------------+----+
Run Code Online (Sandbox Code Playgroud)
到目前为止,我可以愉快地渲染所有课程的json对象,以及每个课程的所有学生的名字,如下所示:
render json: Course.all.to_json(:include => {:students => {:only => :name}})
Run Code Online (Sandbox Code Playgroud)
我还可以轻松呈现学生参加或即将参加的所有课程
render json: @student.courses.to_json(:include => {:students => {:only => :name}})
Run Code Online (Sandbox Code Playgroud)
其中还包括其他学生的课程.
但是假设我想要提供一个学生尚未开始的学生课程,以及所有其他在该课程上学习的课程(有或没有开课) [请阅读下面的更新部分,我正在寻找事实恰恰相反!]
我认为easyieast方法是查询连接表,例如:
StudentCourse.all.where(student_id: @student.id, started: false)
+-------------+------------+------------+----+
| course_id | student_id | started | id |
+-------------+------------+------------+----+
| 5 | 2 | false | 7 |
| 6 | 2 | false | 9 |
+-------------+------------+------------+----+
Run Code Online (Sandbox Code Playgroud)
但是,我如何从这个结果表(关联对象)继续获得一个包含课程名称(以及所有其他属性)的精美包装的json对象,还包括其中的学生,就像我一样:Course.all.to_json(:include => {:students => {:only => :name}})
?
我想我在这里缺少一些关键概念的基本知识,但是在这一点上我甚至无法识别它们并且非常感谢一些帮助......谢谢.
我刚刚意识到以下部分是我原本想要做的事情.这是相反的事情.在所有这些细节中,我迷失在路上.我希望我可以在这里添加它.
所以,考虑到一个学生(让我们称他为艾登),我需要返回一个JSON对象,其中只包含他所在的课程和他已经开始的课程,只有当这些课程中还有其他学生没有开始学习时,必须包括每门课程的学生姓名.
所以...
我现在有:
aiden_started_courses = Student(1).courses.where(:student_courses => {:started => true } )
Run Code Online (Sandbox Code Playgroud)
对于学生来说,它会在join-table"started"列中获取所有具有"true"值的课程.(再次在连接表中,每个学生课程记录都是"复合"唯一的,因此对于给定的student_id和course_id,只能有一个唯一的记录).
通过下一个查询,对于"aiden_started_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 |
+-------------+------------+------------+----+
Run Code Online (Sandbox Code Playgroud)
所以问题在于:我已经设法在aiden_started_courses数组中为单个课程设置了这个,但是我如何能够为所有 Aiden的已开始课程构建一个返回此数据的查询?
有可能在一行中做到这一点吗?我知道我可能会使用Ruby枚举器循环,但我有点觉得我会在Rails编码约定级别和性能级别上打破一些模式?(再次遇到N + 1问题?)......
到目前为止我能做什么:
我找到了这个,我发现所有没有开始给定用户已经开始的课程的学生:
Student.includes(:student_courses).
where(:student_courses => { :started => false, :course_id => aiden.courses.where
(:student_courses => {started: true}).ids } )
Run Code Online (Sandbox Code Playgroud)
或这个:
Course.includes(:students).where(:student_courses => {:started => false,
:course_id => aiden.courses.where(:student_courses => {:started =>true}).ids })
Run Code Online (Sandbox Code Playgroud)
如果这些课程包括尚未开始学习的学生,则查找特定学生已开始的所有课程
但我真正需要的是获得这样的JSON对象:
[
{
"id": 1,
"name": "english",
"students": [
{"name": "ALison"},
{"name": "Robert"}]
},
{
"id": 2,
"name": "music",
"description": null,
"students": [
{"name": "Robert"},
{"name": "Kate"}]
}
]
Run Code Online (Sandbox Code Playgroud)
在那里我可以看到特定学生所在的课程,并且已经开始,但只有那些尚未开始学习的学生,以及那些学生的名字......
我想我可能无法通过常规的AR查询获得这个,所以也许应该手动构建一个JSON?但我怎么能这样做?
谢谢你.我为冗长而道歉..但希望它会有所帮助..
利用scope
你的优势:
class Course < ActiveRecord::Base
# ...
scope :not_started, -> { joins(:student_courses) \
.where(student_courses: {started: false}) }
scope :with_classmates, -> { includes(:students) } # use eager loading
end
Run Code Online (Sandbox Code Playgroud)
然后打电话:
@student.courses.not_started.with_classmates \
.to_json(include: {students: {only: :name}})
Run Code Online (Sandbox Code Playgroud)
输出:
[
{
"id": 1,
"name": "english",
"description": null,
"students": [
{"name": "Aiden"},
{"name": "Alison"}]},
{
"id": 2,
"name": "music",
"description": null,
"students": [
{"name": "Aiden"},
{"name": "Alison"}]},
{
"id": 3,
"name": "dance",
"description": null,
"students": [
{"name": "Aiden"}]}]
Run Code Online (Sandbox Code Playgroud)
使用JBuilder,它默认带有Rails.忽略以'#'开头的行:
Jbuilder.new do |j|
# courses: [{
j.courses <student.courses - replace this with whatever variable> do |course|
# id: <course.id>
j.id course.id
# name: <course.name>
j.name course.name
# students: [{
j.students <course.students - replace with whatever variable> do |student|
# name: <student.name>
j.name student.name
end
# }]
end
# }]
end
Run Code Online (Sandbox Code Playgroud)
不是很多代码.删除注释并简化某些功能,它将如下所示:
student_courses = <...blah...>
json = Jbuilder.new do |j|
j.courses student_courses do |course|
j.(course, :id, :name)
j.students <course.students - whatever method here>, :name
end
end.target!
Run Code Online (Sandbox Code Playgroud)
查看他们的指南,它非常棒,可以在纯Ruby DSL中生成JSON.因此,请继续使用您想要获取学生/课程/学生课程的任何红宝石代码.
归档时间: |
|
查看次数: |
5691 次 |
最近记录: |