Create link_to for downloading a File from Paperclip gem? - ruby-on-rails

I'm building a file management system using the Paperclip gem and I need to download file.
What would be the parameters of the link_to method?
I have the following line in my model:
has_attached_file :box

Suppose your model is Boxholder
If you have #boxholder instance variable in your controller like:
#boxholder = Boxholder.find(params[:id])
Then the following line could be your solution:
<%= link_to #boxholder.box_file_name,#boxholder.box.url %>

Related

Get path to ActiveStorage file on disk

I need to get the path to the file on disk which is using ActiveStorage. The file is stored locally.
When I was using paperclip, I used the path method on the attachment which returned the full path.
Example:
user.avatar.path
While looking at the Active Storage Docs, it looked like rails_blob_path would do the trick. After looking at what it returned though, it does not provide the path to the document. Thus, it returns this error:
No such file or directory # rb_sysopen -
Background
I need the path to the document because I am using the combine_pdf gem in order to combine multiple pdfs into a single pdf.
For the paperclip implementation, I iterated through the full_paths of the selected pdf attachments and load them into the combined pdf:
attachment_paths.each {|att_path| report << CombinePDF.load(att_path)}
Use:
ActiveStorage::Blob.service.path_for(user.avatar.key)
You can do something like this on your model:
class User < ApplicationRecord
has_one_attached :avatar
def avatar_on_disk
ActiveStorage::Blob.service.path_for(avatar.key)
end
end
I'm not sure why all the other answers use send(:url_for, key). I'm using Rails 5.2.2 and path_for is a public method, therefore, it's way better to avoid send, or simply call path_for:
class User < ApplicationRecord
has_one_attached :avatar
def avatar_path
ActiveStorage::Blob.service.path_for(avatar.key)
end
end
Worth noting that in the view you can do things like this:
<p>
<%= image_tag url_for(#user.avatar) %>
<br>
<%= link_to 'View', polymorphic_url(#user.avatar) %>
<br>
Stored at <%= #user.image_path %>
<br>
<%= link_to 'Download', rails_blob_path(#user.avatar, disposition: :attachment) %>
<br>
<%= f.file_field :avatar %>
</p>
Thanks to the help of #muistooshort in the comments, after looking at the Active Storage Code, this works:
active_storage_disk_service = ActiveStorage::Service::DiskService.new(root: Rails.root.to_s + '/storage/')
active_storage_disk_service.send(:path_for, user.avatar.blob.key)
# => returns full path to the document stored locally on disk
This solution feels a bit hacky to me. I'd love to hear of other solutions. This does work for me though.
You can download the attachment to a local dir and then process it.
Supposing you have in your model:
has_one_attached :pdf_attachment
You can define:
def process_attachment
# Download the attached file in temp dir
pdf_attachment_path = "#{Dir.tmpdir}/#{pdf_attachment.filename}"
File.open(pdf_attachment_path, 'wb') do |file|
file.write(pdf_attachment.download)
end
# process the downloaded file
# ...
end

How to view/download file under a custom subdir in Rails 4?

After uploading a file, we would like to make the file available for view and download. The file could be in common format such as pdf, jpg or xls. After a user clicks the file name, the file is downloaded and opened by local app on user's PC. Here is what we did:
<%= link_to r.file_name, r.storage_subdir + '/' + r.file_name %>
r.storage_subdir returns storage/multi_item_orderx_order/15. storage is a subdir under root. r.file_name returns IMG_3002.jpg
When clicking the file name, there pops up an error:
No route matches [GET] "/upload/storage/multi_item_orderx_order/15/IMG_3002.jpg"
(Not sure how upload was put in front of storage). Used save link as to download and the file is only a partial in size and there shows nothing after clicking it. What is the right way to both view and download a file? Or at least to download a file.
If you don't understand how to render uploaded file then you uploading it wrong. Here is a small tutorial for you.
How to implement file upload function in your rails application
First of all add this gems to your Gemfile and then execute bundle install in console.
gem "rmagick"
gem "carrierwave"
Let's imagine that you have model User and you need to give users ability to upload profile picture. When bundler install successfuly installed new gems we need to create Uploader via generator.
rails g uploader avatar
And let's configure it:
class AvatarUploader < CarrierWave::Uploader::Base
include CarrierWave::RMagick
storage :file
def store_dir
"uploads/#{mode.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
version :thumb do
process resize_to_limit: [64, 64]
end
end
Few words about this configuration: we said carrierwave to use RMagick gem, said which storage we would like to use and where data must be stored and implemented resize for thumbnails.
Now need to add column avatar to users table. Let's create migration:
rails g migration add_avatar_to_users avatar:string
And now lets mount our uploader in User model:
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
end
That's all! Carrierwave configured and ready to use in your application! Now you can create view like:
<%= form_for #user, html: {multipart: true} do |f| %>
<%= f.file_field :avatar %>
<%= f.submit %>
<% end %>
This form will give you ability to upload avatar. In controller you need to pass params[:user][:avatar] to model to create\update user's avatar.
And if you need to render image to view you can use something like this:
<%= image_tag #user.avatar_url(:thumb) %>
or
<%= image_tag #user.avatar.thumb.url %>
Don't forget to install imagemagick headers via system's package manager (apt-get \ yum \ pacman \ brew \ etc) because if you will not do it, bundler will fall.
If you got any questions, check out carrierwave github page and carrierwave documentation.

carrierwave not creating method

I am trying to add an image upload to a form through carrierwave and that displaying the picture through an image tag.
Therefore I generated a Picture Uploader and a migration
$ rails generate uploader Picture
$ rails generate migration add_picture_to_cpostings picture:string
and migrated.
I also added
mount_uploader :picture, PictureUploader
to the cpostings model.
In the controller I permitted the picture attribute
def cposting_params
params.require(:cposting).permit(:content, :spots, :class_date, :class_time, :title, :picture)
end
The upload with
<%= f.file_field :picture, accept: 'image/jpeg,image/gif,image/png' %>
in the form works, but when I try to display the picture in the posting with
<%= image_tag cposting.picture.url if cposting.picture? %>
I get the following error:
undefined local variable or method `cposting' for #<#:0x007f9629cc76f0>
According to railstutorial.org, the method should be created automatically by carrierwave. Do you have any idea why it doesn't work here?
undefined local variable or method `cposting' for #<#:0x007f9629cc76f0>
From the error message it's clear that, your view does not find the cposting variable. You have to declare this cposting variable inside the corresponding controller's action as an instance variable (#cposting) and then it will be available in your view file and you will not get this error.
Update
Change:
<%= image_tag cposting.picture.url if cposting.picture? %>
To:
<%= image_tag #cposting.picture.url if #cposting.picture? %>

How to give the xls file link in Ruby on Rails?

How to give the xls file link in ruby. This is my file path
link_to "Excel", "/#{RAILS_ROOT}/public/reports/10014_ByNetwork.xls", :target=>"_blank"
when i given above link that is converting like this
Excel
So its not working. actually i need like this
Excel
Please give me exact path...
#Gagan Your syntax is incorrect. You should test your answers before posting them. This is the correct way:
<%= link_to 'Excel',"/reports/10014_ByNetwork.xls", target: "_blank" %>
OR
<%= link_to 'Excel',"/reports/10014_ByNetwork.xls", :target=>"_blank" %>
You have missed out the comma after the second closing double quotes.
if you have more than one file to download and you have to use different links along your views I could recommend you the next approach too:
Add a download xls get resource and route helper to your routes.rb file like:
get "downloads/xls/:id" => "downloads#xls", :as => :download_xls
In your controller, for my my example I'll use app/controllers/downloads_controller.rb we will need to add the xls action to stream data with send_file:
def xls
if params[:id]
send_file("#{Rails.root}/public/reports/#{params[:id]}.xls",
filename: "#{params[:id]}.xls",
type: 'application/excel',
disposition: 'attachment')
end
end
You can read more about it here:
http://apidock.com/rails/ActionController/DataStreaming/send_file
And finally in your view you'll use the link_to helper with our declared above download_xls_path route and the filename as param:
<p>
Click to download: </br>
<%= link_to "NameOfYourXlsFile.xls", download_xls_path(NameOfYourXlsFile) %>
</p>
Are you sure that you need file:// link? It is not operated by rails server and will work only on your machine. Maybe it will be better to generate link like this: "http://you_server_url.org/public/file.xml". It works fine on local and remote app, and you can manage file-sending by controller action.
Try this in your view file:
<%= link_to 'Excel',"/reports/10014_ByNetwork.xls" :target=>"_blank" %>

Rails upload CSV file with header

I am using Ruby 1.9.2 with Rails 3.2.1.
I would like to create a view to upload a CSV or tab delimited file, and displays the contents of the file on the same page using a table or pagination display, then process that data in JavaScript.
How can I do this? Please walk me through any code samples you have, I am a total noob in Ruby also.
First, write a view to upload your file. You can use Paperclip for this.
Assuming you have a resource Csv, your upload form could look like this:
<%= form_for #csv, :url => csv_path, :html => { :multipart => true } do |form| %>
<%= form.file_field :attachment %>
<% end %>
Your model:
class Csv < ActiveRecord::Base
attr_accessible :attachment
has_attached_file :attachment
end
Your controller actions:
def create
#csv = Csv.create( params[:csv] )
# your save and redirect code here
end
def show
#csv = Csv.find(params[:id])
end
Having that, you can use something like this in your view:
CSV.foreach(#csv.attachment.path) do |row|
# use the row here to generate html table rows
end
Note: this is just a general idea of how this can be done and you need to have the the resource added to your routes, Paperclip gem installed and configured, etc - read the doc on how to do all that.
Just use a nice Ruby gem for parsing CSV files. This should point you in the right direction. http://fastercsv.rubyforge.org/

Resources