Rails - Как избежать нескольких запросов на это - PullRequest
1 голос
/ 16 февраля 2012

У меня есть этот набор таблиц (я использую postgresql)

User (with id, first_name, ....)
Assignment (with id, name, start_date, finish_date,....)
AssignmentUser(with assignment_id, user_id, flag_status)

flag_status - это логическое значение, которое сообщает, находится ли пользователь в назначении или нет.

Допустим, пользователь1 применяется для назначения 1, назначения 2, назначения 3 следующим образом:

                        start_date     finish_date   flag_status
user1  assignment1      11-11-11       11-12-11      false
user1  assignment2      01-10-11       01-02-12      true
user1  assignment3      01-01-12       01-03-12      true

Допустим, я хочу искать СЕГОДНЯ ближайшую начальную дату назначения пользователя.

Я сделал это в моей модели User:

  def last_date
    self.assignments.where("date < ?", Date.today).max.try(:date)
  end

и это

def last_status
  AssignmentUser.find_by_assignment_id_and_user_id(Assignment.find_by_date(self.last_date), self.id).flag_status if self.last_date.present?
end

И на мой взгляд для каждого пользователя:

User.all.each do |u|
  <td>   u.first_name   </td>
  <td>   u.last_date   </td>
  <td>   u.last_status  </td>
end

Это работает хорошо, но в моем журнале я вижу 3 запроса для каждого пользователя (как и ожидалось). Итак, мой вопрос: как я могу избежать этих нескольких запросов? (Я думаю, это больше похоже на вопрос SQL, чем на Rails)

1 Ответ

1 голос
/ 16 февраля 2012
@au = AssignmentUsers.find_by_sql(
  "SELECT assignment_users.user_id, MAX(assignment_users.date) as last_date,
   assignment_id, 
   assignments.flag_status,
   users.first_name
  FROM assignment_users
  LEFT JOIN assignments
   ON assignments.id = assignment_id
  LEFT JOIN users
   ON users.id = user_id
  WHERE date < CURDATE()
  GROUP BY user_id;"
 )

Тогда по вашему мнению:

@au.each do |u|
 <tr>
   <td>   u.first_name   </td>
   <td>   u.last_date    </td>
   <td>   u.last_status  </td>
 </tr>
end

ОБРАТИТЕ ВНИМАНИЕ: это итерация по AssignmentUsers, поэтому, если есть пользователи без назначения, они будут пропущены. Если это не достаточно хорошо (то есть вы не хотите возвращать второй список - это легко сделать с помощью User.all (: условие => "id NOT IN (# {@ au.collect (&: user_id}) - тогда это решение не подходит, и если это так, то я думаю, что вы, вероятно, уже делаете это наилучшим образом, хотя я бы изменил ваши методы на прицелы - если вы хотите, чтобы я показал вам, как это будет выглядеть, дайте мне знаю.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...