This question already has answers here:
How do you access the raw content of a file uploaded with Paperclip / Ruby on Rails?
(7 answers)
Closed 5 years ago.
I have paperclip running to upload and store files in a non-public directory on the server. Now I want to be able to read the files directly and or feed them into a gem such as axlsx. I'm struggling with even simply looping threw a text file and think I'm missing something basic (as is usually the case).
Here is my first attempt at opening the file:
Paperclip config in application.rb:
config.paperclip_defaults = {:storage => :fog, :fog_credentials => {:provider => "Local", :local_root => "#{Rails.root}/secured_storage"}, :fog_directory => "", :fog_host => "localhost"}
Model:
class Census < ActiveRecord::Base
has_attached_file :censusfile
validates_attachment_content_type :censusfile,
:content_type => ["application/octet-stream", "text/plain"]
end
In the Controller:
def processcensus
#census=Census.find(params[:id])
#file=#census.censusfile.path
end
In the View:
<% File.readlines(#file).read do |line| %>
<%= line %>
<% end %>
This fails because the 'path' returned by Paperclip is the path relative to its sotrage path, not the full path.
UPDATE: If I add the directory (in this case "secured_storage" in from of the path it work as expected. For example:
#file="secured_storage/" + #census.censusfile.path
Not sure if this is at all the way to address this. If it is, is there a way to ask Paperclip where it is storing the files??
I've read where I could use:
Paperclip.io_adapters.for(#census.censusfile).path
But that seems to read the file into an array unless I'm missing something completely. My goal is to be able to loop threw a text file as well as feed an Excel file to axlsx for processing. I would also like to be able to eventually feed these files directly to a user somehow to allow for secure downloads.
I have looked hard for some documentation on all this and haven't found anything that really explains it yet. I'm to that point of just randomly throwing code here or there and hoping something works, which rarely does. Any help/direction that could be provided would be GREATLY appreciated!!!
Mark
I think io adapter can support read
Paperclip.io_adapters.for(#census.censusfile).read
so
<% Paperclip.io_adapters.for(#census.censusfile).read %>
<%= line %>
<% end %>
Use the copy_to_local_file method. This returns a file object on which you can read like on a normal file`.
Related
I would like to upload a file to an Amazon S3 bucket from a rails app. The file comes via a user uploading it. I am having difficulty finding the proper documentation for this because of the different versions of the aws-sdk. Additionally, the acl: :public_read is intentional. I only want authorized users uploading, but anyone should be able to access it.
My current problem is that I am unable to index into a lazy loaded collection. Google provides no useful information for how to not load it lazily.
Here is my relevant code. Note that the controller actions for new and show are empty for now.
messages_controller.rb
def create
# Creates the file object
obj = $S3.bucket(TEST_BUCKET).objects[params[:file].original_filename]
# Uploads the file
obj.write(
file: params[:file],
acl: :public_read
)
end
new.html.erb
<h1>Upload a file</h1>
<%= form_tag messages_path, enctype: 'multipart/form-data' do %>
<%= file_field_tag :file %>
<%= submit_tag 'Upload file' %>
<% end %>
I am using restful routes so the only relevant routing info is resources :messages
I am running rails 6.0.0beta, not that it should matter. I am using version 3 of the aws-sdk gem.
I ended up finding the solution sort of. I do not know how to solve the lazy loading problem but there is a better way.
In the create controller action
def create
obj = $S3.bucket(TEST_BUCKET).object('key_name')
obj.put(body: params[:file].to_io)
end
It'll take some more investigation to apply the attributes to it that I want but this should help anyone else scouring the 3! different versions of the sdk documentation.
The .to_io method on the file is required to get access to the actual file that is in the params[:file] object.
Let's says I have the following entry in my seeds.rb file :
Image.create(:id => 52, :asset_file_name => "somefile.jpg", :asset_file_size => 101668, :asset_content_type => "image/jpeg", :product_id => 52)
If I seed it, it tries to process the image specified, I get this error :
No such file or directory - {file path} etc...
My images are backed up, so I don't really need to create them; but I need the record though. I can't comment the paperclip directive in my model; then it works; but I guess there might be another solution.
Is there another pattern to follow in order to accomplish it ? Or a turnaround to tell paperclip not to process the image ?
Rather than setting the asset columns directly, try leveraging paperclip and setting it as ruby File object.
Image.create({
:id => 52,
:asset => File.new(Rails.root.join('path', 'to', 'somefile.jpg')),
:product_id => 52
})
The other answer here certainly works for most situations, but in some cases it may be better yet to provide an UploadedFile rather than a File. This more closely mimics what Paperclip would receive from a form and provides some additional functionality.
image_path = "#{Rails.root}/path/to/image_file.extension"
image_file = File.new(image_path)
Image.create(
:id => 52,
:product_id => 52,
:asset => ActionDispatch::Http::UploadedFile.new(
:filename => File.basename(image_file),
:tempfile => image_file,
# detect the image's mime type with MIME if you can't provide it yourself.
:type => MIME::Types.type_for(image_path).first.content_type
)
)
While this code is somewhat more complicated, it has the benefit of correctly interpreting Microsoft Office documents with .docx, .pptx, or .xlsx extensions which, if attached using a File object, will be uploaded as zip files.
This especially matters if your model permits Microsoft Office documents but does not allow zip files, because validations will otherwise fail and your object won't be created. It wouldn't have affected the OP's situation, but it affected mine, and so I wish to leave my solution in case anyone else needs it.
hi help me in simple question:
how to released simple download:
i my public/data i have some.txt or some.pdf file ( with some text )
and i want to user click in some button and start download this file.
i do something like that
<%= link_to "Terms" ,:action => :download, :file_name => 'some.txt' %>
def download
send_file "#{RAILS_ROOT}/public/data/#{params[:file_name]}", :type=>"application/zip"
end
But what to do next?
PS if you have some tutorial or example on this subject (like downloading file), I would be very grateful
You are definitely missing a route in your routes.rb:
resources :posts do
get :download, :on => :collection
resource :comments
end
and then you can have a link like:
<%= link_to "Terms" ,:action => :download, :file_name => 'some.txt' %>
that will probably generate something like:
Terms
I think it's still not the best solution, but solves your problem.
I recommend a quick look at this part of the Rails Guides to clarify this:
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
A complete read of this guides is always good and highly recommended too.
What exactly do you mean "what next"? Apart from the fact that the application/zip mime type doesn't match your file's (which is .txt, so presumable text/plain) what you wrote is essentially correct.
Two things to keep in mind, since your file is in the public directory you don't strictly need to use send_file through the controller, you could just write this instead:
<%= link_to "Terms", '/data/some.txt' %>
And second if you're going to use send_file to server larger files you might want to look in to xsendfile instead which improves performance. This has to be supported by your webserver though (using mod_sendfile for apache for example.)
But all that said your code should work as is.
In the comments to the solution for How do I find an image on a page with Cucumber/Capybara, somebody asked:
I can't seem to figure how to get this
to work with URLs generated by
Dragonfly. They look like this:
/media/BAh_some_long_string_AwIw/12_11_52_810_5x5.jpg?s=7e360000, where 5x5.jpg is my file name. I've
tried something like:
//img[#src="/media//#{image}?s=*"]
but it doesn't work. Got any tips? – Ramon Tayag Feb 25 at 4:18
I have a similar problem, only worse - in my case, the generated image paths don't even include a (jpg|png|gif) file name, they only have these really long ids:
<img src="/media/BAhbB1sHOgZmSSIdNGQ4MTEyOGU3ZjViZmQwZTQ4MDAwMDAyBjoGRVRbCDoGcDoKdGh1bWJJIg0yMDB4MjAwIwY7BlQ" />
(Using dragonfly with mongo/gridfs)
These paths get rendered alright, but I can't figure out how to find them in a Cucumber/Capybara step :P
Any ideas? I looked at the Dragonfly's features, but they only test the rendering of the image itself, without detecting it's existence within an html page.
Answering my own question, after talking to Dragonfly's author (he's working on making this easier):
#route
match '/media/:dragonfly/:file_name', :to => Dragonfly[:images]
#model
class Store
include MongoMapper::Document
key :photo_uid, String
key :photo_name, String
image_accessor :photo
end
#view
<%= image_tag #store.photo.thumb('274x207#').url(:suffix => "/#{#store.photo_name}") if #store.photo %>
#cucumber
Then I should see the image "my_photo.png"
Then /^I should see the image "(.+)"$/ do |image|
page.should have_xpath("//img[contains(#src, \"#{image}\")]")
end
The key is adding an [attachment]_name field to the model, which Dragonfly populates automatically, and then passing it on as a suffix to url(). And the routes needs to allow for a :file_name param besides the generated dragonfly identifier.
This is tough one to explain so i'll try my best, and hopefully edit the question if people need more information. I am not providing exact code, but merely an example of the issue.
I am using rails 2.3.8. I am on Unix.
I have a bunch of files under a directory not Apache accessible. (i.e. /data/files/file.rpk)
I have the following in my view.
link_to "RPK File", :controller => 'mycontroller', :action=> 'myaction', :file => '/data/files/file.rpk'
I have the following in my controller.
def myaction
if FileTest.exists?(params[:file])
render :file => params[:file]
end
end
When i select the link on the page i get a download prompt for my desired file, but the name of the file is "myaction" instead of the filename.
Thoughts on how i could get it named correctly?
Sounds like a job for send_file. The x_sendfile option prevents that your workers keep busy while transferring the actual file. You can read more about that in this blogpost.
send_file path_to_file_on_filesystem, :type => "application/zip", :x_sendfile => true
You want to use send_data with the :filename option. See the API documentation.
You want to be extremely careful with this, though. Never ever trust the client/user! They will send file=../../../../etc/group or something in order to read arbitrary files on your system, so be very sure to sanitize that value before passing it to any file-reading methods.