Ruby on rails 消除助手模块中的重复代码
我在Ruby on rails 消除助手模块中的重复代码,ruby-on-rails,ruby-on-rails-3,Ruby On Rails,Ruby On Rails 3,我在tests\u 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) %>
tests\u 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 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
如何更好地编写这些方法?在您的模型中:
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
旁注:
- 在助手中执行这种db交互感觉很奇怪
- 我最初考虑过记忆,但ActiveRecord提供了一个内置缓存
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
旁注:
- 在助手中执行这种db交互感觉很奇怪
- 我最初考虑过记忆,但ActiveRecord提供了一个内置缓存
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)
#...
最后,不要让助手通过考试id和主题id,只需通过
@total\u count
和@correct\u count
。好的小助手:)首先,为什么不在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)
#...
最后,不要让助手通过考试id和主题id,只需通过
@total\u count
和@correct\u count
。好的小助手:)在我看来,这些方法应该依赖于您的模型,因为它们的目的是从数据库计算数据。此外,通过在模型层中编写这些方法,可以避免控制器、视图或视图辅助对象中的重复
视图帮助程序只应用于“视图逻辑”方法,这些方法在视图上下文之外没有多大意义
正确的\u问题和比率似乎与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
备忘录是一种“缓存”形式,以避免多次重新计算相同的结果。你可以找到很多关于它的文章。这里有一个很好的例子:
最后,您将在视图中看到以下代码。helper实际上不再需要了,但是您仍然可以编写一个helper方法来构造“correct/total”部分,将ExamResult实例@exam\u 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 %>
/
在我看来,这些方法应该依赖于您的模型,因为它们的目的是从数据库计算数据。此外,通过在模型层中编写这些方法,可以避免控制器、视图或视图辅助对象中的重复
视图帮助程序只应用于“视图逻辑”方法,这些方法在视图上下文之外没有多大意义
正确的\u问题和比率似乎与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
备忘录是一种“缓存”形式,以避免多次重新计算相同的结果。你可以找到很多关于它的文章。这里有一个很好的例子:
最后,您将在视图中看到以下代码。helper实际上不再需要了,但是您仍然可以编写一个helper方法来构造“correct/total”部分,将ExamResult实例@exam\u 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 %>
/
实际上,topic\u id
发生了变化,这是一个循环,因此我必须为不同的主题进行计算。你不应该依赖helpers中的实例变量,糟糕的做法确实会改变情况。我很想知道是否有人有一个好的解决方案,它不涉及在视图或帮助器中调用模型方法。@首先,我建议将实例变量传递给帮助器方法,而不是在帮助器中使用它们。实际上,topic\u id
已更改,它处于循环中,因此,我必须针对不同的主题进行计算。你不应该依赖helpers中的实例变量,糟糕的做法确实会改变很多情况。我很想知道是否有人有一个好的解决方案,它不涉及在视图或帮助器中调用模型方法。@首先,我建议将实例变量传递给帮助器方法,而不是在帮助器中使用它们。好的,我想我必须重写代码以获得更好的效果。当我需要先加载考试答案时,memorization
也可能是我想要解决的问题。非常感谢。好的,我想我必须重写我的代码,以便更好。当我需要先加载考试答案时,memorization
也可能是我想要解决的问题。非常感谢。