我正在花一点时间跟踪应用程序并遇到了一个我不知道如何解决的问题。我有一个Task
模型和一个Client
模型。每个任务都属于一个客户端。
class Task < ActiveRecord::Base
belongs_to :client
attr_accessible :client_id, :description, :start, :end
scope :yesterday, -> {
where('start > ?', Date.yesterday.to_time).where('start < ?', Date.today.to_time)
}
end
class Client < ActiveRecord::Base
attr_accessible :name
has_many :tasks
end
现在我正在显示任务完成当天确定的任务列表,并在完成任务之前进行排序。我想显示相同的列表,但按客户端分组,并按客户端名称排序。这就是我想做的事情:
<div id="yesterday_summary">
<% @yesterday_clients.each do |client| %>
<h2><%= client.name %></h2>
<ul>
<% client.tasks.each do |task| %>
<li><%= task.description %></li>
<% end %>
</ul>
<% end %>
</div>
在我的控制器中,我目前有:
@tasks_yesterday = Task.yesterday
@yesterday_clients = group_tasks_by_client @tasks_yesterday
在group_tasks_by_client
方法中,我有一些非常丑陋的代码,目前还没有工作:
def group_tasks_by_client(tasks)
clients = []
tasks.collect(&:client).each do |client|
clients << {client.id => client} unless clients.has_key? client.id
end
clients_with_tasks = []
clients.each do |client|
c = Struct.new(:name, :tasks)
cl = c.new(client.name, [])
tasks.each do |task|
cl.tasks << task if task.client_id = client.id
end
clients_with_tasks << cl
end
clients_with_tasks
end
我确信有一个干净,简单的轨道方式可以做到这一点,但我不确定如何。怎么办呢?
答案 0 :(得分:8)
您可以让数据库为您执行此操作:
@yesterdays_clients = Client.includes(:tasks).merge(Task.yesterday).order(:name)
除了更清洁之外,它更高效,因为它可以一次性获取所有客户和任务。原始代码受N + 1个查询限制,因为没有急切的加载。
顺便说一下,你也可以让你的范围更简单:
scope :yesterday, -> { where(:start => (Date.yesterday.to_time...Date.today.to_time)) }