undefined method `original_filename' for String - ruby-on-rails

I'm trying to implement a csv upload functionality WITHOUT using gems such as paperclip. Here's the view:
%h1 Add Users From CSV
= form_tag(:action => "upload",:multipart => true,:method => :post) do
= file_field_tag 'csv'
= submit_tag 'Upload'
And here's the controller:
def upload
csv_io = params[:csv]
File.open(Rails.root.join('public', 'uploads', csv_io.original_filename), 'wb') do |file|
file.write(csv_io.read)
end
redirect_to root_path, :notice => "Successfully uploaded csv!"
end
But I got this error message when I'm uploading a csv called data.csv
undefined method `original_filename' for "data.csv":String
I just followed the official Rails guide, but it's still getting error. Can anyone suggest some solutions?
NOTE: I just need to read data from the csv file and it does not need to be saved persistently on server.

The way you're passing the arguments to form_tag, all your arguments are getting treated as part of the first form_tag parameter url_for_options, instead of going in part to the second parameter options (see http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-form_tag for the method definition).
Per the guide at http://guides.rubyonrails.org/form_helpers.html#uploading-files, you can use the following syntax to achieve what you want:
form_tag({:action => "upload"},:multipart => true)
You don't need to set :method because it defaults to post.

Related

Argument error for file uploading with rails 3.1 app

I'm trying to set up a very basic system for uploading files to my rails 3.1 app. Before people start throwing paperclip and carrierwave links at me, let me say that this is NOT the solution that I am looking for. I have read quiet a few posts on this topic, however, all the code I saw was either depreciated in rails 3.1 or I just did not understand how people came to a solution to this problem.
Updated view/form: (haml)
%h1 File Upload
= form_for :upload,:url=>{:action => 'uploadFile'},:html => { :multipart => true } do |f|
%p
%label{:for => "upload_file"} Select File
\:
\#{f.file_field 'datafile'}
= f.submit "Upload"
Updated controller:
class UploadController < ApplicationController
def index
render :file => 'upload/uploadfile.haml'
end
def uploadFile
file_param = params[:upload][:datafile]
post = DataFile.save(file_param)
render :text => "File has been uploaded successfully"
end
end
Updated model
class DataFile < ActiveRecord::Base
def self.save(upload)
# Changed Default Destination: [__RAILS_DIR__/public/data]
name = "public/data/" + upload.original_filename
# can haz data directory?
require 'FileUtils'
FileUtils.mkdir_p(File.dirname(name))
File.open(name, "wb") { |f| f.write(upload.read) }
end
end
The Solution:
Above is the correct code I used to add simple uploading functionality to my rails 3.1 app
You are passing unnecessary argument "file" to the uploadFile method. It's an action and passing argument to it is not possible. Just remove the "file" argument.

Newbie - trying to save a datagrid to pdf

I'm using the gem datagrid to display some data. I would like to use ruport to output the data to pdf.
I added this button to my controller.rb=
<%= button_to "PDF", {:controller => :admin_reports, :action => :worequest_pdf }%>
I have this route=
resources :admin_reports do
post :worequest_pdf, :on => :collection
end
And this in the admin_reports_controller.rb=
def worequest_pdf
f = File.new("worequest.pdf", "w")
f.write Ruport::Data::Table(:column_names =>report.header, :data => report.rows).to_pdf
f.close
end
But, it doesn't work - any ideas?
I get:
undefined local variable or method `report' for #<AdminReportsController:0x007fc463566218>
Ruport probably is not your best option. It has not been updated in more than a year. Thats a lifetime in the ruby world. You may want to look at http://ruby-statsample.rubyforge.org/reportbuilder/ or go to https://www.ruby-toolbox.com/ to find something more up to date.
To overcome the error
undefined local variable or method `report'
Should you be using "#report" instead of "report"?

How do I create a temp file and write to it then allow users to download it?

I'm working on my first application and I need some help with allowing my users to download a text file with certain variables that are being displayed on the page.
Take a shopping list for example.
Let's say you allow your users to create a shopping list of products, and then display the shopping list with the items on a shopping list page,
e.g. localhost:3000/list/my-list
Take a look at the example code below (which is probably incorrect):
File.open('shopping_list.txt', 'w') do |file|
file.puts 'Item 1: #{product_1.name}'
file.puts 'Item 2: #{product_2.name}'
file.puts 'Item 3: #{product_3.name}'
end
Which then creates a text file that has the following content:
Item 1: Eggs
Item 2: Butter
Item 3: Bread
Users should then be able to download this file (i don't want this file to be stored on the server) via a download link.
I have no idea how to achieve this, but I'm hoping you guys can guide me. :D
TL;DR
create text files populated with model data (perhaps create a method to achieve this?)
text files should not be stored on the server, but created as users click the download button (not sure if this is the rails way but perhaps someone could show me a better way)
I am assuming there is a resource for List with the attribute name as the name of the list and a list has_many Item which has an attribute description
First off, create a download path change your routes config/routes.rb
resources :lists do
member {get "download"}
end
Now if you run a rake routes in the console you should see a route like
/lists/:id/download
Whats more you should now have the helpers download_list_url & download_list_path to use in your view like
<ul>
<% #lists.each do |list| %>
<li> <%= list.name %> - <%= link_to 'Download List', download_list_path(list) %> </li>
<% end %>
</ul>
In your lists_controller add the action, and as you dont actually want to keep the file on the server disk just stream the data as a string
def download
list = List.find(params[:id])
send_data list.as_file,
:filename => "#{list.name}.txt",
:type => "text/plain"
end
Finally you see I have used a as_file method which you should add to the model (I prefer not to do this stuff in controllers, fat models, skinny controllers). So in the List model
def as_file
output = [self.name]
self.items.each {|item| output << item.description }
output.join("\n")
end
You say you don't want to store the file on the server, but "download" it on request; this sounds like you just want to generate and deliver a text document in response to the download link. There are several approaches, but you want to be sure of setting the mime-type so the browser sees it as a text file instead of an html document.
product_info = [
"Item 1: #{product_1.name}",
"Item 2: #{product_2.name}",
"Item 3: #{product_3.name}",
].join("\n")
render :text => product_info # implies :content_type => Mime::Type["text/plain"]
BTW, your example with open/puts above won't output what you think since single-quoted strings don't interpolate.
so, you wish to :
create text files populated with model data (perhaps create a method
to achieve this?)
text files should not be stored on the server, but
created as users click the download button (not sure if this is the
rails way but perhaps someone could show me a better way)
You have the right idea, here's what to do :
Create a method in your model to generate the text file contents. Let's say this method is called list_data
It seems like you have an existing controller action called my_list. Hence we can call our new method in the controller like so :
.
def my_list
# pre-existing code
respond_to do |format|
format.html # show html page as before
format.text do
send_data #list.list_data, :content_type => 'text/plain', :filename => 'my-shopping-list.txt'
end
end
end
To link to the download, just use link_to :action => my_list, :format => 'text'
See http://api.rubyonrails.org/classes/ActionController/DataStreaming.html#method-i-send_data for full docs on send_data
Caveat & explanations : Using the method above, there isn't really an explicit creation of files, Rails is streaming it for you. Hence this method is not suitable for very large files, or when the generation of the file content will take a while. Use a delayed method to generate the file and store it - the file contents somewhere if that's the case - but we can use send_data once it has been generated
You could try a combination of TempFile and send_file. In your controller action ..
file = Tempfile.new('foo')
file.write("hello world")
file.close
send_file file.path
At Rails 2.3 you can use Template Streaming. Working with Redmine I can remember something like that, you have to adapt for your case. Reference: Streaming and file downloads
require "prawn"
class ClientsController < ApplicationController
# Generate a PDF document with information on the client and return it.
# The user will get the PDF as a file download.
def download_pdf
client = Client.find(params[:id])
send_data(generate_pdf, :filename => "#{client.name}.pdf", :type => "application/pdf")
end
private
def generate_pdf(client)
Prawn::Document.new do
text client.name, :align => :center
text "Address: #{client.address}"
text "Email: #{client.email}"
end.render
end
end
Using the Thong Kuah you must just change the "content_type" param:
def my_list
# pre-existing code
respond_to do |format|
format.html # show html page as before
format.text do
send_data #list.list_data, :content_type => 'text/plain', :filename => 'my-shopping-list.txt'
end
end
end

get content of local html file with rails

what i need is passing local html file to my form, get content of this file and later parse it.
I have this in view
= form_tag :parser, :html => {:multipart => true} do
= file_field_tag :html_file
= submit_tag
And this in controller
def parser
#file = params[:html_file]
end
It seems like form dont get file, just get the string with name of file. How to fix it?
I wrote this to handle uploads in a Rails 2.3.x app. I cannot remember why I had to split this into an if/elsif/else/end statement, but I must have had an error consolidating it to one if statement.
if %w(File Tempfile ActionController::UploadedTempfile ).include?(params[:html_file].class.to_s)
data = params[:html_file].read
elsif %w(StringIO ActionController::UploadedStringIO).include?(params[:html_file].class.to_s)
data = params[:html_file].read
else
logger.error("File does not appear to be a valid class.")
end

Generate PDF file using AJAX call

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

Resources