jeudi 15 octobre 2015

Breaking Association/ Relation collection objects into smaller Association/ Relation collections in Ruby on Rails

JRuby, Rails 3

I have a piece of code that queries a number of tables, related through association, returning a combined result set as an ActiveRecord::Relation. My problem is that when this function retrieves a very large result set and tries to do something with it (in my case, create a .xls file), the JVM errors, reporting a GC Memory Heap problem.

The problem is partly down to all these records being held in memory when trying to process the .xls export, as well as JRuby's questionable garbage collector- but, all these records should not be processed at once anyway! So my solution is to break these records into smaller chunks, write them to the file and repeat.

However, amongst all my other constraints, the next part of code that I need to use requires a relation object passed to it. Previously, this was the entire result set, but at this point, I've broken it down into smaller bits (for arguments sake, lets say 100 records).

At this point, you're probably thinking, yeah- what's the problem? Well, see my example code below:

#result_set = relation object
result_set.scoped.each_slice(100) do |chunk|
  generic_filter = App::Filter.new(chunk, [:EXCEL_EXPORT_COLUMNS]) #<-- errors here

  #do some stuff
  generic_filter.relation.each_with_index do |work_type, index|
    xls_doc.row(index + 1).concat(generic_filter.values_for_row(work_type))
    DATE_COLUMN_INDEX.each do |column_index|
      xls_doc.row(index + 1).set_format column_index, 
           ::Spreadsheet::Format.new(number_format: 'DD-MM-YYYY')
    end
  end
  [...] #some other stuff
end    

As you can see, I am splitting the result_set into smaller chunks of 100 records and passing it to the App::Filter class that expects a relation object. However, slitting result_set into smaller chunks using each_slice or in_groups causes an error within the block because these two methods return an array of results, not a relation.

I'm fairly new to Ruby on Rails, so my questions are:

  • Is a relation in fact an object/ collection/ or something like a pre- defined query, much like a prepared statement?
  • Is it possible to return smaller relation objects using methods similar to each_slice or in_groups and process them as intended?

Any pointers/ suggestions will be well received- thanks!

Aucun commentaire:

Enregistrer un commentaire