gaku_core 0.3.0.pre.0 → 0.3.0.pre.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/javascripts/gaku/courses.js.coffee +20 -0
- data/app/assets/javascripts/gaku/exams.js.coffee +23 -0
- data/app/assets/stylesheets/gaku/bootstrap_and_theme.css.scss +574 -0
- data/app/controllers/gaku/courses/exams/exam_portion_scores_controller.rb +23 -0
- data/app/controllers/gaku/courses/exams_controller.rb +291 -0
- data/app/controllers/gaku/exams_controller.rb +170 -0
- data/app/helpers/gaku/gaku_helper.rb +155 -0
- data/app/models/gaku/enrollment.rb +1 -1
- data/app/models/gaku/exam_portion.rb +9 -0
- data/app/models/gaku/semester_connector.rb +1 -1
- data/app/models/gaku/student.rb +4 -0
- data/app/views/gaku/admin/grading_methods/_form_fields.html.slim +7 -0
- data/app/views/gaku/courses/_form_fields.html.slim +5 -0
- data/app/views/gaku/courses/exams/exam_portion_scores/update.js.erb +5 -0
- data/app/views/gaku/courses/exams/grading/_calculations.html.slim +16 -0
- data/app/views/gaku/courses/exams/grading/_exam_portion_score_form.htmls.lim +0 -0
- data/app/views/gaku/courses/exams/grading/_exam_scores.html.slim +78 -0
- data/app/views/gaku/courses/exams/grading/_students.html.slim +12 -0
- data/app/views/gaku/courses/exams/grading.html.slim +38 -0
- data/app/views/gaku/layouts/gaku.html.slim +25 -0
- data/app/views/gaku/shared/menu/_global.html.erb +1 -1
- data/config/locales/bg.yml +421 -413
- data/config/locales/en.yml +53 -110
- data/config/locales/ja.yml +891 -883
- data/config/locales/pt-BR.yml +11 -3
- data/config/locales/zh-CN.yml +9 -1
- data/config/routes.rb +120 -5
- data/db/migrate/20160209100945_add_score_types_to_exam_portions.rb +6 -0
- data/db/migrate/20160209104713_add_fields_to_exam_portion_score.rb +6 -0
- data/lib/gaku/grading/single/percentage.rb +3 -3
- data/lib/gaku/grading/single/score.rb +3 -3
- data/lib/gaku/testing/factories/exam_portion_factory.rb +1 -1
- metadata +20 -2
@@ -0,0 +1,291 @@
|
|
1
|
+
module Gaku
|
2
|
+
class Courses::ExamsController < GakuController
|
3
|
+
|
4
|
+
respond_to :html
|
5
|
+
|
6
|
+
|
7
|
+
def grading
|
8
|
+
|
9
|
+
def init_variables
|
10
|
+
@course = Course.find(params[:course_id])
|
11
|
+
@exam = Exam.find(params[:id])
|
12
|
+
@students = @course.students
|
13
|
+
if params[:id] != nil
|
14
|
+
@exams = Exam.find_all_by_id(params[:id])
|
15
|
+
else
|
16
|
+
@exams = @course.syllabus.exams.all
|
17
|
+
end
|
18
|
+
|
19
|
+
# 試験の平均点を入れるハッシュ
|
20
|
+
@exams_average = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc)}
|
21
|
+
|
22
|
+
# 試験の合計点を入れるハッシュ
|
23
|
+
@student_exams_total_score = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc)}
|
24
|
+
|
25
|
+
# 偏差値を入れるハッシュ
|
26
|
+
@student_exams_deviation = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc)}
|
27
|
+
|
28
|
+
# for grade and rank--------
|
29
|
+
# 10段階用の設定
|
30
|
+
# @student_exams_grade: 生徒の10段階を入れるHash。
|
31
|
+
@student_exams_grade = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc)}
|
32
|
+
|
33
|
+
# 5段階用の設定
|
34
|
+
# @student_exams_rank: 生徒の5段階を入れるHash。
|
35
|
+
@student_exams_rank = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc)}
|
36
|
+
end
|
37
|
+
|
38
|
+
def set_student_exams_total_scores_and_set_exams_average
|
39
|
+
@exams.each do |exam|
|
40
|
+
@students.each do |student|
|
41
|
+
|
42
|
+
# 素点用と得点用変数の初期化 --------
|
43
|
+
@student_exams_total_score[:raw][exam.id][student.id] = 0.0
|
44
|
+
@student_exams_total_score[exam.id][student.id] = 0.0
|
45
|
+
|
46
|
+
@exams_average[:raw][exam.id] = 0.0
|
47
|
+
@exams_average[exam.id] = 0.0
|
48
|
+
|
49
|
+
exam.exam_portions.each do |portion|
|
50
|
+
seps = student.exam_portion_scores.where(exam_portion_id: portion.id).first.score.to_f
|
51
|
+
|
52
|
+
@student_exams_total_score[:raw][exam.id][student.id] += seps
|
53
|
+
if exam.use_weighting
|
54
|
+
@student_exams_total_score[exam.id][student.id] += (portion.weight.to_f / 100) * seps
|
55
|
+
else
|
56
|
+
@student_exams_total_score[exam.id][student.id] += seps
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# calc for average --------
|
61
|
+
@exams_average[:raw][exam.id] += @student_exams_total_score[:raw][exam.id][student.id]
|
62
|
+
@exams_average[exam.id] += @student_exams_total_score[exam.id][student.id]
|
63
|
+
end
|
64
|
+
|
65
|
+
# set Exams Average --------
|
66
|
+
if exam === @exams.last
|
67
|
+
@exams_average[:raw][exam.id] = fix_digit @exams_average[:raw][exam.id] / @students.length, 4
|
68
|
+
@exams_average[exam.id] = fix_digit @exams_average[exam.id] / @students.length, 4
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def set_student_exams_deviaton
|
74
|
+
|
75
|
+
def get_standard_deviation exam
|
76
|
+
scratch_standard_deviation = 0.0
|
77
|
+
@students.each do |student|
|
78
|
+
scratch_standard_deviation += (@student_exams_total_score[exam.id][student.id] - @exams_average[exam.id]) ** 2
|
79
|
+
end
|
80
|
+
return Math.sqrt scratch_standard_deviation / @students.length
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_deviation standard_deviation, exam, student
|
84
|
+
scratch_deviation = (@student_exams_total_score[exam.id][student.id] - @exams_average[exam.id]) / standard_deviation
|
85
|
+
if scratch_deviation.nan?
|
86
|
+
return 50
|
87
|
+
else
|
88
|
+
return fix_digit @student_exams_deviation[exam.id][student.id] * 10 + 50, 4
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# start main --------
|
93
|
+
@exams.each do |exam|
|
94
|
+
standard_deviation = get_standard_deviation(exam)
|
95
|
+
|
96
|
+
# set deviations --------
|
97
|
+
@students.each do |student|
|
98
|
+
@student_exams_deviation[exam.id][student.id] = get_deviation(standard_deviation, exam, student)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def set_student_exams_grade_and_rank
|
104
|
+
|
105
|
+
# def method_ratio(grading_method)
|
106
|
+
def method_ratio
|
107
|
+
default_grade_level_deviation = [100, 66, 62, 58, 55, 50, 45, 37, 0]
|
108
|
+
@rank_level = [15, 20]
|
109
|
+
|
110
|
+
# default_grade_level_percent = [5, 5, 10, 10, 30, 10, 100]
|
111
|
+
|
112
|
+
default = {
|
113
|
+
# for grade ----
|
114
|
+
g10: 100,
|
115
|
+
g9: 66,
|
116
|
+
g8: 62,
|
117
|
+
|
118
|
+
# for rank----
|
119
|
+
r10: 5,
|
120
|
+
r9: 5,
|
121
|
+
r8: 10
|
122
|
+
}
|
123
|
+
|
124
|
+
default = {
|
125
|
+
grade:{
|
126
|
+
g10: 100,
|
127
|
+
g9: 66,
|
128
|
+
g8: 62
|
129
|
+
},
|
130
|
+
rank: {
|
131
|
+
r10: 5,
|
132
|
+
r9: 5,
|
133
|
+
r8: 10
|
134
|
+
}
|
135
|
+
}
|
136
|
+
|
137
|
+
# @grade_level_deviation:
|
138
|
+
# 10段階の全体評価で判定する時に使う変数。
|
139
|
+
# 決められた偏差値を基に、生徒の偏差値と比べ、その多寡で評価を行う。
|
140
|
+
# @grade_level_percent:
|
141
|
+
# 10段階の相対評価で判定する時に使う変数。
|
142
|
+
# 決められたパーセンテージを元に、生徒がクラス内で上位何%以内かを調べ、評価を行う。
|
143
|
+
|
144
|
+
@ = JSON.parse grading_method.method.arguments, symbolize_names: true
|
145
|
+
|
146
|
+
@grade_level_deviation = [100, 66, 62, 58, 55, 50, 45, 37, 0]
|
147
|
+
@grade_level_percent = [5, 5, 10, 10, 30, 10, 100]
|
148
|
+
|
149
|
+
# @rank_level: 5段階を付ける時に使うパーセンテージ配列の変数。
|
150
|
+
@rank_level = [15, 20]
|
151
|
+
|
152
|
+
|
153
|
+
|
154
|
+
# Grade and Rank Calculation (ここは別途光ヶ丘の生徒評価表を参照して下さい)-------- {
|
155
|
+
# set grade and rank --------
|
156
|
+
@exams.each do |exam|
|
157
|
+
|
158
|
+
# 生徒の順位用配列を作成
|
159
|
+
exam_student_scores = Hash.new{|h,k| h[k]=Hash.new(&h.default_proc)} # 生徒の順位を出す為の変数。
|
160
|
+
|
161
|
+
# 試験毎の合計点数と生徒IDをexam_student_scoresに格納する。
|
162
|
+
@students.each do |student|
|
163
|
+
exam_student_scores[student.id] = @student_exams_total_score[exam.id][student.id]
|
164
|
+
end
|
165
|
+
# 試験のスコアを降順に並び替える
|
166
|
+
exam_student_scores = exam_student_scores.sort_by {|key,val| -val}
|
167
|
+
|
168
|
+
# 採点方式を選択、その採点方式でGradeを決定。
|
169
|
+
grading_method = 1
|
170
|
+
grade_point = 10
|
171
|
+
|
172
|
+
case grading_method
|
173
|
+
|
174
|
+
# calc for 全体評価
|
175
|
+
when 1
|
176
|
+
@grade_level_deviation.each_with_index do |glevel, i|
|
177
|
+
@students.each do |student|
|
178
|
+
if @grade_level_deviation[i] > @student_exams_deviation[exam.id][student.id] && @grade_level_deviation[i+1] <= @student_exams_deviation[exam.id][student.id]
|
179
|
+
@student_exams_grade[exam.id][student.id] = grade_point
|
180
|
+
end
|
181
|
+
end
|
182
|
+
grade_point -= 1
|
183
|
+
end
|
184
|
+
|
185
|
+
# calc for 相対評価
|
186
|
+
when 2
|
187
|
+
scratch_exam_student_scores = exam_student_scores.clone
|
188
|
+
grade_limit_nums = []
|
189
|
+
@grade_level_percent.each do |glevel|
|
190
|
+
grade_limit_nums.push((@students.length * (glevel.to_f / 100)).ceil)
|
191
|
+
end
|
192
|
+
grade_limit_nums.each do |gnum|
|
193
|
+
i = 0
|
194
|
+
while i < gnum && scratch_exam_student_scores.length != 0
|
195
|
+
@student_exams_grade[exam.id][scratch_exam_student_scores.shift[0]] = grade_point
|
196
|
+
i += 1
|
197
|
+
end
|
198
|
+
grade_point -= 1
|
199
|
+
end
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
# Rank Calculation --------
|
204
|
+
# rankPoint = 5
|
205
|
+
# @students.each do |student|
|
206
|
+
# @student_exams_rank[exam.id][student.id] = 3
|
207
|
+
# end
|
208
|
+
# rankNums = []
|
209
|
+
# @rank_level.each do |rlevel|
|
210
|
+
# rankNums.push((@students.length * (rlevel.to_f / 100)).ceil)
|
211
|
+
# end
|
212
|
+
# rankNums.each do |rnum|
|
213
|
+
# i = 0
|
214
|
+
# while i < rnum && exam_student_scores.length != 0
|
215
|
+
# scoreMem = exam_student_scores.shift()
|
216
|
+
# @student_exams_rank[exam.id][scoreMem[1]] = rankPoint
|
217
|
+
# if exam_student_scores.length != 0 and scoreMem[0] == exam_student_scores[0][0]
|
218
|
+
# rnum += 1
|
219
|
+
# end
|
220
|
+
# i += 1
|
221
|
+
# end
|
222
|
+
# rankPoint -= 1
|
223
|
+
# end
|
224
|
+
# exam_student_scores.each do |score|
|
225
|
+
# if @student_exams_grade[exam.id][socre[1]] == 3
|
226
|
+
# @student_exams_rank[exam.id][score[1]] = 2
|
227
|
+
# elsif @student_exams_grade[exam.id][socre[1]] < 3
|
228
|
+
# @student_exams_rank[exam.id][score[1]] = 1
|
229
|
+
# end
|
230
|
+
# end
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
# start main --------
|
235
|
+
# p '@exam.grading_method.method -------'
|
236
|
+
# p @exam.grading_method
|
237
|
+
|
238
|
+
# case @exam.grading_method.method
|
239
|
+
case "ratio"
|
240
|
+
|
241
|
+
when "ratio"
|
242
|
+
# method_ratio(@exam.grading_method)
|
243
|
+
# method_ratio()
|
244
|
+
method = Grading::Ratio.new (arguments)
|
245
|
+
|
246
|
+
exam.student_score.each do |student|
|
247
|
+
results << method.grade (student, exam)
|
248
|
+
end
|
249
|
+
|
250
|
+
return results
|
251
|
+
|
252
|
+
|
253
|
+
end
|
254
|
+
|
255
|
+
end
|
256
|
+
|
257
|
+
def fix_digit num, digit_num
|
258
|
+
for_fix = 10 ** digit_num
|
259
|
+
num = num * for_fix
|
260
|
+
if num.nan?
|
261
|
+
num = 0
|
262
|
+
else
|
263
|
+
num = num.truncate.to_f / for_fix.to_f
|
264
|
+
end
|
265
|
+
return num
|
266
|
+
end
|
267
|
+
|
268
|
+
# start main --------
|
269
|
+
init_variables()
|
270
|
+
init_portion_scores()
|
271
|
+
set_student_exams_total_scores_and_set_exams_average()
|
272
|
+
set_student_exams_deviaton()
|
273
|
+
set_student_exams_grade_and_rank()
|
274
|
+
|
275
|
+
respond_with @exam
|
276
|
+
end
|
277
|
+
|
278
|
+
private
|
279
|
+
|
280
|
+
def init_portion_scores
|
281
|
+
@students.each do |student|
|
282
|
+
@exam.exam_portions.each do |portion|
|
283
|
+
unless portion.exam_portion_scores.pluck(:student_id).include?(student.id)
|
284
|
+
ExamPortionScore.create!(exam_portion: portion, student: student)
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
end
|
@@ -0,0 +1,170 @@
|
|
1
|
+
module Gaku
|
2
|
+
class ExamsController < GakuController
|
3
|
+
|
4
|
+
respond_to :html, :js, :json
|
5
|
+
respond_to :xls, only: :export
|
6
|
+
|
7
|
+
include Gaku::Grading::Calculations
|
8
|
+
|
9
|
+
before_action :set_exam, only: %i( show edit update soft_delete )
|
10
|
+
before_action :set_unscoped_exam, only: %i( destroy recovery )
|
11
|
+
before_action :load_data, only: %i( new edit )
|
12
|
+
|
13
|
+
def index
|
14
|
+
if params[:course_id]
|
15
|
+
@exams = Course.find(params[:course_id]).syllabus.exams
|
16
|
+
else
|
17
|
+
@exams = Exam.all
|
18
|
+
@exam = Exam.new
|
19
|
+
end
|
20
|
+
|
21
|
+
@exam.exam_portions.build
|
22
|
+
set_count
|
23
|
+
respond_to do |format|
|
24
|
+
format.html
|
25
|
+
format.json { render json: @exams.as_json(include: {exam_portions: {include: :exam_portion_scores}})}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def show
|
30
|
+
respond_with @exam
|
31
|
+
end
|
32
|
+
|
33
|
+
def new
|
34
|
+
@exam = Exam.new
|
35
|
+
@master_portion = @exam.exam_portions.new
|
36
|
+
respond_with @exam
|
37
|
+
end
|
38
|
+
|
39
|
+
def create
|
40
|
+
@exam = Exam.create(exam_params)
|
41
|
+
@exam.save
|
42
|
+
set_count
|
43
|
+
respond_with @exam
|
44
|
+
end
|
45
|
+
|
46
|
+
def edit
|
47
|
+
respond_with @exam
|
48
|
+
end
|
49
|
+
|
50
|
+
def update
|
51
|
+
@exam.update(exam_params)
|
52
|
+
respond_with @exam, location: [:edit, @exam]
|
53
|
+
end
|
54
|
+
|
55
|
+
def destroy
|
56
|
+
@exam.destroy
|
57
|
+
set_count
|
58
|
+
respond_with @exam
|
59
|
+
end
|
60
|
+
|
61
|
+
def recovery
|
62
|
+
@exam.recover
|
63
|
+
respond_with @exam
|
64
|
+
end
|
65
|
+
|
66
|
+
def soft_delete
|
67
|
+
@exam.soft_delete
|
68
|
+
respond_with @exam, location: exams_path
|
69
|
+
end
|
70
|
+
|
71
|
+
def export
|
72
|
+
@course = Course.find(params[:course_id])
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# def grading
|
77
|
+
# @course = Course.find(params[:course_id])
|
78
|
+
# @exam = Exam.find(params[:id])
|
79
|
+
# @students = @course.students
|
80
|
+
|
81
|
+
# respond_with @exam
|
82
|
+
# find_exams
|
83
|
+
|
84
|
+
# calculate_totals
|
85
|
+
# calculate_exam_averages
|
86
|
+
# calculate_deviation
|
87
|
+
# calculate_rank_and_grade
|
88
|
+
|
89
|
+
# @path_to_exam = course_path(id: params[:course_id])
|
90
|
+
|
91
|
+
# #exam_portions need reload to properly include exam_portion_score in as_json
|
92
|
+
# @exams.each { |exam| exam.exam_portions.reload }
|
93
|
+
|
94
|
+
# respond_to do |format|
|
95
|
+
# format.json do render json: {
|
96
|
+
# student_total_scores: @student_total_scores.as_json,
|
97
|
+
# exams: @exams.as_json(include: {exam_portions: {include: :exam_portion_scores }},root: false),
|
98
|
+
# course: @course.as_json(root: false),
|
99
|
+
# exam_averages: @exam_averages.as_json(root: false),
|
100
|
+
# deviation: @deviation.as_json(root: false),
|
101
|
+
# students: @students.to_json(root: false),
|
102
|
+
# grades: @grades.as_json(root: false),
|
103
|
+
# ranks: @ranks.as_json(root: false),
|
104
|
+
# attendances: @student_portion_attendance.as_json(root: true, include: :attendance_type),
|
105
|
+
# path_to_exam: @path_to_exam.to_json,
|
106
|
+
# completion: @completion
|
107
|
+
# }end
|
108
|
+
# format.html { render 'gaku/exams/grading' }
|
109
|
+
# end
|
110
|
+
# end
|
111
|
+
|
112
|
+
def completed
|
113
|
+
@exam = Exam.find(params[:id])
|
114
|
+
@course = Course.find(params[:course_id])
|
115
|
+
@students = @course.students
|
116
|
+
|
117
|
+
|
118
|
+
respond_with @exam.completed_by_students(@students)
|
119
|
+
end
|
120
|
+
|
121
|
+
protected
|
122
|
+
|
123
|
+
def exam_params
|
124
|
+
params.require(:exam).permit(attributes)
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def load_data
|
130
|
+
@departments = Department.all
|
131
|
+
end
|
132
|
+
|
133
|
+
def t_resource
|
134
|
+
t(:'exam.singular')
|
135
|
+
end
|
136
|
+
|
137
|
+
def attributes
|
138
|
+
[:name, :department_id, :weight, :description, :adjustments, :use_weighting,
|
139
|
+
exam_portions_attributes: [:id, :name, :weight, :problem_count, :max_score, :description, :adjustments]
|
140
|
+
]
|
141
|
+
end
|
142
|
+
|
143
|
+
def set_exam
|
144
|
+
@exam = Exam.find(params[:id])
|
145
|
+
set_notable
|
146
|
+
end
|
147
|
+
|
148
|
+
def set_unscoped_exam
|
149
|
+
@exam = Exam.unscoped.find(params[:id])
|
150
|
+
set_notable
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_notable
|
154
|
+
@notable = @exam
|
155
|
+
@notable_resource = @notable.class.to_s.underscore.split('/')[1].gsub('_','-')
|
156
|
+
end
|
157
|
+
|
158
|
+
def set_count
|
159
|
+
@count = Exam.count
|
160
|
+
end
|
161
|
+
|
162
|
+
def find_exams
|
163
|
+
if params[:id] != nil
|
164
|
+
@exams = Exam.where(id: params[:id])
|
165
|
+
else
|
166
|
+
@exams = @course.syllabus.exams
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module Gaku
|
2
|
+
module GakuHelper
|
3
|
+
|
4
|
+
include SortHelper
|
5
|
+
include TranslationsHelper
|
6
|
+
include FlashHelper
|
7
|
+
|
8
|
+
def broadcast(channel, &block)
|
9
|
+
message = {:channel => channel, :data => capture(&block)}
|
10
|
+
uri = URI.parse("http://localhost:9292/faye")
|
11
|
+
Net::HTTP.post_form(uri, :message => message.to_json)
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def tr_for(resource, &block)
|
16
|
+
content_tag :tr, id: "#{resource.class.to_s.demodulize.underscore.dasherize}-#{resource.id}" do
|
17
|
+
block.call
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def current_parent_controller
|
22
|
+
controller.controller_path.split('/').second
|
23
|
+
end
|
24
|
+
|
25
|
+
def current_controller_action
|
26
|
+
controller.action_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def drag_field
|
30
|
+
content_tag :td, class: 'sort-handler' do
|
31
|
+
content_tag :i, nil, class: 'icon-move'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def can_edit?
|
36
|
+
if controller.action_name.include?('edit')
|
37
|
+
true
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def cannot_edit?
|
44
|
+
! can_edit?
|
45
|
+
end
|
46
|
+
|
47
|
+
def genders
|
48
|
+
{ t(:'gender.female') => false, t(:'gender.male') => true }
|
49
|
+
end
|
50
|
+
|
51
|
+
def style_semester(date)
|
52
|
+
date.strftime('')
|
53
|
+
end
|
54
|
+
|
55
|
+
def required_field
|
56
|
+
content_tag :span, t(:required), class: 'label label-important pull-right'
|
57
|
+
end
|
58
|
+
|
59
|
+
def render_js_partial(partial, locals = {})
|
60
|
+
unless locals == {}
|
61
|
+
escape_javascript(render partial: partial, formats: [:html], handlers: [:erb, :slim], locals: locals)
|
62
|
+
else
|
63
|
+
escape_javascript(render partial: partial, formats: [:html], handlers: [:erb, :slim])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def title(text)
|
68
|
+
content_for(:title) do
|
69
|
+
text
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def color_code(color)
|
74
|
+
content_tag :div, nil, style: "width:100px;height:20px;background-color:#{color}"
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
|
79
|
+
def comma_separated_list(objects, &block)
|
80
|
+
if objects.any?
|
81
|
+
objects.map do |object|
|
82
|
+
block_given? ? block.call(object) : object
|
83
|
+
end.join(', ').html_safe
|
84
|
+
else
|
85
|
+
t(:empty)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def prepare_target(nested_resource, address)
|
90
|
+
return nil if nested_resource.blank?
|
91
|
+
[nested_resource, address].flatten
|
92
|
+
end
|
93
|
+
|
94
|
+
def prepare_resource_name(nested_resources, resource)
|
95
|
+
@resource_name = [nested_resources.map {|r| r.is_a?(Symbol) ? r.to_s : get_class(r) }, resource.to_s].flatten.join '-'
|
96
|
+
end
|
97
|
+
|
98
|
+
def exam_completion_info(exam)
|
99
|
+
@course_students ||= @course.students
|
100
|
+
ungraded = exam.ungraded(@course_students)
|
101
|
+
total = exam.total_records(@course_students)
|
102
|
+
|
103
|
+
percentage = number_to_percentage exam.completion(@course_students), precision: 2
|
104
|
+
|
105
|
+
"#{t(:'exam.completion')}:#{percentage} #{t(:'exam.graded')}:#{total - ungraded} #{t(:'exam.ungraded')}:#{ungraded} #{t(:'exam.total')}:#{total}"
|
106
|
+
end
|
107
|
+
|
108
|
+
def datepicker_date_format(date)
|
109
|
+
date ? date.strftime('%Y-%m-%d') : Time.now.strftime('%Y-%m-%d')
|
110
|
+
end
|
111
|
+
|
112
|
+
def extract_grouped(grouped, resource)
|
113
|
+
grouped.map(&resource.to_sym)
|
114
|
+
end
|
115
|
+
|
116
|
+
def nested_header(text)
|
117
|
+
content_tag :h4, text
|
118
|
+
end
|
119
|
+
|
120
|
+
def state_load(object)
|
121
|
+
object.country.nil? ? Gaku::State.none : object.country.states
|
122
|
+
end
|
123
|
+
|
124
|
+
def disabled?(object)
|
125
|
+
object.new_record? || object.country.states.blank?
|
126
|
+
end
|
127
|
+
|
128
|
+
def link_to_download(resource, options = {})
|
129
|
+
name = content_tag(:span, nil, class: 'glyphicon glyphicon-download')
|
130
|
+
attributes = {
|
131
|
+
class: "btn btn-xs btn-success download-link"
|
132
|
+
}.merge(options)
|
133
|
+
link_to name, resource, attributes
|
134
|
+
end
|
135
|
+
|
136
|
+
def ajax_link_to_recovery(resource, options = {})
|
137
|
+
name = content_tag(:span, nil, class: 'glyphicon glyphicon-repeat')
|
138
|
+
attributes = {
|
139
|
+
remote: true,
|
140
|
+
class: "btn btn-xs btn-success recovery-link"
|
141
|
+
}.merge(options)
|
142
|
+
link_to name, resource, attributes
|
143
|
+
end
|
144
|
+
|
145
|
+
def icon(name)
|
146
|
+
content_tag(:span, nil, class: "#{name}")
|
147
|
+
end
|
148
|
+
|
149
|
+
def icon_label(icon_name, label)
|
150
|
+
raw %{ #{icon(icon_name)} #{label} }
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
@@ -26,6 +26,9 @@ module Gaku
|
|
26
26
|
after_destroy :refresh_positions
|
27
27
|
|
28
28
|
before_update :weight_calculate
|
29
|
+
before_save :sanitize_score_selection_options
|
30
|
+
|
31
|
+
enum score_type: %i( score score_selection score_text )
|
29
32
|
|
30
33
|
def to_s
|
31
34
|
name
|
@@ -68,6 +71,12 @@ module Gaku
|
|
68
71
|
|
69
72
|
private
|
70
73
|
|
74
|
+
def sanitize_score_selection_options
|
75
|
+
if self.score_selection_options
|
76
|
+
self.score_selection_options = self.score_selection_options.reject(&:blank?)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
71
80
|
def proper_position
|
72
81
|
self.position = exam.exam_portions.count
|
73
82
|
end
|
@@ -7,7 +7,7 @@ module Gaku
|
|
7
7
|
validates :semester_id, :semesterable_type, :semesterable_id, presence: true
|
8
8
|
|
9
9
|
validates :semester_id,
|
10
|
-
uniqueness: { scope: %
|
10
|
+
uniqueness: { scope: %i( semesterable_id semesterable_type ), message: I18n.t(:'semester.already') }
|
11
11
|
|
12
12
|
validates :semesterable_type,
|
13
13
|
inclusion: { in: %w( Gaku::ClassGroup Gaku::Course ), message: '%{value} is not a valid' }
|
data/app/models/gaku/student.rb
CHANGED
@@ -0,0 +1,7 @@
|
|
1
|
+
= f.text_field :name, label: t(:'grading_method.name')
|
2
|
+
= f.text_field :description, label: t(:'grading_method.description')
|
3
|
+
|
4
|
+
/= f.text_field :method, label: t(:'grading_method.method')
|
5
|
+
= f.select :method, {"Score" => "score", "Percentage" => "percentage", "Ordinal" => "ordinal", "Interval" => "interval", "Ratio" => "ratio", "Pass/Fail" => "pass_fail"}, {prompt: "メソッドを選択してください"} , class: "form-control"
|
6
|
+
|
7
|
+
= render 'arguments_form_fields', f: f
|