4

介绍

我正在做一个系统,其中我有一个非常简单的布局,仅包含事务(带有基本 CRUD)。每笔交易都有日期、类型、借方金额(减)和贷方金额(加)。想想网上银行对账单,差不多就是这样。

我遇到的问题是让我的控制器保持瘦身并担心可能过度查询数据库。

一个简单的报告示例

  • 所选期间的总借方,例如SUM(debit) as total_debit
  • 所选期间的总学分,例如SUM(credit) as total_credit
  • 总的总数,例如total_credit - total_debit

  • 报告必须允许动态日期范围,例如where(date BETWEEN 'x' and 'y')

  • 日期范围永远不会超过一年,一次最多只能说 1000 个事务/行

所以在我创建的控制器中:

def report
  @d = Transaction.select("SUM(debit) as total_debit").where("date BETWEEN 'x' AND 'y'")
  @c = Transaction.select("SUM(credit) as total_credit").where("date BETWEEN 'x' AND 'y'")
  @t = @c.credit_total - @d.debit_total
end

附加问题信息

我的实际报告有接近 6 或 7 个数据库查询(例如,根据类型 == 1 或类型 == 2 等提取总贷方/借方)并且有更多计算,例如总计某些贷方/借方类型,然后添加和从其他总数中删除这些总数。

我正在尽最大努力坚持“瘦模型,胖控制器”,但我的控制器需要传递给视图的变量数量存在问题。在您创建要传递给视图的变量之前,Rails 似乎非常简单。除了将变量创建线放入控制器并通过将一些查询点点滴滴放入模型中使其“更瘦”之外,我看不出您还能如何做到这一点。

在模型中创建变量然后让控制器将这些变量传递给视图的地方我是否遗漏了什么?

4

2 回答 2

4

在 Activerecord 中编写查询的更惯用的方式可能是:

class Transaction < ActiveRecord::Base
  def self.within(start_date, end_date)
    where(:date => start_date..end_date)
  end

  def self.total_credit
    sum(:credit)
  end

  def self.total_debit
    sum(:debit)
  end
end

这意味着在您的控制器中发出 3 个查询,如果您创建数据库索引并将事务数量和时间范围限制在合理的范围内,这应该不是什么大问题:

@transactions = Transaction.within(start_date, end_date)
@total = @transaction.total_credit - @transaction.total_debit

最后,您还可以使用 Ruby 的Enumerable#reduce方法通过直接遍历从数据库检索到的事务列表来计算您的总数。

@total = @transactions.reduce(0) { |memo, t|  memo + (t.credit - t.debit) }

对于非常小的数据集,这可能会提高性能,因为您只会访问数据库一次。但是,我认为第一种方法更可取,当数据库中的记录数开始增加时,它肯定会提供更好的性能

于 2013-03-17T18:14:35.403 回答
0

我正在为 x 和 y 输入 params[:year_start]/params[:year_end],这样做安全吗?

您永远不应该params[:anything]直接嵌入到查询字符串中。而是使用这种形式:

where("date BETWEEN ? AND ?", params[:year_start], params[:year_end])

我的实际报告可能有接近 5 次数据库调用,然后对这些变量进行 6 或 7 次计算,我是否应该只查询一次日期范围,然后对数组/哈希等进行所有工作?

这有点主观,但我会给你我的意见。通常,扩展应用程序层比扩展数据库层更容易。您目前是否遇到数据库性能问题?如果是这样,请考虑将逻辑移至 Ruby 并将更多资源添加到您的应用程序服务器。如果没有,也许现在担心这个还为时过早。

我真的没有看到如何将大部分工作/计算放入模型中,我了解范围,但是您如何将日期范围放入范围并仍然使用 GET 参数?

你见过has_scope吗?这是一个很棒的 gem,可让您在模型中定义范围并让它们自动应用于控制器操作。我通常将其用于过滤/搜索,但似乎您可能有一个很好的用例。

如果您可以举例说明通过广泛的数据库调用创建数组,然后对该数组进行各种计算,然后将这些变量传递给模板,那就太棒了。

这不适合 Stack Overflow,而且与您在标准 Rails 应用程序中所做的工作相差无几。我会阅读 Rails 指南和一本 Ruby 书,这并不难理解。

于 2013-03-17T16:42:14.173 回答