Rails - group_by

时间:2011-02-09 18:53:50

标签: ruby-on-rails activerecord group-by

我的应用程序有一些报告,我正在尝试为group_by为所有这些集合创建一个帮助方法。

示例:

def group_collection(collection, options = {})
    column = options[:column]
    group_count = collection.group_by{ |item| item.column.strftime('%b %y')}
end

这就是我打算如何使用它

@user_groups = group_collection(@users, :column => "created_at")

不幸的是,这不起作用。

undefined method `column' for... [CollectionObject]

有关如何在运行时将“column”变量设置为实际列类型的任何线索,因此它将自身视为activerecord列而不是实例方法?

2 个答案:

答案 0 :(得分:21)

忽略代码中的其他一些问题,您尝试使用column执行的操作可以这样做:

collection.group_by { |item| item.send(column).strftime('%b %y') }

这是有效的,因为在Ruby中,访问实例变量的方式是通过访问器方法,通常以您尝试访问的变量命名,因此@item.foobar调用foobar上的@item方法}。

现在,回到那些“其他问题”。你试图将重复的行为转移到一个地方是很棒的,并且当你把事情变得不那么明确而有利于灵活时,它表明你正在考虑可扩展性。但是,有一些事情对你来说不是很好,我觉得有必要指出。

  1. 分组适用于大量数据类型,其中大多数数据类型不响应strftime。通过对其进行硬编码,您会引入意外行为,这意味着您无法运行group_collection(@users, :column => 'phone_number')。相反,只有在测试后才能运行该列数据可以响应它。

    collection.group_by do |item|
      data = item.send(column)
      data.respond_to?(:strftime) ? data.strftime('%b %y') : data
    end
    
  2. 如果确定这个辅助方法的行为是对任意列进行分组,那么你可以放弃接受选项哈希的额外复杂性,只是为了绕过它。

    def group_by_column(collection, column)
      collection.group_by { ... }
    end
    group_by_column(@users, :column)
    
  3. 如果您使用的是Ruby 1.9+并且不需要进行任何其他格式设置,则可以更轻松地按任意列进行分组。

    @users.group_by &:created_at
    

答案 1 :(得分:2)

def group_collection(collection, options = {})
    column = options[:column]
    group_count = collection.group_by{ |item| item.send(column).strftime('%b %y')}
end