我有三个模型Exam
,User
和ExamResult
。 ExamResult
包含所有考试(考试)学生(用户)的记录。对于一个特定的Exam
记录,每个学生在ExamResult
中应该有一条记录。在edit
的{{1}}方法中,根据是否为一个学生创建了ExamController
记录,我需要构建一个新记录或者只是跳过它。不确定这是否是惯用的Rails方式。
ExamResult
或者这样:
# ExamController
def edit
User.students.each do |s|
@exam.exam_results.build(user_id: s.id) unless @exam.exam_results.find_by(user_id: s.id)
end
end
也许两者都不是惯用的Rails。欢迎任何建议。
在桌面上带上def edit
newIds = User.students.map(&:id) - @exam.exam_results.map(&:user_id)
newIds.each do |id|
@exam.exam_results.build(user_id: id)
end
end
(由@ user3334690推荐)。如果我理解正确的文档,这应该与前两个实现相同。
find_or_initialize_by
答案 0 :(得分:4)
在上述情况下,您可以使用find_or_create_by_user_id代替构建。
def edit
User.students.each do |s|
ExamResult.find_or_create_by_exam_id_and_user_id(exam_id, user_id)
end
end
答案 1 :(得分:3)
就是这样:
def edit
User.students.each do |s|
ExamResult.where(exam_id: @exam.id, user_id: s.id).first_or_create
end
end
答案 2 :(得分:0)
使用你的第二个例子:
def edit
newIds = User.students.map(&:id) - @exam.exam_results.map(&:user_id)
newIds.each do |id|
@exam.exam_results.build(user_id: id)
end
end
正如我在上面的评论中所说,这将对数据库进行两次查询,而不管学生数量会更好。如果您处于一个非常极端的环境中,您可以将其编写为只使用一个查询以及"采取"只拉动" id"列(并避免对象创建开销),如下所示:
newIds = User.students.where("users.id not in (select user_id from exam_results where exam_id=?)", @exam.id).pluck(:id)
然而,可读性因此而降低。你的原版也可以使用" pluck"而不是" map"。
另一种风格说明 - 我会使用" new_ids"这是使用Rails执行此操作的标准惯用方法。