Rails: handling errors within respond_to block (csv) - ruby-on-rails

I have a search method on my controller that responds to either the html or CSV format. The html format renders the search results as expected, and I want the CSV format to work by downloading a CSV file of the results.
Most of the time, send_data is called and the CSV file is generated. However there are situations in which I don't want to generate the CSV, and instead show an error (for example when a user has used all of their allotted exports for the month). The following code is a simplified version of what I'd like to do, however this doesn't seem to like how I'm attempting to handle the error.
respond_to do |format|
format.html do
#results = ...
render "index"
end
format.csv do
#results = ...
if user_can_export?(#results)
send_data generate_csv(#results), filename: "Search-Results.csv"
else
flash[:error] = "Unable to export search results."
render "index"
end
end
end
Is there any way for me to break out of this block and render HTML or am I stuck generating a csv file here? I'd prefer to not handle this situation by sending a csv file with an error message contained in it, but that seems like my best option at the moment. Help is appreciated!

You need to set the content-type header to text/html instead of text/csv.
render template: "things/index.html.erb", content_type: "text/html"
Also if you want to display a flash message in the current request cycle you need to use flash.now[:error] = "Unable to export search results"

Related

respond_to works only for the first MIME type in Rails 6

Straight-forward enough problem: everything renders just fine if I remove either geojson or csv, but when both are in the block, the first one is rendered no matter what Content-Type header I send along (text/csv or vnd.geo+json). I do have custom MIME types and renderers, but these don't seem to be the problem since when I use one or the other, everything works as expected, but it is only when I try to reference multiple formats does only the first format end up being used, regardless of header.
def all
resource = Thing.where.not(thing_type: BaseThing::ONE_OF_THE_THINGS).order(:unique_id)
respond_to do |format|
format.geojson do
render geojson: Things::GeoSerializer.to_geojson(resource)
end
format.csv do
render csv: Things::CsvSerializer.to_csv(resource), filename: 'things'
end
end
end
ah; Rails expects the header to be Accept, not Content-Type.

When you upload multiple files using ActiveStorage, is it possible to determine what was just uploaded?

I have a model (let's call it Message) that's using Active Storage with has_many_attached to store multiple uploads through a Javascript routine. I'd like to know the URL of the uploads as soon as these are received and processed by the Update action in my controller. Ideally, the response would be in the form of a JSON string, containing the URL of the file that is just uploaded by the Javascript routine.
Other than having to loop through all the uploads, is there a way to obtain this information as they're uploaded?
I'm not using the DirectUpload javascript suggested in the Active Storage guide, in case you're wondering. The Javascript I'm using sends the files to a custom PATCH action /message/:id/new_upload (where :id is the ID of the Message record), with the BLOB file as its only parameter.
I've tried to use something like this:
def new_upload
#message.uploads.attach(params[:uploads])
respond_to do |format|
format.json {render json: { location: "The URL would go here"} }
end
end
But the attach line at the beginning doesn't return anything (obviously), all it is is doing is saving the attachments. Is there anything I can use to figure out what was just uploaded?
UPDATE
I've managed to make it "work" by doing something like this:
def new_upload
#message.uploads.attach(params[:uploads])
upload_url = rails_blob_url(#message.uploads.blobs.last)
respond_to do |format|
format.json {render json: { location: upload_url} }
end
end
However, this only works for one attachment (the last). Thankfully I only require to upload one file at a time, but I'd prefer to infer the URL by something other than checking the last upload.

Rails HAML View Rendering Raw HTML

I'm trying to render a simple view using HAML that shows a collection of JSON objects with a header above. The route I'm using is get 'posts.json', to: 'posts#posts_as_json'. This renders the below view.
posts_as_json.haml
%h1 Posts As JSON
%div.gutter-spacing
=raw(#posts)
The problem I'm running into is that the page will render raw HTML tags as well as the JSON itself. I've been trying to figure out what the issue is and based on some experimentation I think it's directly tied to using .json in my routing. If I remove that it seems to render the HTML as expected. Update: This is definitely the root of the issue
Using the route 'posts.json' is a requirement of my project, but I need to be able to search the parsed JSON as well which I have previously solved with a simple HTML text input tied to a javascript function. How can I use this endpoint while still rendering HTML alongside the JSON data?
The problem is that if you request a .json format, rails will automatically try to send it as a response with the corresponding MIME type application/json.
Now the browser gets a response that he thinks should be a JSON so it renders it as text.
You can override the MIME type for your render method:
render content_type: content_type: "text/html"
Or if you want to serve both request from the same controller action, you can do it with the respond_to-method:
def index
#posts = Post.all
respond_to do |format|
format.html { render }
format.json { render 'index_as_json.html', content_type: "text/html" }
end
end

Generate XML file and redirect to other view with Rails

I have a piece of code that generates an XML file. What I want to, and didn't find the solution, is to generate the XML file and ALSO redirect to another page, to give a feedback message.
My code is
def exportFiles
#files=FileToExport.getComponentToExport
recursive_tree= GitHubRepositorioService.getRecursiveTree('master')
GitHubService.updateFiles(#files, recursive_tree)
xml = Builder::XmlMarkup.new(:target=>$stdout, :indent=>2)
respond_to do |format|
format.xml { send_data render_to_string(:exportFiles), filename: 'exported_module.xml', type: 'application/xml', disposition: 'attachment' }
end
FileToExport.setComponentToExport(nil)
end
As I already use "respond_to" I can't use another redirect sentence... so, there is a way to generate (downloading) that file and redirect to other view?
Unfortunately, this is not possible via the controller as you can't send two responses.
But you could do this via javascript for instance. See this topic for more info Rails how do I - export data with send_data then redirect_to a new page?

Creating PDFs with Prawn - missing attribute error

I'm working on PDF creation in my rails application. I found PDFkit didn't necessarily do what I wanted to do, so I figured I'd test out Prawn.
I added it to my controller using this code:
def show
#document = Document.find(params[:id])
respond_to do |format|
format.html
format.pdf do
pdf = Prawn::Document.new(#document)
send_data pdf.render, filename:"1",
type: "application/pdf",
disposition: "inline"
end
end
end
But using this I get a Missing Attribute error. I'm assuming this is because my model is also named Documents and conflicts with the Prawn::Document.new command?
Can I just not have a documents model and use Prawn - or is there something I'm missing here?
I don't think it's about Document vs Prawn::Document, but I've never seen someone pass an ActiveRecord instance to Prawn::Document.new. I think that expects an options hash, right? And calling render before giving it any content seems suspicious. What is the actual stack trace?

Resources