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 %>
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.
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 }
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