Rails - group_by

There are several reports in my application, and I'm trying to create a helper method for group_by for all of these collections.

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 hints on how to make a column variable an actual column type at runtime so that it considers itself an activerecord column rather than an instance method?

+6
ruby-on-rails activerecord group-by
source share
2 answers

Ignoring some other problems with your code, what you are trying to do with column can be done as follows:

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

This works because in Ruby you access instance variables through access methods, usually called after the variable you are trying to access, so @item.foobar calls the foobar method on @item .

Now back to those "other problems." It's great that you are trying to move repetitive behavior in one place, and this shows that you think about extensibility when you make things less explicit in favor of flexibility. However, there are a few things that will not work very well for you here that I feel compelled to indicate.

  • Grouping works with many data types, most of which do not respond to strftime . When hard-coding a call to it, you introduce unexpected behavior, which means that you cannot run group_collection(@users, :column => 'phone_number') . Instead, run only after verifying 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 
  • If you nail the behavior of this helper method, you must group it in an arbitrary column, you can discard the additional complexity of accepting an options hash, only to bypass it.

     def group_by_column(collection, column) collection.group_by { ... } end group_by_column(@users, :column) 
  • You can group an arbitrary column much easier if you use Ruby 1.9+, and you do not need to do any additional formatting.

     @users.group_by &:created_at 
+21
source share
 def group_collection(collection, options = {}) column = options[:column] group_count = collection.group_by{ |item| item.send(column).strftime('%b %y')} end 
+2
source share

All Articles