0

我已经建立了两种exams_helper.rb在视图中使用的方法:

<% @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

在我看来,这些方法应该依赖于您的模型,因为它们的目的是从数据库中计算数据。此外,通过在模型层中编写这些方法,您可以避免控制器、视图或视图助手中的重复。

视图助手应该只用于“视图逻辑”方法,在视图上下文之外没有多大意义。

正确的问题和比率似乎与 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

然后,我会将这些数据库调用完全排除在视图之外。我不喜欢在视图中调用模型的数据库方法,因为它只是在模板文件中编写 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_countand @correct_count。现在好小帮手:)

于 2012-12-05T12:00:54.627 回答