2012-12-05 57 views
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

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

视图助手只应该用于'视图 - 逻辑'方法,这些方法在视图上下文之外没有多少意义。

correct_questions似乎是密切相关的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 %> 
+0

好吧,我想我要改写我的代码更好。当我需要首先加载考试答案时,“Memoization”也可能是我正在寻找解决问题的方法。非常感谢。 – Thanh

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 

图片的标题说明:

  • 感觉怪异内执行这种数据库的交互帮手。

  • 我首先考虑memoizing但ActiveRecord的提供了一个内建的缓存

  • 如果它是在一个循环中考虑缓存的结果让他们坚持之中请求,因为它伤害了分贝

+0

你能告诉我有关如何缓存一些资源? – Thanh

+0

谢谢,我会看它现在:) – Thanh

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_count@correct_count。尼斯和小帮手现在:)

+0

实际上,'topic_id'改变,这是一个循环,所以我必须来计算不同的主题 – Thanh

+0

你不应该依赖于佣工实例变量,是不好的做法 – apneadiving

+0

这确实发生了改变情况相当多。我有兴趣看看是否有人有一个不涉及在视图或助手中调用模型方法的好解决方案。 –