重构冗余回路逻辑

时间:2018-08-03 00:28:20

标签: ruby

我的代码应该从QUIZ(MyQuiz)中获取答案(真),并将其与Root类型进行比较。测验问题具有通过RootProfile关联的类型(名称)。例如,

question.root_profile.name

将返回类似的内容:

{question: "1", name: "ocean", ...}

我应该知道我也有什么类型的答案。

answer.question.root_profile.name

当我从MyQuiz获得所有真实答案时,我可能拥有10个Ocean 6鸟3轮胎。然后,基于此,我计算了每个小测验相对于整个测验的百分位数。如果测验有100个问题,它将计算出10%的海洋,6%的鸟类和3%的轮胎。

代码如下:

module RootServices
  class RootCount

    def initialize (my_quiz)
      @my_quiz = my_quiz
    end

    attr_reader :my_quiz

    def root_counts(root_profile)
      total = []
      all_answers.each do |answer|
        if answer.question.root_profile.name == root_profile.name
          total << answer
        end
      end

      total_percentage = (total.count.to_f / all_answers.count.to_f) * 100
      element = {root_profile_id: root_profile.id, root_profile: root_profile.name, total: total_percentage}
      return element
    end

    def root_branch
      root_branch_total = []

      # Pass root_profile object to root_counts and store in the root_branch_total array of hashes the returned element
      root_profiles.each do |root_profile|
        root_branch_total << root_counts(root_profile)
      end

      return root_branch_total
    end

    def root_profiles
      title = RootProfile.all
    end

    def all_answers
      all_answers = my_quiz.my_answers.where(answer: true)
    end

  end
end

它可以工作,但是有点复杂,循环似乎是多余的。我想知道是否会有更优雅的方法。我的逻辑工作正常,但是我的日志显示来自Answers = true的查询(假设我的测试具有五个true),其中五个查询针对RootProfile,五个查询针对Question Nested。这是一个视觉效果:

SELECT "my_answers".* FROM ...
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
SELECT "my_answers".* FROM ...
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
  SELECT  "questions".* FROM "questions"
  SELECT  "root_profiles".* FROM "root_profiles"
...
3x more

编辑:添加经过修改的代码行

module RootServices
  class RootCount

    def initialize (my_quiz)
      @my_quiz = my_quiz
      @root_profiles = RootProfile.all
      @all_answers = @my_quiz.my_answers.where(answer: true)
    end    

    def root_branch
      root_profiles.map { |root_profile| root_counts(root_profile) }
    end

    private

      attr_reader :my_quiz, :root_profiles, :all_answers

      def root_counts(root_profile)
        answers = matching_answers(root_profile)
        {
          root_profile_id: root_profile.id,
          root_profile: root_profile.name,
          total: percentage_of_total(answers)
        }
      end

      def matching_answers(root_profile)
        all_answers.joins(question: :root_profile).where("root_profiles.name = ?", root_profile.name)
      end

      def percentage_of_total(answers)
        (answers.count.to_f / all_answers.count.to_f) * 100
      end

  end
end

1 个答案:

答案 0 :(得分:2)

首先,我认为您可能会丢失ruby的几个核心概念-最明显的是隐式返回-对于您的代码,这意味着您不需要在return语句在方法的最后,您无需在单行代码中分配给局部变量。 Ruby就是那样的好。

您可以通过将要比较的所有名称收集到一个查询中来减少查询,而不必重复调用answer.question.root_profile.name。此外,您可能应该在SQL中进行选择,而不是立即将其转换为数组。我将为您重构一些方法,以提供一个示例,说明如何更好地做到这一点。类似于以下内容

def root_counts
  answers = matching_answers(root_profile)
  {
    root_profile_id: root_profile.id,
    root_profile: root_profile.name,
    total: percentage_of_total(answers)
  }
end

private

def root_profiles
  RootProfile.all
end

def percentage_of_total(answers)
  (answers.count.to_f / true_answers.count.to_f) * 100
end

def true_answers
  my_quiz.my_answers.where(answer: true)
end

def matching_answers(root_profile)
  true_answers
    .joins(:questions, :root_profiles)
    .where("root_profiles.name = ?", root_profile.name)
end

我不完全理解您正在尝试使用root_branch方法做什么,因为从我看到的结果来看,它正在返回包含(1) all 数据库中RootProfile对象的>,以及(2)包含该root_profile的百分比计数的哈希集合(由root_count方法返回)。我认为您应该对此重新考虑逻辑。

此外,我可能会考虑将root_profiles作为实例变量(您也要使用该类初始化(也带有attr_reader))-因为它将加载整个root_profiles表,因此最好只调用一次