Reputation: 714
I have this set of tables (I'm using postgresql)
User (with id, first_name, ....)
Assignment (with id, name, start_date, finish_date,....)
AssignmentUser(with assignment_id, user_id, flag_status)
The flag_status is a boolean that says if a user is still or not in an assignment.
Let's say user1 applies for assignment1, assignment2, assignment3 as follows:
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
Let's say I want to search TODAY the closest start_date of an user's assignment.
I've done this in my User model:
def last_date
self.assignments.where("date < ?", Date.today).max.try(:date)
end
and this
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
And in my view for each user:
User.all.each do |u|
<td> u.first_name </td>
<td> u.last_date </td>
<td> u.last_status </td>
end
It works well but, in my log I see 3 queries for each user (as expected). So my question is: how can I avoid these multiple queries? (I guess it's more like a SQL question than a Rails one)
Upvotes: 1
Views: 231
Reputation: 4877
@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;"
)
Then in your view:
@au.each do |u|
<tr>
<td> u.first_name </td>
<td> u.last_date </td>
<td> u.last_status </td>
</tr>
end
PLEASE NOTE: this is iterating over AssignmentUsers, so if there are any users who are without an assignment they will be missed. IF that isn't good enough (i.e. you don't want to pull back a 2nd list - easily done by User.all(:conditions => "id NOT IN (#{@au.collect(&:user_id}) - then this solution isn't suitable and if that's the case, then i think you're already probably doing it the best way, although i would have changed your methods to scopes - if you want me to show you how that would look let me know.
Upvotes: 1