此代码对我有用,但我怀疑这是一种更为红宝石的方法。
<% this_score = this_student.scores.find_by(:assignment => team.assignment) %>
<% if this_score && this_score.points == 100 %>
<br/><small>(100%)</small>
<% end %>
前两行代表了我的问题。我这样做是为了避免在this_student.scores.find_by(:assignment =&gt; team.assignment)为零时发生的错误。是不是有办法在一行中做到这一点?
谢谢!
答案 0 :(得分:3)
你正在寻找的东西被称为“无守卫”。有一些方便的模式:
# safe navigation operator - if `nil_thing` is nil, `points` won't be called
nil_thing&.points
# the double ampersand check (what you've used)
if nil_thing && nil_thing.points == 100
# compound one-line conditional
do_stuff if nil_thing.points == 100 unless nil_thing.blank?
你也可以在很多时候避免这种情况:
if student.scores.where(points: 100, assignment: team.assignment).exists?
do_stuff
end
请注意,您组合此查询的方式很难避免N + 1查询问题。
我怀疑你与学生和作业之间没有适当的关系。我会将Score
重命名为StudentAssignment
并在其上设置score
属性:
class Student
has_many :student_assignments
has_many :assignments, through: :student_assignments
end
class Assignment
has_many :student_assignments
has_many :students, through: :student_assignments
end
然后你可以在Ruby中使用基本的预先加载和值比较:
Assignment.includes(student_assignments: :students).each do |assignment|
puts "Scores for #{assignment.name}:"
assignment.student_assignments.each do |sa|
puts "#{sa.student.name} scored #{sa.score}"
puts "Congratulations to #{sa.student.name}" if sa.score >= 99
end
end
你也可以从另一个方向做到这一点:循环学生并用分数显示他们的作业。
如果你的设置中没有可能将学生连接到多对多分配,你可以设置像perfect_scores
这样的条件关联,让你急于加载其他任意的查询,利用ActiveRecord关系导航来避免N + 1:
class Student
has_many :scores
has_many :perfect_scores, -> { where(score: 100) }, class_name: 'Score', inverse_of: :student
def perfect_score_on_assignment?(assignment)
if perfect_scores.loaded?
# use cached data
perfect_scores.any? { |score| score.assignment_id == assignment.id }
else
# use sql to determine
perfect_scores.where(assignment: assignment).exists?
end
end
end
class Score
belongs_to: :student
belongs_to: :assignment
end
class Assignment
has_many :scores
end
# Load up all of the students and eager load perfect scores
@students = Student.includes(perfect_scores: :assignment)
@assignments = Assignment.all
@assignment.each do |assignment|
@students.each do |student|
if student.perfect_score_on_assignment?(assignment)
puts "#{student.name} scored 100%"
end
end
end
答案 1 :(得分:2)
您可以按照here所述使用Ruby的安全导航操作符。
<% this_score = this_student.scores.find_by(:assignment => team.assignment) %>
<% if this_score&.points == 100 %>
<br/><small>(100%)</small>
<% end %>
答案 2 :(得分:0)
我们可以在2.3中使用安全导航操作员&.
。
<% this_score = this_student.scores.find_by(:assignment => team.assignment) %>
<small>(<%= this.student&.score || 0 %>%)</small>
<% end %>