希望围绕铁轨最佳实践提出一个简单的问题。
让我们保持这种超级简单;说我有一个具有ID,描述和状态的任务模型。
在我的控制器中,我有一个索引操作来返回所有任务
def index
@tasks = Task.all
end
我的问题是,在我看来,假设我想根据其状态在单独的 HTML表格中显示这些任务。
最佳做法是什么?
a)在索引操作中多次查询数据库,即
def index
@draft_tasks = Task.where(status: "Draft")
@approved_tasks = Task.where(status: "Approved")
@closed_tasks = Task.where(status: "Closed")
end
b)查询数据库一次,并在控制器操作中过滤
def index
tasks = Task.all
@draft_tasks = tasks.#somethinghere
@approved_tasks = tasks.#somethinghere
@closed_tasks = tasks.#somethinghere
end
c)在视图中过滤
<% @tasks.each do |k, v| %>
<% some if statement searching for the status I want %>
# Some code to output the table
<%end%>
<%end%>
或
d)还有别的吗?
答案 0 :(得分:3)
这里普遍接受的最佳实践是保持控制器方法的精简并使逻辑不在视图之外。因此,考虑到这一点,一种可行的方法是:
# model
class Task
scope :drafts, where(:status => "Draft")
scope :approved, where(:status => "Approved")
scope :closed, where(:status => "Closed")
end
# controller
def index
@draft_tasks = Task.drafts
@approved_tasks = Task.approved
@closed_tasks = Task.closed
end
这将对数据库进行3次查询,这可能会成为一个性能问题,但如果确实发生了这种情况,您可以在模型级别对其进行优化(例如,通过定义类方法drafts
,{{ 1}}和approved
,其中第一个叫做prefetches everything)。它虽然不那么优雅,所以不要过早优化。
答案 1 :(得分:1)
这是一个很复杂的问题,在我看来没有一个最佳实践。鉴于您已声明的情况(显示每个status
的表格),我将使用以下思维过程:
status
显示不同的标记,我可能会使用案例B. 如果每个status
的标记相同,我通常会倾向于案例C.您可以使用group_by功能:
当页面上的信息量开始变得越来越大,越来越复杂时,您可以开始考虑从控制器中提取一些逻辑并进入另一个对象(此对象的常用术语是presenter
或decorator
)。这可以通过将它与控制器分离并保持控制器“薄”来更轻松地测试一些表示逻辑。但是对于你给出的情况,我会坚持使用选项b或c。
答案 2 :(得分:1)
在任务数量有限的简单情况下,我只会执行一个查询来检索它们,然后按如下方式将它们分开:
tasks = Task.all
@draft_tasks = tasks.select { |x| x.status == 'Draft' }
@approved_tasks = tasks.select { |x| x.status == 'Approved' }
@closed_tasks = tasks.select { |x| x.status == 'Closed' }
此外,根据您的要求的可弯曲性,我甚至可以将它们呈现在具有清晰视觉标记的单个表中,状态是什么(例如背景颜色或图标)。然后甚至没有理由事先将任务分开(但我可以想象这会完全破坏你的UI)。
一旦任务数量变大,上述任何一项都无效,您需要应用分页,并且需要显示三个不同的表(每个状态一个)。
在这种情况下,您需要使用@Ben回答的三个单独的查询。
现在用户界面,我不确定如何一次分页三组不同的数据。因此,我会使用显示所有状态的单个表,并提供过滤状态的选项。在这种情况下,至少对于用户来说,分页意味着什么。
只是我的两分钱,希望这有帮助。
答案 3 :(得分:0)
选项a)似乎更好,因为数据库可以为你和东西缓存查询,所以它应该更快。