Reputation: 665
I'm working on a React app served by a RoR backend. I want to have a button that, when clicked, will query the server for the required data and create the CSV for download in the users browser.
I'm pretty versed in the Rails side of things but I'm not at all sure how to go about doing this on the React side (or even if that's the best order to do it in as I've seen some answers saying it might be better to do the API call when the component initially mounts).
Any advice is appreciated!
Upvotes: 1
Views: 2429
Reputation: 126
The above solution with form with form will, but why not just use a link and style it like a button. This way you can even have a GET request
render() {
return ()
<a href='api/reports/export'>Download CSV</a>
}
Upvotes: 0
Reputation: 533
The biggest problem here is that you can't download a file via AJAX -- browsers don't allow it. The only solution is to render a static form in your react component, save a reference to it, and manually submit it when you click your button. Here's an example:
class MyComponent extends React.Component {
constructor(props) {
super(props)
this.onClickDownload = this.onClickDownload.bind(this)
}
render() {
return (
<div>
<form style={{display: 'none'}} method="POST" action="/api/reports/export"
ref={(el) => {this.exportForm = el}}>
</form>
<button onClick={this.onClickDownload}>Download CSV</button>
</div>
)
}
onClickDownload() {
this.exportForm.submit()
}
}
Upvotes: 1
Reputation: 1270
I would propose you have an endpoint in your Rails app that accepts parameters for the CSV report. This endpoint gets hit when the user presses the button.
The Rails app would create the CSV, put it somewhere (maybe S3 using https://github.com/carrierwaveuploader/carrierwave), and return an S3 URL to the React app. The user could then go to that URL and download the file.
It's probably best to generate the CSV asynchronously to not tie up resources. In that case, the frontend could poll (or use a websocket) and wait until the report is ready. When it's ready, the API would return the URL.
Upvotes: 0