如何在Rails中重构这个模型逻辑

时间:2014-12-30 22:09:58

标签: ruby-on-rails model refactoring rails-activerecord

我有老师模特,有很多学生。然后学生有很多科目。 基于这种关系,我需要准备一份报告..

这里我只是通过includes语句组合每个实体,然后循环以获取所需格式的数据(哈希数组)。

#teacher.rb

      def get_students_report
        teachers = Teacher.includes(students: :subjects)

        final_result = []
        teachers.each do |teacher|
          students = teacher.students
          teacher_name = teacher.full_name
          classes_taken = teacher.classes_count 

          students.each do |student|
            student_name = student.name
            attendance = (student.days_attended/classes_taken.to_f) * 100.0
            subjects = student.subjects
            final_result = 0
            subject_total = subjects.sum(:marks_obtained)
            #show in percentage
            mark_in_percentage = (subject_total * 100)/subjects.sum(:maximum_mark).to_f 

            students_record = {
              student_name: student_name
              teacher_name: teacher_name
              attendance: attendance, 
              subject_total: subject_total
              subject_percentage: mark_in_percentage
            }
            final_result.push student_record

         end #end of student loop
        end #end of teacher loop
      end  #end of method.

以上解决方案正常。但我觉得这有以下缺陷: - 这个方法太大了,将来如果我需要更多的列,那么这将会增长更多。 - 代码无法很好地维护。

我们能有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

假设教师has_many学生和学生belongs_to是教师,您可以执行以下操作:

<强> Teacher.rb

has_many :students, inverse_of: :teacher

def self.get_students_report
  self.includes(student: :subjects).map(&:students_reports).flatten
end

def students_reports
  students.map(&:record).flatten
end

<强> Student.rb

belongs_to :teacher, inverse_of: :students

def record
  {
    student_name: name,
    teacher_name: teacher.name,
    attendance: attendance, 
    subject_total: subject_total,
    subject_percentage: mark_in_percentage
  }
end

private

def attendance
  (student.days_attended/classes_taken.to_f) * 100.0
end

def classes_taken
  teacher.classes_count
end

def subject_total
  subjects.sum(:marks_obtained)
end

def mark_in_percentage
  (subject_total * 100)/subjects.sum(:maximum_mark).to_f
end