gaku_core 0.3.0.pre.0 → 0.3.0.pre.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|