Deleting a public folder or file from a Rails3 view? - ruby-on-rails

I have a user model where users can upload their profile image, using the Paperclip gem. This all works fine and stores the file in the /public/images/#{user.id}/medium or original or small directory.
However I need to create an method to be able to delete these files, could someone help me with this?
Here is the code I have so far:
app/views/users/index.html.erb:
<%= link_to "Delete", method: :file_cleanup, action: :destroy %>
app/controllers/users_controllers.rb:
def file_cleanup
File.delete(Rails.root + 'public/#{current_user.image.url}')
redirect_to :action => :edit
end
I have not added any routes as the page seems to load without any errors.

It should be as simple as:
def delete_image
#user.image.destroy
end
I'd use that as a hook like before_destroy :delete_image.
See: Rails Paperclip how to delete attachment?

Related

Rails 7 help DRYing out image attachments?

Bear with me, I am new to posting and Rails so sorry if I mess up phrasing!!
I am working on a Rails app with many similar models. Each view has a _form.html.haml partial that differs in content but contains similar components, such as buttons to submit, delete, etc. Every model has_many_attached photos, and in the form you can add or delete photos. The haml for deleting photos looks like this, where variable is replaced with whatever view _form.html.haml is in:
.gallery#form
- #VARIABLE.photo.each_with_index do |image, index|
.overlay-container
.img-square{ :style => "background-image: url(#{rails_blob_url(photo(#VARIABLE, index))})", :alt => "Photo of #{image}" }
= link_to("Delete", delete_image_attachment_VARIABLE_url(image), method: :delete, class: 'button delete overlay')
To make the delete work on each photo, this code is in each controller:
def delete_image_attachment
#photo = ActiveStorage::Attachment.find(params[:id])
#photo.purge
redirect_back fallback_location: #VARIABLE
flash[:success] = 'Photo was successfully deleted.'
end
And routes.rb has this chunk of code for each model:
resources :VARIABLE do
member do
delete :delete_image_attachment
end
end
However, I have about a dozen models I need to do this on. My goal is to bring the gallery into a new partial, since it will be used in every _form regardless of the other content. However, the delete function (though the same for every controller) is tied to the controller/routes.rb of each model.
There must be some way of DRYing this functionality into a couple files instead of copy-pasting for each model, but my Google searches have not turned up anything. So, any guidance or better Rails convention is greatly appreciated!
If I'm understanding the structure properly, it sounds like you would want to do something like the following:
Create a top-level controller that handles deleting images
This could be used by any page.
This would require the following query parameters:
id the photo's ID to delete by.
redirect where to redirect the user after the action is completed.
Routes
Now there will only be 1 route to handle the controller above.
Create a reusable partial
For rendering a collection of images with a redirect url that allows you to set the following state for the partial:
photos a collection of images to render.
redirect_url this is passed as a query parameter to the centralized delete image controller.
Thoughts & Mocked Examples
This should be able to DRY up your implementation. Currently the only thing I see that couples the view with the deletion is the redirect URL. By abstracting that out and moving that essentially to a parameter for the partial will allow for re-use and flexibility.
You've already identified your coupling via #VARIABLE, here's a quick mock of how I would expect it to end up looking like:
Partial Template
.gallery#form
- #photos.each_with_index do |image, index|
.overlay-container
.img-square{ :style => "background-image: url(#{rails_blob_url(photo(#VARIABLE, index))})", :alt => "Photo of #{image}" }
= link_to("Delete", delete_image_attachment_url(image, redirect: #redirect_url), method: :delete, class: 'button delete overlay')
Ths would require: photos, and redirect_url
So make sure to set #photos and #redirect_url on the consuming controller.
Example with instance properties to access in the template
#photos = GET_PHOTOS_HERE
#redirect_url = 'some-redirect-path'
render partial: 'photos_partial'
Example with locals parameter for the template
photos = GET_PHOTOS_HERE
render partial: 'photos_partial', locals: { photos: photos, redirect: 'some-redirect-path' }`
Note: You may need to change how you access the local variables in the template.
https://guides.rubyonrails.org/layouts_and_rendering.html#passing-local-variables
Controller
def delete_image_attachment
#photo = ActiveStorage::Attachment.find(params[:id])
#photo.purge
redirect_back fallback_location: params[:redirect]
flash[:success] = 'Photo was successfully deleted.'
end
Routes
Here you would only have the single route for deleting any image attachment, and point at the single controller above.
delete 'resources/image_attachment/:id', to: 'resources#delete_image_attachment'
Note: Replace "resources" with whatever your controller name is, or the scoping/naming you would like.
PS: It's been a while since I've done Rails so I'm not completely certain on the accuracy or your environment.

"Too many open files" error uploading with Paperclip

I'm using Rails 3.2.13 and Paperclip to upload/store images for a photo website. The form is nested for albums and photos. The Album model contains the lines
attr_accessible :photos_attributes
accepts_nested_attributes_for :photos
And the Photo model
has_attached_file :photo
So the form has an input
<input type="file" name="album[photos_attributes][][photo]" multiple="true">
It works perfectly for a few photos, but when I try to upload a ton, as a user might since it's a photo website, I get the error "Too many open files."
From what I read, it seems like it's because of the way Paperclip handles opening files and not closing them, so I need to manually close them? The Album#create controller action looks like this:
def create
#album = Album.new(params[:album])
if #album.save
redirect_to album_url(#album)
else
render :new
end
end
What do I need to add here to get this to work? Thanks in advance.

Rails: download .to_pdf stuck on old revision of object

I have a rails app and stuck on a problem when trying to create a download link to some dynamic generated data.
I've placed a .to_pdf method in my Folha model. And on controller folhas_controller.rb:
def show
nome = "#{#folha.nome_do_mes}-#{#folha.ano}-#{DateTime.now.to_i}"
#folha = Folha.find(params[:id])
respond_to do |format|
format.pdf do
pdf = #folha.to_pdf(view_context)
send_data pdf.render, filename: "#{nome}.pdf", type: "application/pdf"
end
end
end
The issue is that the .to_pdf method is executed only the first time i click the link. For all other clicks it gives me the same file, no matter if my object was updated.
I dont know where in my stack this is ocurring.
It only happens in production. Im using Rails 3.2.6 on Thin 1.4.1 deployed to heroku.
Please help =)
I used a workaround, pretty sure its not the proper way:
routes.rb
resources :folhas do
resources :servicos
end
match 'exportar/:id/:dummy' => 'folhas#show', as: "exportar"
and then on the view:
<%= link_to image_tag('pdf_small.png'), exportar_path(id: folha.id, dummy: DateTime.now.to_i, format: 'pdf'), class: 'item' %>
that way a different link is placed each time the view is rendered.

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

Paperclip & Rails Api

I have a photo rails app using paperclip. My model called photo and the request parameter also photo.So when i am trying to upload via curl i use : curl -F "photo[photo]=#/pics/pic.jpg" http://something/photos.xml .
That's works fine! How can i change the photo[photo] parameter to "photo" or "media" or something else? How can i change the endpoint url? (ex. http//something/upload.xml)
thanx!
any help will be highly appreciated, :-)
What you could do is setup another controller and work with it. What paperclip does is just setup an extra "photo" attribute and methods, thus reusing Rails .new and .update_attributes own methods. That way, when you call /photos.xml with that info, what you are doing is just a regular post photo action, with the added benefit of setting up it's picture.
When you do Object.photo = YOUR_PHOTO, you are actually using Paperclip code.
So, you could work with something like:
class ApplicationController < ActiveController::Base
def upload
photo = Photo.new
photo.photo = params[:photo]
# ... extra code
photo.save
render :text => "Ok"
end
end
And add a route like:
map.upload "/upload(.:format)", :controller => "application", :action => "upload"
(or it's Rails3 equivalent if you are using it)
That way, when you do 'curl -F "photo=#/pics/pic.jpg" http://something/upload.xml', you will invoke the upload action and create a photo using the 'photo' parameter. The photo = params[:photo] will take the tempfile you've uploaded and continue with the usual paperclip tasks :)

Resources