Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails - group_by

My application has a few reports and I'm trying to make a helper method for group_by for all 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 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?

like image 821
AMIT Avatar asked Feb 09 '11 18:02

AMIT


People also ask

What does Group_by do in Ruby?

The group_by() of enumerable is an inbuilt method in Ruby returns an hash where the groups are collectively kept as the result of the block after grouping them. In case no block is given, then an enumerator is returned. Parameters: The function takes an optional block according to which grouping is done.

What is group by in rails?

Ruby's #group_by method provides a way to (wait for it) group things by some arbitrary property. It's part of the Enumerable module, so you can generally use it anywhere you'd be using #each or some iteration.

What are active records in Rails?

Rails Active Records provide an interface and binding between the tables in a relational database and the Ruby program code that manipulates database records. Ruby method names are automatically generated from the field names of database tables.

What is an ActiveRecord relation?

An instance of ActiveRecord::Base is an object that represents a specific row of your database (or might be saved into the database). Whereas an instance of ActiveRecord::Relation is a representation of a query that can be run against your database (but wasn't run yet).


1 Answers

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

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.foobar calls the foobar method 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
    
like image 166
coreyward Avatar answered Oct 04 '22 04:10

coreyward