Search code examples
ruby-on-railsrubyactiverecorddelayed-job

Is there a way to serialize an ActiveRecord Relation object without loading it?


I am trying to export database rows to CSV depending on the parameters user picks. These exports can take a while, so I'm using delayed_job to process them and upload them to S3. My controller looks like this:

def search
  @books = visible_books.includes(:publisher)
  @books = @books.where(contract_id: assigned_contract_ids) if assigned_subscriber.present?
  @books = @books.unifilter(params, to_cents: ['total_cost'])

  respond_to do |format|
    format.json { export }
    format.js { @books.paginate(params[:page], per: 50) }
  end
end

def export
  exportable_books = ExportableBooks.new(@books)
  exportable_books.delay.upload
  render json: { id: exportable_books.id }
end

Unfortunately, @books can hold up to 10.000 rows, and when they are serialized to YAML for delayed_job, all those rows get loaded into memory, and then written to the database in YAML format. Is there a way to avoid that?


Solution

  • The problem is that delay needs to serialize exportable_books into the database and exportable_books holds the complete result set of @books.

    Instead of that you should initialize ExportableBooks just with the params and assigned_contract_ids, because that is much smaller when serialized. And then run the query in the upload method.