I have a few parts of the solution, but I'm having trouble bringing them together.
I have a page with two text fields (in a form_tag) in which I'll enter a datetime string with the start and end dates of the records I want to download in CSV form.
I can use a submit_tag and get the two dates, but then I don't know how to get the view to tell the controller that I want a CSV, so . I can use a link_to, but then the params get left behind.
The view and controller look a little wonky as I'm trying to figure out how this stuff should work together. I won't ship both a link and a button, for example. I also removed/changed things as needed for brevity/privacy.
show.html.erb:
<%= form_tag do %>
<br/><br/>
<%= label_tag :start_date, "From:" %>
<%= text_field_tag :start_date, nil, size: 40 %>
<%= label_tag :end_date, "To:" %>
<%= text_field_tag :end_date, nil, size: 40 %>
<br/>
<%= link_to "Export Report", report_path(:csv) %>
<%= submit_tag("Generate .CSV", format: :csv) %><br/><br/>
<% end %>
report_controller.rb:
require 'csv'
class ReportController < ApplicationController
def show
if params[:start_date]
@data = get_data(params[:start_date], params[:end_date])
respond_to do |format|
format.html
format.csv
end
end
end
def build_csv_enumerator(header, data)
Enumerator.new do |y|
CSVBuilder.new(header, data, y)
end
end
def download
if params[:start_date]
@data = get_data(params[:start_date], params[:end_date])
respond_to do |format|
format.html
format.csv
end
end
redirect_to action: "show"
end
private def csv_filename
"report-#{Time.now.to_s}.csv"
end
end
class CSVBuilder
attr_accessor :output, :header, :data
def initialize(header, data, output = "")
@output = output
@header = header
@data = data
end
def build
output << CSV.generate_line(header)
data.each do |row|
output << CSV.generate_line(row)
end
output
end
end
download.csv.erb:
<%- headers = ["name", "email", "created_at"] -%>
<%= CSV.generate_line(headers) %>
<%- @data.each do |line| -%>
<%- row = line.values_at(*headers) -%>
<%= CSV.generate_line(row) %>
<%- end -%>
This is the name used to generate the input's name (and the params' names), example: = form_for Admin.new, as: :user do |f| #^^^^ = f.input :username # will generate an input like this: <input type='text' name='user[username]' #... /> #
This can be used for: creating new database records, building a contact form, integrating a search engine field, and pretty much every other aspect of the application that requires user input.
Because you want to download a CSV, the request should be a GET
request.
Your link should look like <a download href="/reports/1.csv?from=2017-01-01&to=2017-12-31">Download</a>
. I suggest you build this url on browsers (which means using javascript, not rails).
Your rails application must understand the extension .csv
. This can be configured in config/initializers/mime_types.rb
Mime::Type.register "text/csv", :csv
Now you can send CSV to the browser
class ReportsController < ApplicationController
def show
respond_to do |format|
# ...
format.csv do
@csv = ...
send_data @csv.to_s # what you send must be a string
end
end
end
end
Links are self-contained; submit buttons (typically) submit forms (with all their non-disabled
, name
-having values) to the action URL of the form (unless you're doing submission through JavaScript, in which case you can do whatever you want, obviously).
Thus, you don't specify the URL on submit_tag
, you specify it on form_tag
:
Starts a form tag that points the action to a url configured with
url_for_options
just likeActionController::Base#url_for
.
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