3

各評価期間の学生の平均スコアを表示するために、ビューの部分に次のコードがあります。

<tr class="<%= cycle("odd", "even", name: "students")%>">
    <td>
    <%= link_to "#{student.name}", 
                 student_path({student_group_id: student.student_group_id, id: student.id})%>
    </td>
    <% student.eval_count.times do |i| %>
      <td class="center"><%= student.avg_for_eval(i) %></td>
    <% end %>
    <td class="center"><%= student.avg unless student.avg.nan? %></td>
</tr>

このメソッドを使用しstudent.rbて平均スコアを生成していますが、最初は、データがないときに空の行を生成できない理由がわかりませんでした。

def evals
  evals = self.evaluations.order("eval_number").group_by(&:eval_number)
end

def eval_number_set(index)
  numbers = Evaluation.where('student_id = ?', self.id).uniq.pluck(:eval_number)
  numbers[index]
end

def avg_for_eval(i)
  scores = []
  evals = self.evals.select { |k, v| k == self.eval_number_set(i) }.values.first
  for eval in evals
    scores << eval.score
  end
  evals.empty? #(scores.sum.to_f / scores.size).round(2)  
end

メソッドの最後の行をevals.empty?上記のように変更し、ブラウザーでこれを取得しました。

ブラウザ

selectその後、学生が出席しなかった評価のため (新しい学生の場合)、コードを生成するために使用していたデータセットの一部ではないことに気付きました。

問題は、図でわかるように、最後の評価のデータしか持っていない 2 人の学生が正しい列にデータを持っていないことです<td>。ビュー コードによって no が生成されているため、すべてが左にシフトしています。 .

if scores.empty?したがって、問題は、同じ出力が得られるようにメソッドコードを書き直すにはどうすればよいか""ということです。"no data"<td>

アップデート

私は今何が起こっているのかを少しよく理解しています。この方法:

def eval_number_set(index)
  numbers = Evaluation.where('student_id = ?', self.id).uniq.pluck(:eval_number)
  numbers[index]
end

学生の評価番号を返しているため、それらの番号が次のメソッドで使用される場合

def avg_for_eval(i)
  scores = []
  evals = self.evals.select { |k, v| k == self.eval_number_set(i) }.values.first
  for eval in evals
    scores << eval.score
  end
  evals.empty? #(scores.sum.to_f / scores.size).round(2)  
end

学生が出席した評価のみを取得できます。今のところ製図板に戻ります...

更新 2

クラスメソッドを次のように変更しました。

#returns all 'eval_number's for a given group of students 
#as the first student will have been present for all evaluations

def eval_number_set(index)
  numbers = self.student_group.students.first.evals.keys
  # numbers = Evaluation.where('student_id = ?', self.id).uniq.pluck(:eval_number)
  numbers[index]
end

#attempts to match the first present 'eval_number' for a given student against
#the first number in the set of all 'eval_number's and react accordingly
def avg_for_eval(i)
  scores = []
  if self.evals.keys[i] == self.eval_number_set(i)
    "match"
  else
    "no_match"
  end  
end

これは、すべての評価に出席したすべての学生に一致しましたが、一部を逃した学生の評価には一致しませんでした。コードを次のように変更しました

  def avg_for_eval(i)
    scores = []
    if self.evals.keys[i] == self.eval_number_set(i)
      "#{self.evals.keys[i]} vs #{self.eval_number_set(i)}"
    else
      "#{self.evals.keys[i]} vs #{self.eval_number_set(i)}"
    end          
  end

ブラウザで次のように返されました。

新しい問題

そのため、if ステートメントにカウンターを追加して、ステートメントが一致した場合は試行中のキーをインクリメントし、それ以外の場合は同じキーにとどまるようにしました。

  def avg_for_eval(i)
    scores = []
    key_match = 0
    if self.evals.keys[key_match] == self.eval_number_set(i)
      "#{self.evals.keys[i]} vs #{self.eval_number_set(i)}"
      key_match += 1
    else
      "#{self.evals.keys[i]} vs #{self.eval_number_set(i)}"
    end  
  end

これはこれを生成します:

ここに画像の説明を入力

そして理にかなっています-カウントのインクリメントは、それが呼び出されている方法のために実際の効果をもたらしません. しかし、私は今、私が望む効果に近づいていると思いますが、それを実現する方法がわかりません!

更新 3

さらに近づいて...キーが逆に読み取られるように変更したため、すべてのデータが読み取られますが、最新のものを右側に印刷してデータを印刷したいと思います(下の図を参照) )。モデル メソッド コードは次のようになります。

  def eval_number_set(index)
    numbers = self.student_group.students.first.evals.keys.reverse
    # numbers = Evaluation.where('student_id = ?', self.id).uniq.pluck(:eval_number)
    numbers[index]
  end
  
  def avg_for_eval(i)
    scores = []
    eval_number = self.eval_number_set(i)
    if self.evals.keys.reverse[i] == eval_number
      for eval in self.evals.values[i] 
        scores << eval.score if self.evals.values[i]
      end
      scores
    else
      "no data"
    end  
  end

これは、私が探しているものが何であるかをもう少し明確に理解できるように、私が注釈を付けた次のものを返します。

ここに画像の説明を入力

更新 4

呼び出しは次をstudent.evals返します ( id32 の学生の場合):

{29=>[
  #<Evaluation id: 1949, score: 3, created_at: "2013-08-28 09:44:32", updated_at: "2013-08-28 09:44:32", student_id: 32, goal_id: 63, eval_number: 29>, 
  #<Evaluation id: 1950, score: 4, created_at: "2013-08-28 09:44:32", updated_at: "2013-08-28 09:44:32", student_id: 32, goal_id: 64, eval_number: 29>, 
  #<Evaluation id: 1951, score: 5, created_at: "2013-08-28 09:44:32", updated_at: "2013-08-28 09:44:32", student_id: 32, goal_id: 65, eval_number: 29>], 
30=>[
  #<Evaluation id: 1957, score: 3, created_at: "2013-08-28 09:44:43", updated_at: "2013-08-28 09:44:43", student_id: 32, goal_id: 65, eval_number: 30>, 
  #<Evaluation id: 1956, score: 2, created_at: "2013-08-28 09:44:43", updated_at: "2013-08-28 09:44:43", student_id: 32, goal_id: 64, eval_number: 30>, 
  #<Evaluation id: 1955, score: 1, created_at: "2013-08-28 09:44:43", updated_at: "2013-08-28 09:44:43", student_id: 32, goal_id: 63, eval_number: 30>], 
31=>[
  #<Evaluation id: 1968, score: 2, created_at: "2013-08-28 11:26:56", updated_at: "2013-08-28 11:26:56", student_id: 32, goal_id: 70, eval_number: 31>, 
  #<Evaluation id: 1967, score: 2, created_at: "2013-08-28 11:26:56", updated_at: "2013-08-28 11:26:56", student_id: 32, goal_id: 69, eval_number: 31>, 
  #<Evaluation id: 1966, score: 1, created_at: "2013-08-28 11:26:56", updated_at: "2013-08-28 11:26:56", student_id: 32, goal_id: 68, eval_number: 31>, 
  #<Evaluation id: 1965, score: 1, created_at: "2013-08-28 11:26:56", updated_at: "2013-08-28 11:26:56", student_id: 32, goal_id: 67, eval_number: 31>, 
  #<Evaluation id: 1964, score: 1, created_at: "2013-08-28 11:26:56", updated_at: "2013-08-28 11:26:56", student_id: 32, goal_id: 66, eval_number: 31>, 
  #<Evaluation id: 1963, score: 3, created_at: "2013-08-28 11:26:56", updated_at: "2013-08-28 11:26:56", student_id: 32, goal_id: 65, eval_number: 31>, 
  #<Evaluation id: 1962, score: 3, created_at: "2013-08-28 11:26:56", updated_at: "2013-08-28 11:26:56", student_id: 32, goal_id: 64, eval_number: 31>, 
  #<Evaluation id: 1961, score: 3, created_at: "2013-08-28 11:26:56", updated_at: "2013-08-28 11:26:56", student_id: 32, goal_id: 63, eval_number: 31>], 
32=>[
  #<Evaluation id: 1983, score: 3, created_at: "2013-08-29 19:31:48", updated_at: "2013-08-29 19:31:48", student_id: 32, goal_id: 69, eval_number: 32>, 
  #<Evaluation id: 1982, score: 2, created_at: "2013-08-29 19:31:48", updated_at: "2013-08-29 19:31:48", student_id: 32, goal_id: 68, eval_number: 32>, 
  #<Evaluation id: 1981, score: 3, created_at: "2013-08-29 19:31:48", updated_at: "2013-08-29 19:31:48", student_id: 32, goal_id: 67, eval_number: 32>, 
  #<Evaluation id: 1980, score: 4, created_at: "2013-08-29 19:31:48", updated_at: "2013-08-29 19:31:48", student_id: 32, goal_id: 66, eval_number: 32>, 
  #<Evaluation id: 1979, score: 4, created_at: "2013-08-29 19:31:48", updated_at: "2013-08-29 19:31:48", student_id: 32, goal_id: 65, eval_number: 32>, 
  #<Evaluation id: 1978, score: 3, created_at: "2013-08-29 19:31:48", updated_at: "2013-08-29 19:31:48", student_id: 32, goal_id: 64, eval_number: 32>, 
  #<Evaluation id: 1977, score: 3, created_at: "2013-08-29 19:31:48", updated_at: "2013-08-29 19:31:48", student_id: 32, goal_id: 63, eval_number: 32>, 
  #<Evaluation id: 1984, score: 3, created_at: "2013-08-29 19:31:48", updated_at: "2013-08-29 19:31:48", student_id: 32, goal_id: 70, eval_number: 32>]
}
4

5 に答える 5

0

group.eval_countが の最大数であると仮定しeval_countます。

意見

<table class="fixed">
  <thead>      
    <tr>
      <th></th>
      <% group.eval_count.times do |i| %>                                             
      <th class="center">Evaluation <%= i + 1 %></th>
      <% end %>
      <th><%= "Student average" if group.eval_count > 0  %></th>
    </tr>
  </thead>
  <tbody>
    <% group.students.each do |student| %>
    <tr class="<%= cycle("odd", "even", name: "students")%>">
      <td>
        <%= link_to student.name, 
                    student_path({
                      student_group_id: student.student_group_id, 
                      id: student.id
                      })%>
      </td>
      <% group.eval_count.times do |i| %>
      <td class="center"><%= student.avg_for_eval(i+1) %></td>
      <% end %>
      <td class="center"><%= student.avg unless student.avg.nan? %></td>
    </tr>
    <% end %>
    <% reset_cycle("students") %>
  </tbody>
</table>

すべての評価番号を反復処理したくない場合 (つまり、29 から開始する場合) は、 range を使用(min..group.eval_count).eachして、 reverse で実行することもできます(min..max).to_a.reverse.each。あなたのデータからmaxminを理解することはかなり簡単なはずです。

学生.rb

def avg_for_eval(i)
  # nil evaluated as false hence this works...
  if evaluations_with_sum[i]
     (evaluations_with_sum[i].sum / evaluations_with_sum[i].size).round(2)
  else
    'no data'
  end  
end

private
def evaluations_with_sum
  # memoize as hash using instance variable
  # 'order' does work with symbol and the sorting will be ASC
  @evals ||= self.evaluations.order(:eval_number).inject({}) do |hash, evaluation|
    hash[evaluation.eval_number] ||= []
    hash[evaluation.eval_number] << evaluation.score
    hash
  end
end

実際にはas key とas value の合計self.evaluations.order(:eval_number).average(:score).group(:eval_number)ハッシュを与えるべきだと思いますが、あなたがそれを試すことができるかどうかはわかりません…</p> eval_numberscore

于 2013-09-06T15:07:00.623 に答える
0

以下のコードで最終的にこれが機能するようになりました-しかし、誰かがこれを行うためのより良い方法を教えてくれれば、喜んで彼らに報奨金を与えます.

_student_list.html.erb

<table class="fixed">
  <tbody>      
    <% group.students.each_with_index do |student, index| %>
    <tr>
      <th></th>
      <% if index == 0 %>
        <% student.eval_count.times do |i| %>                                             
          <th class="center">Evaluation <%= i + 1 %></th>
        <% end %>
        <th><%= "Student average" if student.eval_count > 0  %></th>
      <% end %>

    </tr>
    <tr class="<%= cycle("odd", "even", name: "students")%>">
      <td>
        <%= link_to student.name, student_path({student_group_id: student.student_group_id, id: student.id})%>
      </td>
      <% student.student_group.eval_count.times do |i| %>
        <td class="center"><%= student.avg_for_eval(i) %></td>
      <% end %>
      <td class="center"><%= student.avg unless student.avg.nan? %></td>
    </tr>
    <% end %>
    <% reset_cycle("students") %>
  </tbody>
</table>

student.rb

  def eval_number_set(index)
    numbers = self.student_group.students.first.evals.keys
    numbers[index]
  end

  def reverse_eval_number_set(index)
    numbers = self.student_group.students.first.evals.keys.reverse
    numbers[index]
  end

  def avg_for_eval(i)
    scores = []
    eval_number = self.reverse_eval_number_set(i)
    count_differential = (self.student_group.eval_count - self.eval_count) - i
    if self.student_group.eval_count == self.eval_count
      for eval in self.evals.values[i] 
        scores << eval.score
      end
      (scores.sum.to_f / scores.size).round(2)
    else
      if self.evals.values[count_differential]
        for eval in self.evals.values[count_differential]
          scores << eval.score
        end
        (scores.sum.to_f / scores.size).round(2)
      else
        "no data"
      end  
    end  
  end
于 2013-09-05T15:30:59.927 に答える