Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails Persist Search Results to CSV Output

I have a Rails 3.2.x app where I have a reporting controller that does search on the Call model. The code I put together works fine and allows for multiple conditions that will display on the page. The problem I'm having is with exporting the specific search results to a CSV file. So far I've only been able to export the entire database to CSV instead of the specific search results.

I'd like to figure out how to get my search params to persist and be able to export only those records to CSV.

Here is my relevant code:

reports_controller.rb

  def index    
     @calls = Call.report(params[:search])
     respond_to do |format|
         format.html do
           @calls = @calls.paginate(:per_page => params[:per_page] || 10, :page => params[:page]).order('incident_number ASC')
         end
         format.csv { send_data @calls.to_csv }
         format.xls  { send_data @calls.to_csv(col_sep: "\t") }
       end
   end

Call.rb

def self.report(search)
    search ||= { type: "all" }

    # Determine which scope to search by
    results = case search[:type]
              when "open"
                open_status
              when "canceled"
                cancel
              when "closed"
                closed
              when "waitreturn"
                waitreturn
              when "wheelchair"
                wheelchair
              else
                scoped
              end

    results = results.by_unit_name(search[:unit_name]) if search[:unit_name].present?
    results = results.by_service_level(search[:service_level]) if search[:service_level].present?
    results = results.from_facility(search[:transferred_from]) if search[:transferred_from].present?
    results = results.to_facility(search[:transferred_to]) if search[:transferred_to].present?

    # If searching with BOTH a start and end date
    if search[:start_date].present? && search[:end_date].present?
      results = results.search_between(Date.parse(search[:start_date]), Date.parse(search[:end_date]))

      # If search with any other date parameters (including none)
    else
      results = results.search_by_start_date(Date.parse(search[:start_date])) if search[:start_date].present?
      results = results.search_by_end_date(Date.parse(search[:end_date])) if search[:end_date].present?
    end

    results
  end

 def self.to_csv(options = {})
    CSV.generate(options) do |csv|
      csv << ["Call ID", "Caller Name", "Caller Phone", "Call Created At", "Call Status", "Incident Number", "Diagnosis", "Service Level", "Patient Name", "Patient Age", "Patient Sex", "Transfer From", "Transfer To", "Insurance", "Transfer Date", "Unit", "IMX Number"]
      all.each do |call|
        csv << [call.id, call.caller_name, call.caller_phone, call.created_at, call.call_status, call.incident_number, call.nature.determinant, call.service_level.level_of_service, call.patient_name, call.patient_age, call.patient_sex.sex, transfer_from_name(call), transfer_to_name(call), call.insurance.insurance_type, call.transfer_date, call.units.map(&:unit_name).join(", "), call.imx_num]
      end
    end
  end

index.html.erb

<h2>Reports</h2>
<%= render 'search'%>
<%= render 'results'%>

_search.html.erb

<div>
  <%= form_tag reports_path, :method => 'get' do %>  
    <p>
        <%= select_tag "search[type]", options_for_select([["All Statuses", "all"], ["Open", "open"], ["Closed", "closed"], ["Canceled", "canceled"], ["Wait & Return", "waitreturn"]], selected: params[:search].try(:[], :type)) %>
        <%= select_tag "search[service_level]", options_from_collection_for_select(ServiceLevel.order(:level_of_service), :level_of_service, :level_of_service, selected: params[:search].try(:[], :service_level)), prompt: "All Service Levels" %>
    </p>
    <p>
        <%= text_field_tag "search[start_date]", params[:search].try(:[], :start_date), :placeholder => 'Start Date', :class => 'input-large search-query ', id: 'start_date_select' %>
        to 
        <%= text_field_tag "search[end_date]", params[:search].try(:[], :end_date), :placeholder => 'End Date', :class => 'input-large search-query', id: 'end_date_select'   %>
      </p>

      <p>
        Unit
        <%= select_tag "search[unit_name]", options_from_collection_for_select(Unit.order(:unit_name), :unit_name, :unit_name, selected: params[:search].try(:[], :unit_name)), prompt: "Any Unit" %>

      </p>

      <p>
        From
        <%= select_tag "search[transferred_from]", options_from_collection_for_select(Facility.order(:facility_name), :id, :facility_name, selected: params[:search].try(:[], :transferred_from)), prompt: "Any Facility" %>
        To
      <%= select_tag "search[transferred_to]", options_from_collection_for_select(Facility.order(:facility_name), :id, :facility_name, selected: params[:search].try(:[], :transferred_to)), prompt: "Any Facility" %>
      </p> 

      <p>
        Results Per Page
        <%= select_tag "per_page", options_for_select([["10", 10], ["25", 25] , ["50", 50], ["100", 100], ["All", 100000]], selected: params[:per_page]), class: "span1" %>
        <%= submit_tag "Search", :name => nil, :class => 'btn' %>
      </p>
  <% end %>
</div>

_results.html.erb

<table class="table table-striped">
  <thead>
    <tr>
      <th>Incident Number</th>
      <th>Patient Name</th>
      <th>Transfer Date</th>
      <th>Transferred From</th>
      <th>Transferred To</th>
      <th>Determinant</th>
      <th>Unit</th>
      <th>Insurance</th>
      <th>Cancelation Reason</th>
      <th>IMX Number</th>
      <th></th>
    </tr>
  </thead>

  <tbody>
    <% @calls.each do |c| %>
      <tr>
        <td><%= c.incident_number %></td>
        <td><%= c.patient_name %></td>
        <td><%= c.transfer_date.strftime("%m/%d/%y") %></td>
        <td><%= transferred_from(c) %><br/><%= transferred_from_address(c) %></td>
        <td><%= transferred_to(c) %><br/><%= transferred_to_address(c) %></td>
        <td><%= c.nature.try(:determinant)%></td>
        <td><%= c.units.map(&:unit_name).join(", ") %></td>
        <td><%= c.insurance.try(:insurance_type)%></td>
        <td><%= c.cancel_reason.try(:reason) %></td>
        <td><%= c.imx_num %></td>
        <td><%= link_to 'View', c, :class => 'btn btn-close btn-mini'%></td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= will_paginate @calls, :renderer => BootstrapPagination::Rails %>
like image 623
nulltek Avatar asked Mar 22 '23 02:03

nulltek


2 Answers

In my view this is the code that needs to persist the params and merge them.

 <%= link_to "Export Results to CSV", reports_path(params.merge(format: "csv")), :class => "btn btn-info" %>

Note the params.merge which takes all of the selected params, merges them, and passes them to the controller.

like image 152
nulltek Avatar answered Mar 28 '23 04:03

nulltek


In your Call#to_csv method you have:

all.each do |call|
        csv << [call.id, call.caller_name, call.caller_phone, call.created_at, call.call_status, call.incident_number, call.nature.determinant, call.service_level.level_of_service, call.patient_name, call.patient_age, call.patient_sex.sex, transfer_from_name(call), transfer_to_name(call), call.insurance.insurance_type, call.transfer_date, call.units.map(&:unit_name).join(", "), call.imx_num]
      end

I'm thinking the all is what is loading up the entire data-set, not your filtered version.

How about passing in the actual rows to convert to CSV, like:

def self.to_csv(records = [], options = {})
    CSV.generate(options) do |csv|
      csv << ["Call ID", "Caller Name", "Caller Phone", "Call Created At", "Call Status", "Incident Number", "Diagnosis", "Service Level", "Patient Name", "Patient Age", "Patient Sex", "Transfer From", "Transfer To", "Insurance", "Transfer Date", "Unit", "IMX Number"]
      records.each do |call|
        csv << [call.id, call.caller_name, call.caller_phone, call.created_at, call.call_status, call.incident_number, call.nature.determinant, call.service_level.level_of_service, call.patient_name, call.patient_age, call.patient_sex.sex, transfer_from_name(call), transfer_to_name(call), call.insurance.insurance_type, call.transfer_date, call.units.map(&:unit_name).join(", "), call.imx_num]
      end
    end
  end

And then updating your controller:

format.csv { send_data Call.to_csv(@calls }
like image 34
Cody Caughlan Avatar answered Mar 28 '23 05:03

Cody Caughlan