I have a ransack search form which is working wonderfully, I would like to add an export for the user to send the contents of the result set to an XLS file.
I have implemented the to_xls sucessfully as well, however it is giving me back the fullest possible scope of the object I am searching, and not the filtered results that are shown in the view.
def index
#search = Expense.search(params[:q])
#expense_list = #search.result.sort_by(&:expense_date)
respond_to do |format|
format.html
format.xml { render :xml => #expense_list }
format.xls { send_data #expense_list.to_xls, :filename => '123.xls'}
end
end
Does it have something to do with how ransack uses the GET method? Any help would be great.
Thanks!
I know this is such a hack, after spending many hours of not getting it, I used it anyway.
make xls
so basically it takes the searchpath after the ?, then adds it to your model.xls output path and then it works. I hate it myself, there must be a better way, but deadlines.
There was a good link here.
Ronin gave a simple solution to this related question, but with CSV instead of XLS . In my case, using Ronin's answer, I just rewrote the link to work with XLS as shown below
<%= link_to "Download Excel", reports_path(params.merge(format: "xls")) %>
%= link_to "Download Excel", yours_controller_path(params.merge(format: "xls")) %>
Related
I followed the http://railscasts.com/episodes/362-exporting-csv-and-excel
and set up an Excel Download in my Rails application.
My controller code looks like this:
def show
#project = Project.find(params[:id])
#project.tasks.order(:name)
respond_to do |format|
format.html
format.json { render json: #project }
format.xls
end
end
and in my view I create the link to download the excel file like this:
.dl_xls= link_to "Download xls", url_for(:format => 'xls')
Now the generated excel file is always named like the id of the Project record, e.g. 80.xls
Is there any way to change this behaviour and give it a custom name?
Thank you..
I believe your answer is here: in rails, how to return records as a csv file
Use headers to set the filename.
headers["Content-Disposition"] = "attachment; filename=\"#{filename}\""
def index
#tabulars = Tabular.all
filename = "data_users.xls"
respond_to do |format|
format.html
format.xls { headers["Content-Disposition"] = "attachment; filename=\"#{filename}\"" }
end
end
This link more detail change the file name excel
I expect what you are actually seeing there is the name of the view sans .erb, not necessarily the controller action.
If you want that level of control there are three things you can do.
Use the send_data call from your controller with tab separated data as shown in the rails cast with the filename: option
e.g.
class ProductsController < ApplicationController
def index
#products = Product.order(:name)
respond_to do |format|
format.html
format.csv { send_data #products.to_csv }
format.xls { send_data #products.to_csv(col_sep: "\t"), filename: 'your_file_name.xls'}
end
end
end
There are problems with this approach as well as the old propriety spreadsheetML language that the railscast introduces, but if your user base is locked into MS-OFFICE, I dont think anyone will notice.
Alternatively, you can use a gem like acts_as_xlsx or axlsx_rails that consume the axlsx gem. Those tools generate validated xlsx data (also known as Office Open XML / ECMA-376 - or what MS has been using since office 2007...), and have fairly good interoperability with other modern spreadsheet software like Numbers, GoogleDocs, LibraOffice. I am sure you noticed all the comments related to this in the railscast.
I know, because I am the author or axlsx, and those limitations, and the lack of styling, charts and validation where what drove me to author axlsx in the first place.
More Info:
axlsx: https://github.com/randym/axlsx
acts_as_xlsx:
http://axlsx.blogspot.jp/2011/12/using-actsasxlsx-to-generate-excel-data.html
Write your own responder / renderer
axlsx_rails is also a great example on how to author your own renderer and responder so that you can use the standard rails view, but rename the file that gets downloaded.
https://github.com/straydogstudio/axlsx_rails/blob/master/lib/axlsx_rails/action_controller.rb
First of all i know this type of posts are already been made but i've tried almost all of them and i'm not been able to get the results so here i'm again posting the same kind of question.
Second of all i'm not having an asset pipeline issue here, so please forget about that.
Now let me explain what i'm doing. I'm using rails 3.1 and ruby 1.9.2, i installed wicked_pdf as a gem and installed wkhtmltopdf as mentioned in the wiki by purging the already installed wkhtml and downloading and extracting the new one to /usr/bin/wkhtmltopdf
I have an initializer that contains the following:
wicked_pdf.rb
WickedPdf.config = { :exe_path => '/usr/bin/wkhtmltopdf'}
In my view i have a link_to method as follows:
_filters.html.haml
= link_to 'show pdf', jobs_report_jobs_path(:format => :pdf), :method=>"post"
note if i remove the :format => :pdf option it works fine
in my controller i'm doing the following:
report_jobs_controller.rb
respond_to do |format|
format.html
format.js
format.pdf{
render :pdf=>"jobs",
:template => 'jobs.html.erb',
:layout=>"jobs.html"
}
end
note that i have tried from format.pdf alone without any options. I tried "jobs.pdf.erb", with and without layout option, all sorts of other options i don't even remember. All i get is a 406 not acceptable in the end.
Please guide me coz i need to implement this feature asap.
Regards,
406 means the request isn't valid (in regards to what is acceptable to that controller action)
I've had trouble with :format => :pdf before. Try :format => 'pdf'
The barebones implementation should just be:
format.pdf {
render :pdf => 'jobs'
}
Also, is the link_to really supposed to be :method => "post"?
i had a before_filter in my application controller that was checking every request with the mentioned format for authentication and i was missing pdf format there, so as soon as i put the :pdf in the list of formats for each incoming request it worked fine.
I too had the same issue. I work on ubuntu. AFter I installed wkhtmltopdf, I am not getting this error any more.
in terminal run the command below:
$sudo apt-get install wkhtmltopdf
I hope this helps :)
I don't how much about wicked-pdf, but I once used pdfkit and this is how I did the rendering part:
def pdf
respond_to do |format|
format.pdf { render :text => PDFKit.new( Pdf.find(params[:id]).content ).to_pdf }
end
end
I hope the code is clear enough and self-explanatory. My view code is:
<p><%= link_to "Download PDF", pdf_pdf_path(#pdf, :format => "pdf") %></p>
I'm working through Agile Web Development with Rails, Edition 4 with some tweaks (mostly just naming variations), and I've arrived at Iteration F2. In this iteration, you modify the index button with :remote => true, you add format.js to the respond_to section of the controller, and you generate a js.rjs file to execute the AJAX render. Or at least that's my interpretation of it. The goal of these steps is to have a cart (in this case, a team) in the sidebar update using AJAX when adding new line items (in this case, members)
In my case, I'm trying to add members to a team. Her's some code snippets I've added:
index.html.erb:
<%= button_to 'Add to Team', members_path(:player_id => player),
:remote => true %>
members_controller:
def create
#team = current_team
player = Player.find(params[:player_id])
#member = #team.add_player(player.id)
respond_to do |format|
if #member.save
format.html { redirect_to(nba_url) }
format.js
format.xml { render :xml => #member,
:status => :created, :location => #member }
else
format.html { render :action => "new" }
format.xml { render :xml => #member.errors,
:status => :unprocessable_entity }
end
end
end
create.js.rjs:
page.replace_html('team', render(#team))
The page is able to render, and I'm still able to click the button to add members to the team. However, the AJAX isn't working. When I reload, I can still see that the members have been added in the sidebar. All of the other team functionality remains, as I'm able to empty the team and add whichever members I wish. When I check the server log, I find the following error:
Error:
ActionView::Template::Error (undefined local variable or method `page' for #<
#<Class:0x413e1b8>:0x413cb20>):
1: page.replace_html('team', render(#team))
app/views/members/create.js.rjs:1:in `block in _app_views_members_create_js_rj
s___908569197_34199712_807066544'
app/views/members/create.js.rjs:1:in `_app_views_members_create_js_rjs___90856
9197_34199712_807066544'
app/controllers/members_controller.rb:47:in `create'
Based on this it seems like it has found the create.js.rjs but is having trouble interpreting it. I'm not sure what the weird symbols are in front of page.
Edit: I've also found that if I view the source code before and after clicking the button, the button is indeed refreshing the code and adding the desired items. The problem seems to be exclusively in trying to refresh the partial.
Any help is appreciated. Thanks!
It seems your rjs file has some invalid bits at the start. Maybe try to re-create the file?
What did you expect to do with render(#team) ?
I've taken a look at the action view's method "render" and didn't found how you were expecting it to function. Maybe there is another functionality that you are aware and I don't.
You can also use erb and not rjs, using it just like a view
Along the lines of Bert Goethal's answer, is your editor saving your text file as UTF-8 with BOM?
A BOM will add two unicode encoded characters to the beginning of the file, and that might be where those are coming from...
I'm trying to generate a PDF file using AJAX call in Rails3. The following code generates a PDF file which I have created using PRAWN gem.
<%= link_to "Generate pdf", books_path(#book, :format => 'pdf') %>
I do not want user to view the PDF until they order it. So, the goal is to create a PDF file in the server.
Any ideas or thoughts much appreciated.
Use this, make sure your remote action does not return the PDF, but simple generates and stores it on the server.
link_to "Generate PDF", prepare_books_path(#book), :remote => true, :method => :put
This will work in Rails 3. If you're using jQuery, make sure to read this article on how to set things up correctly.
Your controller action may look like this:
def prepare
# Do your thing to generate the PDF
render :text => "PDF Generated", :status => 200
end
I used the PUT-method because you are altering the state of your data (e.g. you are generating something new, you don't want a bot or crawler to automatically call that).
Firstly, it beats me why you would do something on a request like generating a PDF, when the user is not expecting that action. Isn't better to only generate the pdf when the user requests for it?
Thanks Ariejan.
I modified your code as following and it did just what I wanted.
<%= link_to "Generate Story Book", pdfbook_stories_path(:format => 'pdf'), :remote => true %>
And for the controller,
def pdfbook
#stories = current_account.stories
respond_to do |format|
format.pdf {}
end
end
I am having problems with a remotely executed action and a partial that doesn't update the first time I click the link.
Inside the view (a partial named books) I am creating a link:
link_to "⊗", read_book_path(book), :remote => true
The read_book_path is defined in routes.rb
There is also a conditional that displays a different text when that book is read.
Inside my controller, I have defined a new action:
def read
#books = Book.all
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
respond_to do |format|
format.html { redirect_to(books_url) }
format.js {render :layout => false, :locals => { :book => #book } }
end
end
This means I need a file read.js.erb, this file's content is:
$("#books").empty().html("<%= escape_javascript( render(:partial => "books") ) %>");
When I click the link, I can see in the terminal window that the database field is updated but the partial is not. Clicking the same link again updates the partial.
Changing the link to :remote => false also works but the page reloads (as expected).
I have tried to debug it with Safari and the Developer tools and I can see the server's response when clicking the link for the first time.
Something is wrong there, the HTML generated by <%= escape_javascript( render(:partial => "books") ) %> contains the wrong HTML with the old content of the partial. Only the second or third click shows the updated HTML.
I have integrated jquery-ujs - is that the reason the partial doesn't update the first time or am I missing something else?
This really gave me a headache, can you help me?
Edit:
If that helps: I created a listener in application.js to ajax:before and ajax:complete. The first one shows a little spinner, the second one hides it.
When I click the link, the spinner shows but it doesn't hide.
It looks like you have an ordering problem that's causing the trouble. You're capturing a complete set of books into the #books variable and then modifying a separate copy of a single book. This change will not be propagated back.
# Load and modify the one book by flipping the flag
#book = Book.find(params[:id])
#book.read = !#book.read
#book.save
# Load all books
#books = Book.all
As a note this is an extremely inefficient way of doing things, so I hope you're not working on a large amount of data. You might find it's easier to do this by simply toggling the one field with a simple UPDATE query:
Book.update_all({ :read => true }, { :id => params[:id] })
I'm not sure why you're calling $(...).empty().html(...) instead of simply $(...).html(...) since the html() method should replace the HTML wholesale with no need to clear it in advance.
One thing that might help is using .js.rjs where the equivalent would be:
page[:books].replace_html(:partial => 'books')
With simple JavaScript, RJS allows you to eliminate a lot of the drudgery. You can use JS in RJS as well for cases where there is no equivalent:
page << '$("#books").empty()'
page[:books].replace_html(:partial => 'books')
To make this more Rails friendly, you could call your partial _book which would make the local variables redundant. Each partial has a default variable with a name matching the template name:
render(:partial => 'book', :collection => #books)