0

exams_helper.rbビューで使用する2 つのメソッドを組み込みました。

<% @topic_questions.each do |topic_question| %>
<tr>
  <td><%= topic_question.topic.name %></td>
  <td><%= correct_questions(@exam_result.exam_id, topic_question.topic_id) %></td>
  <td><%= number_to_percentage(ratio(@exam_result.exam_id, topic_question.topic_id), precision: 0) %></td>
</tr>
<% end %>

トピックの正解数の計算方法:

  def correct_questions(exam_id, topic_id)
    total = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id).count
    correct = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id, correct: true).count
    correct.to_s + '/' + total.to_s
  end

正解率の計算方法

  def ratio(exam_id, topic_id)
    total = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id).count
    correct = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id, correct: true).count
    ratio = (correct.to_f/total).round(2)*100
    if ratio.nan?
      ratio = 0
    else
      ratio
    end
  end

これらのコードが繰り返されます。

total = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id).count
correct = ExamQuestion.where(exam_id: exam_id, topic_id: topic_id, correct: true).count

これらのメソッドをより適切に記述するにはどうすればよいですか?

4

3 に答える 3

4

私の意見では、これらのメソッドの目的はデータベースからデータを計算することであるため、これらのメソッドはモデルに依存する必要があります。また、これらのメソッドをモデル層に記述することで、コントローラー、ビュー、またはビュー ヘルパーでの重複を避けることができます。

ビュー ヘルパーは、ビュー コンテキストの外ではあまり意味をなさない「ビュー ロジック」メソッドにのみ使用する必要があります。

correct_questionsratioは、ExamResult オブジェクトと密接に関連しているようです。次の実装を想像できます。

class ExamResult
  has_many :exam_questions

  def correct_questions_ratio(topic)
    ratio = (correct_questions(topic).to_f/total_questions(topic)).round(2)*100

    if ratio.nan?
      ratio = 0
    else
      ratio
    end
  end

  def total_questions(topic)
    #To avoid recomputing the result from db we memoize it for each topic.
    @total_questions ||= {}
    @total_questions[topic] ||= exam_questions.where(:topic_id => topic.id).count
  end

 def correct_questions(topic)
   #To avoid recomputing the result from db we memoize it for each topic.
   @correct_questions ||= {}
   @correct_questions[topic] ||= exam_questions.where(:topic_id => topic.id, :correct => true).count
 end
end

メモ化は、同じ結果を何度も再計算することを避けるための「キャッシング」の一種です。それに関する多くの記事を見つけることができます。これは良いものです: http://www.railway.at/articles/2008/09/20/a-guide-to-memoization/

最後に、ビューに次のコードが表示されます。ヘルパーはもはや必要ではありませんが、パラメーターとして ExamResult インスタンス (@exam_result) を取って、「正解/合計」部分を作成するヘルパー メソッドを作成することはできます。

<% @topic_questions.each do |topic_question| %>
  <tr>
    <td><%= topic_question.topic.name %></td>
    <td><%= @exam_result.correct_questions(topic_question.topic) %>/<%= @exam_result.total_questions(topic_question.topic)%></td>
    <td><%= number_to_percentage(@exam_result.correct_questions_ratio(topic_question.topic)), precision: 0) %></td>
  </tr>
<% end %>
于 2012-12-05T13:42:04.590 に答える
1

あなたのモデルでは:

scope :exam,  lambda { |exam_id|  where(exam_id:  exam_id) }
scope :topic, lambda { |topic_id| where(topic_id: topic_id) }
scope :correct, lambda { where(correct: true) }

あなたのヘルパーで:

def get_total_and_correct_count_for(exam_id, topic_id)
  [
   ExamQuestion.exam(exam_id).topic(topic_id).count,
   ExamQuestion.exam(exam_id).topic(topic_id).correct.count
   ]
end

def correct_questions(exam_id, topic_id)
  total, correct = get_total_and_correct_count_for(exam_id, topic_id)
  correct.to_s + '/' + total.to_s
end

def ratio(exam_id, topic_id)
  total, correct = get_total_and_correct_count_for(exam_id, topic_id)
  ratio = (correct.to_f/total).round(2)*100
  if ratio.nan?
    ratio = 0
  else
    ratio
  end
end

補足:

  • ヘルパー内でこの種のデータベース操作を実行するのは奇妙に感じます。

  • 最初はメモ化を検討しましたが、ActiveRecord には組み込みのキャッシュが用意されています

  • ループしている場合は、結果をキャッシュしてリクエスト間で永続化することを検討してください。これはデータベースに悪影響を与えるためです。

于 2012-12-05T12:00:50.837 に答える
0

まず、毎回ExamQuestion使用するのではなく、モデル上にいくつかのメソッドを作成してみませんか?where

class ExamQuestion
    #...
    def self.total_count(exam_id, topic_id)
        where(exam_id: exam_id, topic_id: topic_id).count
    end

    # create similar method for "correct" count
 end

次に、これらのdb呼び出しをビューから完全に削除します。ビューでモデルのデータベースメソッドを呼び出すのは好きではありません。テンプレートファイルにSQLを記述するためのより良い方法だからです。可能であれば、それらをコントローラーアクションに入れて、ビューに渡します。

# Your controller action
@total_count = ExamQuestion.total_count(exam_id, topic_id)
@correct_count = ExamQuestion.correct_count(exam_id,topic_id)
#...

最後に、exam_idとtopic_idをヘルパーに渡す代わりに、合格@total_countして@correct_count。素敵で小さなヘルパーが今:)

于 2012-12-05T12:00:54.627 に答える