如何从模型中返回聚合数据?

时间:2012-02-13 22:10:14

标签: sql ruby-on-rails ruby-on-rails-3 postgresql

我有一个允许用户保存事件的应用程序。我希望能够看到过去一周内哪些事件被保存得最多。为此,我在我的Event模型中创建了一个'趋势'功能,然后尝试在我的视图中访问它。这会返回错误。

_trending.html.erb:

missing attribute: is_public
Extracted source (around line #3):

1: 
2: <% 
3:   events = Event.trending( :timespan => 1.week, :limit => 25 )
4: %>

这是我的活动模型中的趋势功能。我决定用原始SQL(postgres db)编写代码,这样就不会混淆ActiveRecord如何构建我的查询。

event.rb:

def self.trending(options={})
  limit = options[:limit]
  span = options[:timespan]

  earliest_save = (Time.now - span)
  event_sql = %( SELECT events.title, saved_events.event_id, COUNT(user_id) as save_count, MAX(saved_events.created_at) as created 
                 FROM saved_events, events
                 WHERE events.id = saved_events.event_id AND saved_events.is_public = TRUE AND saved_events.created_at >= '#{earliest_save}'
                 GROUP BY saved_events.event_id, events.title
                 ORDER BY save_count DESC, created DESC
                 LIMIT #{limit} )

  find_by_sql( "#{event_sql}" )
end

因此,此函数应返回的行应仅包含字段title,event_id和save_count。为什么要寻找is_public?我得到的印象是它以某种方式期望一个Event对象的实际实例。如果是这种情况,我该如何重写呢?

针对有关is_public:的问题进行更新 is_public绝对是saved_events中的一列。我确实进行了迁移。为了进一步隔离,我从SQL中删除了'AND saved_events.is_public = TRUE',但仍然遇到了同样的错误。 SQL是有效的,我检查它是否在pgAdmin中工作。

2 个答案:

答案 0 :(得分:1)

我认为问题源于find_by_sql的工作方式,如API中所述。

  

如果调用跨越多个表的复杂SQL查询,则SELECT指定的列将是模型的属性,无论它们是否是相应表的列。   http://apidock.com/rails/ActiveRecord/Base/find_by_sql/class

我重写了Rails-way™的查询,并且能够摆脱SELECT语句。这段代码完美无缺。

time_range = (Time.now - span)..Time.now
joins(:saved_events).where( :saved_events => { :created_at => time_range, :is_public => true } )
                    .group( "saved_events.event_id, events.id" )
                    .order( "COUNT(saved_events.user_id) DESC, MAX(saved_events.created_at) DESC" )
                    .limit( limit )

答案 1 :(得分:0)

Nodrog是对的,它正在寻找is_public。 你有没有进行迁移? (并在生产时重新启动),如果该列不存在则删除该行:“saved_events.is_public = TRUE”