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?
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.
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.
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.
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).
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.
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
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)
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With