I have students who took 'tests', which have 5 'questions'. What I want to do is to show the max 'score' for each question for each test.
Test, Student, Question are all separate table.
class Test < ActiveRecord::Base
has_many :students
end
class Student < ActiveRecord::Base
belongs_to :test
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :students
end
The code that I have:
<% @tests.each do |test| %>
<% max_score = [] %>
<% test.students.collect {|s| s.questions.collect {|q| max_score << q.score}}%>
<tr>
开发者_Python百科 <th><%= test.name %></th>
<th><%= max_score.max %></th
</tr>
<% end %>
However, what this shows is the max score for the whole test.
example)
Math - 95
History - 98
Physics - 100
It does not return the max for each 'question_number' 1 to 5. I want to print the max score for each question for each test.
example)
Math - 1 - 90
Math - 2 - 100
Math - 3 - 88
Math - 4 - 79
Math - 5 - 98
History - 1 - 80
History - 2 - 95
..and so on...
In the Question table it has a column named 'question_number'. I don't know how to use this attribute to get the result I want.
You have your models wrong. Play with this:
class Test < ActiveRecord::Base
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :test
has_many :question_scores
has_many :students, :through => :question_scores
end
class Student < ActiveRecord::Base
has_many :question_scores
has_many :questions, :through => :question_scores
end
class QuestionScore < ActiveRecord::Base
belongs_to :student
belongs_to :question
end
And the code should be something like this:
<% @tests.each do |test| %>
<% test.questions.each do |question| %>
test: <% test.name %>
question: <%= question.name %>
max score: <%= question.question_scores.maximum(:score) %>
<% end %>
<% end %>
If, as your comment suggests, you're unable to alter your class structure then it's going to be a bit ugly. You can still add has_many :through
to clean things up a little bit:
class Test < ActiveRecord::Base
has_many :students
has_many :questions, :through => :students
end
class Student < ActiveRecord::Base
belongs_to :test
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :students
end
then you're going to have to nest iterators...
<% @tests.each do |test| %>
<% 1.upto(5) do |index|
max = test.questions.select {|q|
q.question_number == index }.max_by {|q| q.score } %>
<tr>
<td><%= test.name %></td>
<td><%= index %></td>
<td><%= max.score %></td>
</tr>
<% end %>
<% end %>
One issue with your code as it stands is that you're only outputting a <tr>
once for each test. You want to do it once for each question. A better solution would be to write scopes. Something along the lines of:
class Test < ActiveRecord::Base
has_many :students
has_many :questions, :through => :students
end
class Student < ActiveRecord::Base
belongs_to :test
has_many :questions
end
class Question < ActiveRecord::Base
belongs_to :student
scope :max_score_by_question_number, lambda {|num| where(:question_number => num).maximum(:score) }
end
Then you could do this, which looks nicer
<% @tests.each do |test| %>
<% 1.upto(5) do |index|
max = test.questions.max_score_by_question_number(index) %>
<tr>
<td><%= test.name %></td>
<td><%= index %></td>
<td><%= max.score %></td>
</tr>
<% end %>
<% end %>
精彩评论