Ruby-on-rails Rails - group_by

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4949164/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 00:22:30  来源:igfitidea点击:

Rails - group_by

ruby-on-railsactiverecordgroup-by

提问by AMIT

My application has a few reports and I'm trying to make a helper method for group_by for all these collections.

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

Example:

例子:

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

This is how i plan to use it

这就是我计划使用它的方式

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

Unfortunately, this does not work.

不幸的是,这不起作用。

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

Any clues on how to make the "column" variable an actual column type at runtime so it considers itself as activerecord column and not a instance method?

关于如何在运行时使“列”变量成为实际列类型以便它认为自己是 activerecord 列而不是实例方法的任何线索?

回答by coreyward

Ignoring some of the other problems in your code, what you are trying to do with columncan be done like so:

忽略代码中的其他一些问题,您column可以这样做:

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

This works because in Ruby the way you access instance variables is through accessor methods, usually named after the variable you're trying to access, so @item.foobarcalls the foobarmethod on @item.

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

Now, back to those "other problems". It's great that you're trying to move repeated behavior into a single place, and it shows you're thinking about extensibility when you make things less explicit in favor of being flexible. However, there are a couple of things that aren't going to work out very well for you here that I feel compelled to point out.

现在,回到那些“其他问题”。尝试将重复的行为移到一个地方真是太好了,这表明当您让事情变得不那么明确以支持灵活性时,您正在考虑可扩展性。但是,我觉得有必要指出一些对您来说不太合适的事情。

  1. Grouping works on lots of data types, most of which don't respond to strftime. By hard coding the call to it you're introducing unexpected behavior that means you can't run group_collection(@users, :column => 'phone_number'). Instead, only run that after testing that the column data can respond to it.

    collection.group_by do |item|
      data = item.send(column)
      data.respond_to?(:strftime) ? data.strftime('%b %y') : data
    end
    
  2. If you nail down the behavior of this helper method is to group on an arbitrary column, you can ditch the additional complexity of accepting an options hash, only to circumvent it.

    def group_by_column(collection, column)
      collection.group_by { ... }
    end
    group_by_column(@users, :column)
    
  3. You can group by an arbitrary column much more easily, provided you're using Ruby 1.9+ and you don't need to do any additional formatting..

    @users.group_by &:created_at
    
  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
    

回答by fl00r

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