Rails 2.3.5
我在3个不同的视图上创建了一个报告(主要,预览和自动电子邮件的无布局纯HTML版本)。该报告使用了大约28个查询,对于其中一些查询,我在查询之前做了一些逻辑:
sunday_this_week = (Time.now.beginning_of_week - 1.days).strftime("%Y-%m-%d")
sunday_1_week_ago = (Time.now.beginning_of_week - 8.days).strftime("%Y-%m-%d")
sunday_2_week_ago = (Time.now.beginning_of_week - 15.days).strftime("%Y-%m-%d")
sunday_3_week_ago = (Time.now.beginning_of_week - 22.days).strftime("%Y-%m-%d")
sunday_4_week_ago = (Time.now.beginning_of_week - 29.days).strftime("%Y-%m-%d")
@sunday_dates = [sunday_this_week,sunday_1_week_ago,sunday_2_week_ago,sunday_3_week_ago,sunday_4_week_ago ]
sql = %Q{
SELECT * FROM report_notes
WHERE week_of IN(?)
ORDER BY week_of ASC, market ASC, measure ASC
}
@performance_metric_notes = RptNote.find_by_sql([ sql, @sunday_dates ])
有些查询非常大,而且由于3个视图需要它们,因此我在三个不同的控制器方法下列出了相同的查询。控制器中有很多行(约1400行)。
你会做什么来重构一些东西(是否可能有一个带有所有查询设置逻辑和查询的单一控制器方法,3种不同的视图方法可以调用而不是每个具有副本的视图方法)?
谢谢!
答案 0 :(得分:2)
我会在单独的Report
课程中提取所有这些代码
将它移动到另一个控制器动作仍然会导致一个巨大的控制器。另外,如果生成报告有很多逻辑,那么控制器操作就不适合它。如果您可以保持控制器清洁,只需为视图准备变量,那就好多了。
只需将您的课程放在/ lib中,并在您的控制器操作中,您可以调用类似
的内容report = Report.new params
@performance_metric_notes = report.performance_metric_notes
@other_performances = report.other_performances
...
你明白了。
答案 1 :(得分:1)
为什么不把它作为方法放在报告模型中?
@performance_metric_notes = RptNote.get_my_custom_report
答案 2 :(得分:1)
正如@Christoph所说,如果涉及到很多逻辑,那么将其作为模型中的一种方法来实现;此外,您可以将其实现为scope:
class RptNote < ActiveRecord::Base
def self.performance_metric_notes( past_weeks = 4 )
# this will calculate the last sundays for this week +
# the nth past weeks, defaults to 4 :
last_sundays = (0..past_weeks).map do |n|
(Time.now.beginning_of_week - (1+n*7).days).strftime("%Y-%m-%d")
end
# this will return a relation. Using an array in a where clause
# renders a SQL IN selector.
self
.where( week_of: last_sundays )
.order( :week_of, :market, :measure )
end
end
...这甚至可以通过添加其他子句来优化结果:
RptNote.performance_metric_notes.where( measure: something )
有关rails 3中关系和查询的详细信息,请参阅Railscasts #215
编辑: wooops,我的不好,只是看到你的问题在轨道上2.逻辑保持不变,除了查询。
还有更多:如果您的控制器操作经常使用它,您可以在控制器上设置before_filter以自动获取记录:
before_filter :fetch_notes
def fetch_notes
@notes = RptNote.performance_metric_notes
end
答案 3 :(得分:0)
在你的模特中:
scope :by_dates, lambda { |dates|
where("week_of IN (#{sunday_dates.join(,)})").
order_by("week_of ASC, market ASC, measure ASC")
}
def self.sunday_dates
sunday_this_week = (Time.now.beginning_of_week - 1.days).strftime("%Y-%m-%d")
sunday_1_week_ago = (Time.now.beginning_of_week - 8.days).strftime("%Y-%m-%d")
sunday_2_week_ago = (Time.now.beginning_of_week - 15.days).strftime("%Y-%m-%d")
sunday_3_week_ago = (Time.now.beginning_of_week - 22.days).strftime("%Y-%m-%d")
sunday_4_week_ago = (Time.now.beginning_of_week - 29.days).strftime("%Y-%m-%d")
[sunday_this_week,sunday_1_week_ago,sunday_2_week_ago,sunday_3_week_ago,sunday_4_week_ago]
end
在你的控制器中:
RptNote.by_dates(RptNote.sunday_dates)