In an RoR application, I would like the index resource to download an xls file.
Currently, I can get the file to download but it requires a link to a path I created like so
link_to subscribers_path(:format => :xls)
Ideally like the subscribers_path on it's own to add the format xls, and I don't want a view in html format with index.
My file structure
/subscribers
index.html.erb
index.xls.erb
and my controller code
def index
#subscribers = Subscriber.all
respond_to do |format|
format.html
format.xls #{send_data #subscribers.to_csv(col_sep: "/t")}
end
end
I tried to remove html to see if it would just default to another path but it says unknownformat error. I also tried to remove the index.html.erb file to see if would fallback to another format of the same name, but that didn't work.
Hopefully my objective is clear: How do I use the resource index path to link with xls instead of html format?
First, to clarify things: Yes, Rails does fully support XLS.
To use it just put the following line under config/initializers/mime_types.rb:
Mime::Type.register "application/xls", :xls
Then, as the author did it, change the format to xls and create an index.xls.erb
Now, to answer your question, there is a number of ways:
The first thing I thought of, was to just change the request format. In your controller:
class SubscriberController < ActionController::Base
before_filter :change_format
def index
#subscribers = Subscriber.all
respond_to do |format|
format.xls #{send_data #subscribers.to_csv(col_sep: "/t")}
end
end
private
def change_format
request.format = "xls"
end
end
There should also be a dozen other ways to do this, but I would prefer this one.
Related
This is more of an architecture/functional question for Rails. I have a search function which sends the criteria to the model where the query resides. The search works. Now I have a CSV export link <%= link_to "CSV", contacts_path(format: "csv") %> in my view file which points to localhost/books.csv.
The export didn't work without my search parameters (so localhost/book.csv?book_name=foo works as expected). What I do in send_data is I pass the #books object to the .to_csv function inside my model, and it becomes nil without passing the parameter also. Pls see code below.
My controller:
def index
#books = Book.search(params[:search])
respond_to do |format|
format.html
format.csv { send_data Book.to_csv(#books) }
end
My model:
def self.search(criteria)
find(:all, :conditions => ['book_name LIKE ?', "%#{criteria}%"])
end
def self.to_csv(search_results)
CSV.generate do |csv|
csv << column_names
search_results.each do |contact|
csv << contact.attributes.values_at(*column_names)
end
end
end
I like to understand why. The current setup seems to be making another request to the server in order to generate the CSV file, and that's why it requires the parameters in localhost/books.csv request. Is this correct?
Now, if instead I put the query inside the controller like below, the CSV request works as expected (so I just click the link and receive the file).
def index
#books = Book.find(:all, :conditions => ['book_name LIKE ?', "%#{criteria}%"]) respond_to do |format|
format.html
format.csv { send_data Book.to_csv(#books) }
end
I love to keep the query inside the model for the sake of organization, so would be awesome if you guys can point me to the right direction. Thanks!
I would suggest that you change your link to something like this:
<%= link_to "CSV", contacts_path(params.merge(format: "csv")) %>
This will pass down the current search parameters plus the new option for the format to be CSV. Then you can continue to keep the search method inside the model in the way that you had originally written it.
I have a list of users being displayed, you can click on "Show user" or "PDF" to see details of that user in HTML or as a PDF document. The show was automatically created with scaffolding, now I'm trying to add the option to view it as a PDF. The problem is adding a second GET option, if I pass the user along as a parameter, it is assumed to be a POST and I get an error that the POST route does not exist. I am not trying to update the user, just to show it in a different way, basically to add a second "show user" option.
How do I tell it that I want a GET, not a POST? Is there an easier way to do what I am trying to do? Thanks.
Please, create a controller like this:
class ClientsController < ApplicationController
# The user can request to receive this resource as HTML or PDF.
def show
#client = Client.find(params[:id])
respond_to do |format|
format.html
format.pdf { render pdf: generate_pdf(#client) }
end
end
end
Please, update route.rb file, action name with post and get, like below :
match 'action_name', to: 'controller#action', via: 'post'
match 'action_name', to: 'controller#action', via: 'get'
More info please read this link : "http://guides.rubyonrails.org/routing.html"
you haven't posted any code or details, so I am guessing you want something like this:
routes
resources :users
controller
class UsersController < ActionController::Base
def show
#user = User.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.pdf # handle the pdf response
end
end
end
view file in views/users/show.pdf.prawn
prawn_document() do |pdf|
#user.each {|r| pdf.text r.id} # will print user id of the user
end
The way above example will work is, if something visits the following URLs, they will get html file:
localhost:3000/users/1 #html is the default format in rails
localhost:3000/users/1.html
but if they visit .pdf, they will be served a pdf format.
localhost:3000/users/1.pdf
If the above assumptions are correct, then check prawn or wicked_pdf pdf gem. the above example uses prawn
Checkout this link http://apidock.com/rails/ActionController/MimeResponds/InstanceMethods/respond_to. You can add a new MIME type and pass on the :format as pdf in all your rails routes.
Hope this will help.
And for the POST-request check your
config/routes.rb
There shoud be a few routes already, so you can infer the route you need.
In your link you can pass an additional parameter called format for pdf. For e.g.
<%= link_to 'Display in PDF', "/user/pdf", :format => "pdf" %>
So there's the basic function like this ....
def show
#position = Position.find(params[:id])
respond_to do |format|
format.html # show.html.erb
format.xml { render :xml => #position }
end
end
and if you go to, say, http://localhost/(position_id).xml then you will see the xml... But I wish to have a standard xml filename that I can write the object details to because I want to access it from outside rails. I am very new to rails and have not programmed in a while...seems like this should be easy, right ? So I just want to have a file created with a name like my_xml.xml for all the objects, rather than 1.xml, 2.xml, (id).xml, etc.
Thanks for the help !
I met similar questions, here is my solution(I am a newbie):
I added below in routes.rb:
resources do
collection do
get 'my_xml'
end
end
Then added the my_xml action in controller. In my_xml action, assemble all data, and format it to xml via to_xml method.
No sure whether above is useful for you. Hope it helpful.
For some strange reason I need to save a file (normally downloaded directly) in the server. In my case I have a PDF file created with PDFKit that I need to keep.
# app/controllers/reports_controller.rb
def show
#report = Report.find(params[:id])
respond_to do |format|
format.pdf { render :text => PDFKit.new(report_url(#report)).to_pdf }
end
end
If I go to reports/1.pdf I get the report I am expecting but I want to keep it in the server.
Is there a Raily way to save a file in the server from a respond to?
Just a quick note before I get to the actual answer: It looks like you're passing a fully-qualified URL (report_url(#report)) to PDFKit.new, which is a waste--it means PDFKit has to make a request to the web server, which in turn needs to go through Rails' router and so on down the line to fetch the contents of the page. Instead you should just render the page inside your controller with render_to_string and pass it to PDFKit.new, since it will accept an HTML string. Keeping that in mind...
This is covered in the "Usage" section of PDFKit's README. You would do something like this:
def show
#report = Report.find(params[:id])
kit = PDFKit.new render_to_string(#report) # pass any options that the
pdf_file = kit.to_file '/some/file/path.pdf' # renderer needs here (same
# options as `render`).
# and if you still want to send it to the browser...
respond_to do |format|
format.pdf { render :file => pdf_file.path }
end
end
I want some users to be able to download data in a yaml file.
I see that you can do this with
send-file (but uses a lot of resources)
direct link_to the file in public folder (not good for me since the file is generated so the request needs to go to a controller.
restful url via controller (this method is partially explained in http://guides.rubyonrails.org/action_controller_overview.html but not enough to get it working!)
I followed this and tried something like
def show
#client = Client.find(params[:id])
respond_to do |format|
format.html
format.yml { render :yml => #client.redis_to_file }
end
end
redis_to_file returns a string with the yaml data
in config mime_types.rb
Mime::Type.register "x-yaml", :yml
then access like
clients/5.yml
All I get is "invalid template". (It's correct, I don't have a yml template in my views.)
Any clues about how to do this so that it works is greatly appreciated.
Try this:
respond_to do |format|
format.html
format.yml { send_data #client.redis_to_file, :type => 'x-yaml' }
end
There are more options in the Docs