こういうパターンの場合、集計を別テーブルに入れるのは、あまり筋が良くないと感じます。
大学の成績評価の集計であれば、何万レコードの集計を行う訳ではないので、集計操作の短縮化などの意味はなさそうです。
単純な関連テーブルを作成して、集計はその都度行うのが良いかと。
クラス名など、勝手に想像して書いてみるので、うまい事自分の環境に当てはめて考えてみてください。
Ruby
1# models
2class SchoolClass < ActiveRecord::Base
3 attr_accessor :name
4 has_many :grade_of_classes
5end
6
7class Student < ActiveRecord::Base
8 attr_accessor :name, :student_number, :class_year
9 has_many :grade_of_classes
10end
11
12class GradeOfClass < ActiveRecrod::Base
13 attr_accessor :grade
14 belongs_to :school_class
15 belongs_to :student
16end
17
18# controllers
19# school_class_controllerとstudent_controllerは省略
20class GradeOfClassController < ActionController::Base
21 def new
22 @school_clsses = SchoolClass.all # 成績投入の際の授業一覧
23 end
24
25 def create
26 @grade_of_class = prams[:grade_of_class]
27 # params[:grade_of_class][:school_class_id] 対象クラスのIDを格納
28 # params[:grade_of_class][:grade] 対象クラスの成績を格納
29 @grade_of_class.student = @student # ログイン中の学生はセッション管理ですでにインスタンス化されていると思われ
30 if @grade_of_class.save
31 # レンダラを適当に書く
32 else
33 # 失敗パターンのレンダラを書く
34 end
35 end
36
37 def average_of_classes
38 results = []
39 SchoolClass.all.each do |sc|
40 results << {class: sc, average: sc.grade_of_classes.average(:grade)}
41 # school_classインスタンスにひも付いているgrade_of_classのgrade平均をArelで取得している
42 end
43 end
44end
45
46# view
47# new, createアクションのビューは省略
48
49# result_of_class/average_of_class.html.erb
50<table>
51 <tr><th>科目名</th><th>平均成績</th><tr>
52 <% @results.each do |result| %>
53 <tr><td><%= result[:class].name %></td><td><%= result[:average] %></td></tr>
54 <% end %>
55</table>
とまあ、こんな感じでしょうか。
後は、授業に年度を入れて、複数年で記録できるようにしたり、
StudentクラスとSchoolClassクラスを関連づけするようにして、
自分が取っている授業のみを入力できるようにするとか、そういう風に発展させてゆけば良いかと思います。
あくまで登録用テーブルと、集計のためのまとめテーブルを利用したいのであれば、
登録用テーブルのcreateアクションのところで、トランザクションを張って更新してあげるのがよいでしょうね。
Ruby
1 def create
2 @grade_of_class = prams[:grade_of_class]
3 # params[:grade_of_class][:school_class_id] 対象クラスのIDを格納
4 # params[:grade_of_class][:grade] 対象クラスの成績を格納
5 @grade_of_class.student = @student # ログイン中の学生はセッション管理ですでにインスタンス化されていると思われ
6 @gradeSum = GradeSum.where(GradeSum.arel_table[:school_class_id].eq(params[:grade_of_class][:school_class_id]).first
7 unless @gradeSum
8 @gradeSum = GradeSum.new
9 @gradeSum.school_class_id = params[:grade_of_class][:school_class_id]
10 end
11 @gradeSum.count += 1
12 @gradeSum.grade_sum += params[:grade_of_class][:grade].to_i
13 ActiveRecord::Base.transaction do
14 @grade_of_class.save!
15 @gradeSum.save!
16 rescue
17 # 失敗パターンのレンダラ
18 end
19 # 成功パターンのレンダラ
20 end