2017-07-14 16 views
0

このコードは私のために働いていますが、これを行うにはもっとルビーの方法があると思われます。値がチェックされる前に変数が存在するかどうかを確認してください

<% this_score = this_student.scores.find_by(:assignment => team.assignment) %> 
    <% if this_score && this_score.points == 100 %> 
     <br/><small>(100%)</small> 
    <% end %> 

最初の2行は私の質問を具現化します。 this_student.scores.find_by(:assignment => team.assignment)がnilの場合に発生するエラーを避けるために、このようにします。これを1行で行う方法はありませんか?

ありがとうございます!

答えて

3

あなたが探しているものは、「nilガード」と呼ばれています。いくつかの便利なパターンはこのためにあります。

# 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個のクエリの問題。

私は、あなたと学生との間に適切な関係がないと思われます。私はStudentAssignmentScoreの名前を変更し、それに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リレーションシップを利用して、それ以外の任意のクエリを熱心に読み込むことができます

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 
+0

優れています。あなたの答えと一緒に役立つ説明をありがとう。私は、すべての学生とすべての課題をチェックする1つの関数を持っているので、これらの行は数千回実行されます。最高のパフォーマンスのためにどのパターンをお勧めしますか? –

+0

@JeffZivkovicちょうどあなたの状況に応じてこれを処理する方法の2つの緩やかに仮説的な例で更新されました。 – coreyward

+0

これ以上のことはありません。私はあなたの例を自分のアプリケーションに適応しようとします。 –

2

Rubyのセーフナビゲーションオペレータは、hereのように使用できます。

<% this_score = this_student.scores.find_by(:assignment => team.assignment) %> 
    <% if this_score&.points == 100 %> 
     <br/><small>(100%)</small> 
    <% end %> 
0

我々は2.3で安全なナビゲーション演算子&.を使用することができます:N + 1を回避するためのナビゲーション。

<% this_score = this_student.scores.find_by(:assignment => team.assignment) %> 
    <small>(<%= this.student&.score || 0 %>%)</small> 
<% end %> 
+0

この提案はすでに7時間前に投稿されました。 –

関連する問題