Bucle dentro de bucle dentro de bucle en Ruby on Rails

I want the user of my website to see the average of the answers (1 to 100) his friends have given him on different questions.

The final result of this method is an array with [question, sum of all answers, answer count]

3 tables are involved, each one with its own controller and model

I have a table of 'friendships', which stores users and friends.

Then there is a table of questions, which have just the questions and its ids.

Finally I have an answers table, which stores the friendship id, the question id and the answer given.

I found a way to do it (haven't tried it yet though): I look for the friendships of the user, then look for the answers given by each of these friendships, then going through each question to add it to a 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 horrible, I'm hoping there is a better way to do this? Even more considering that the friendships table, as well as the answers table, are bound to have hundreds of thousands of records and will continue to grow

Editar As stated below, I had the associations set up but i was not using them! rookie mistake. The final working code is:

@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 the config on friendship.rb

has_many :relationships
has_many :answers, :through => :relationships

preguntado el 09 de marzo de 12 a las 15:03

Is your backend a traditional SQL database? This does potentially present a problem "at scale", which would lead to potentially optimizing this w/ a separate "friendship_stats" table that is eventually consistent/updated in "near" realtime. -

it is an sqlite3, I'm starting the development. You mean I should have a 'friendship_stats' table that is running the code above in the background all the time? -

Not necessarily "all the time", but at some interval in the background such that users would see a roughly-up-to-date version of this. Much the same way a user's reputation on SO isn't recalculated every time you log in, some things make sense to compute once and cache. -

Que es statement.description? -

statement.description is question.description. Thanks Pete -

2 Respuestas

Bien

friendships.answers.each

should work, given that you have your relationships set up correctly (has_many, belongs_to)

respondido 09 mar '12, 17:03

The inner 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

respondido 09 mar '12, 16:03

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.