我正在建立一个系统,我的布局非常简单,只包含事务(使用基本的CRUD)。每笔交易都有日期,类型,借方金额(减号)和贷方金额(加号)。想想网上银行的声明,这就是它。
我遇到的问题是让我的控制器变瘦,担心可能会过度查询数据库。
SUM(debit) as total_debit
SUM(credit) as total_credit
整体总数,例如total_credit - total_debit
报告必须允许动态日期范围,例如where(date BETWEEN 'x' and 'y')
所以在我创建的控制器中:
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似乎非常简单。除了将变量创建行放入控制器并通过将一些查询位和部分放入模型中而使其“更瘦”之外,我不知道你是怎么做的。
在模型中创建变量然后控制器将这些变量传递给视图时,是否存在我缺少的内容?
答案 0 :(得分: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) }
对于非常小的数据集,这可能会导致更快的性能,因为您只会访问数据库一次。但是,我认为第一种方法更可取,当数据库中的记录数开始增加时,它肯定会提供更好的性能
答案 1 :(得分:0)
我在x和y中加入参数[: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书籍,并不难理解。