在检查值之前检查变量是否存在
问题描述:
此代码适用于我,但我怀疑有更多的ruby-ish方式来执行此操作。在检查值之前检查变量是否存在
<% 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 => team.assignment)为零。有没有办法在一行中做到这一点?
谢谢!
答
你在找什么叫做“nil guard”。这有几个方便的模式:
# 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
答
您可以使用Ruby的安全导航运算符,如here所述。
<% this_score = this_student.scores.find_by(:assignment => team.assignment) %>
<% if this_score&.points == 100 %>
<br/><small>(100%)</small>
<% end %>
答
我们可以在2.3使用安全导航操作&.
。
<% this_score = this_student.scores.find_by(:assignment => team.assignment) %>
<small>(<%= this.student&.score || 0 %>%)</small>
<% end %>
+0
此建议已于7小时前发布。 –
非常好。谢谢你的解答和你的回答。我有一个功能可以检查每个学生的作业,因此它可以运行几千次。你会建议哪种模式以获得最佳性能? –
@JeffZivkovic刚刚更新了两个松散的假设例子,如何处理这取决于你的情况。 – coreyward
现在,这超越了!我会尝试将您的示例适用于我的应用程序。 –