Loop within a loop within a loop in Ruby on Rails
I want a user of my website to see the average number of responses (1 to 100) that his friends have given him on various questions.
The end result of this method is an array with [question, sum of all answers, number of answers]
3 tables, each with its own controller and model
I have a friends table that stores users and friends.
Then there is a table of questions that only have questions and their IDs.
Finally, I have an Answers table that stores the Friendship ID, Question ID, and Answer.
I found a way to do this (although I haven't tried it yet): I look for friendships with the user and then look for the answers given by each of those friendships, then looping through each question to add it to the final array.
q_and_a = Array.new
friendships = Friendship.find_by_user_id(current_user.id)
friendships.each do |friendship|
answers = Answer.find_by_friendship_id(friendship.id)
answers.each do |answer|
q_and_a.each do |array|
question = Question.find_by_id(answer.question_id)
if array[0] == statement.description
array[1] = array[1] + answer.value
array[2] = array[2] + 1
else
q_and_a << [ question.description, answer.value, 1 ]
end
end
end
end
Its terrible, I hope there is a better way to do this? Moreover, given that the friendship table as well as the answer table must have hundreds of thousands of entries and will continue to grow
Edit As stated below, I had associations, but I didn't use them! rookie mistake. Final working code:
@q_and_a_them = Array.new
user_answers = current_user.friends.collect { |c| c.answers }.flatten
user_answers.each do |a|
question = Question.find_by_id(a.question_id)
if @q_and_a_them.empty?
@q_and_a_them << [ question.description, a.value, 1 ]
else
@q_and_a_them.each do |q|
if q[0] == question.description
q[1] = q[1] + a.value
q[2] = q[2] + 1
else
@q_and_a_them << [ question.description, a.value, 1 ]
end
end
end
end
Plus config on friendship .rb
has_many :relationships
has_many :answers, :through => :relationships
source to share
The internal logic is a little more complicated, but you can reduce one level of depth using # flat_map :
friendships.flat_map { |f| Answer.find_by_friendship_id f.id }.each do |answer|
q_and_a.each do |array|
# Blah blah.
end
end
source to share