Paperclip & Rails Api - ruby-on-rails

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 :)

Related

Deleting a public folder or file from a Rails3 view?

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?

Associating a file uploaded with Carrierwave_Direct with an object

I'm uploading files directly to S3 using the carrierwave_direct gem and everything is going smoothly. However, when amazon redirects back to the URL specfied in success_action_redirect, I'm not associating the uploaded file with the object.
My controller looks like
def edit
#excel_version = ExcelVersion.find(params[:id])
#uploader = #excel_version.excel_everest_macro
#uploader.success_action_redirect = edit_admin_excel_version_url
end
def update
#excel_version = ExcelVersion.find(params[:id])
#excel_version.assign_attributes(params[:excel_version])
#excel_version.save
end
And I have a hidden form field in my view that looks like
= form_for #excel_version do |form|
= form.hidden_field :key
So in my update action I just use #excel_version.assign_attributes(params[:excel_version])
and the key returned by Amazon makes it into the model just fine. However, the uploader mounted on the #excel_version object doesn't get url and I can't set up a link to then download the file.
Any suggestions on how I can use the S3 parameters returned to me to associate the file with the model as carrierwave would normally do?
Thanks!
P.S. another answer on here suggested reading the carrier_wave direct documentation on github, which I have and have found unhelpful in this respect.
To associate the image to the model what you can do is create a method in your controller which would use the params from amazon and create the image link
For example you can do -
def image_url
respond_to do |format|
format.json { render :json => { :filelink => "https://s3.amazonaws.com/#{params[:bucket]}/#{params[:key]}" } }
end
end
What this code will do is when amazon does a success redirect to image_url method it will use the parameters "bucket" and "key" to create a exact link to your image. (The params which are sent have both key and the bucket name)
Now you can put this image url in the hidden object on your view so that when the form is posted to the server the url also gets posted along with it. Which you can associate to your model.
Hope this helps. It worked for me.
So my problem was that I had the hidden_field :key field on the wrong form. I mistakenly put the field on the direct_upload_form_for #uploader form that uploads the file to S3.
Of course, you need the :key field on a form that the user returns to after posting the file to S3 (ie at the url passed in to the success_action_redirect method). It is there that S3 will return the key in the params and you can associate it with your model.
Thanks for all the helpful suggestions!

Ruby on Rails, pass Image from one object to another or from NEW to CREATE

I'm pretty new to Ruby on Rails.
I changed this thread, because i recognized that I was searching for my problems' solution at the wrong end.
Here's my Problem:
I got a Class ProfileProposal which I upload an Image with(Using CarrierWave).
Now I want to convert ProfileProposal to another class, called Profile.
So I pass all the Information to the NEW-Form of Profile.
Works fine with strings, but not with Images.
What I've already tried/done:
Pass the Image as GET Param to the Create Method:
<%= form_for #profile, :url => { :action => "create", :controller => "profiles", :image => #profile_proposal.image } do |f| %>
#
Which now works, so I DO have the image-url.
What's not working is the following:
#profile = Profile.new(params[:profile], :image => new_image_url)
# OR
#profile.image = new_image_url
#profile.image still has the default value given by Carrierwave.
Thanks in advance!
I'm coming from using paperclip, not carrierwave, so I'll try to keep this high level. But I have an idea for you. Maybe you can set the filename of the new attachment before it exists, then move the image to that path. With paperclip this would play out like:
#profile.image_file_name = "profile.jpg"
# creates the directory of the new path. There's probably a better way to do this:
FileUtils.mkdir_p #profile.image_file_path.gsub(/[^\/]*$/,'')
FileUtils.mv #profile_proposal.image_path #profile.image_path
You should embed a hidden field in that Profile form, referencing ProfileProposal by some ID. Then while handling the form server side, after everything is validated and ready for save, you should copy the image using some read/write methods, from ProfileProposal instance to Profile instance. I'm not sure how CarrierWave wants you to do this.
I finally fixed that problem, by using paperclip and creating a new Instance via
Profile.create(:name => #profile_proposal.name, :image => #profile_proposal.image)

How to upload an image to S3 using paperclip gem

For the life of my I can't understand how the basic paperclip example works. There's only one line included in the controller, and that's
#user = User.create( params[:user] )
I simply don't understand how that's all that is needed to upload an image to s3. I've changed the example quite a bit because i wanted to use jquery file uploader rather than the default rails form helper, so I'm at the point where an image is being POSTed to my controller, but I can't figure out how I'm supposed to take the image from the params and assign it as an attachment. Here's what I'm seeing the logs:
Parameters: {"files"=>[#<ActionDispatch::Http::UploadedFile:0x132263b98 #tempfile=#<File:/var/folders/5d/6r3qnvmx0754lr5t13_y1vd80000gn/T/RackMultipart20120329-71039-1b1ewde-0>, #headers="Content-Disposition: form-data; name=\"files[]\"; filename=\"background.png\"\r\nContent-Type: image/png\r\n", #content_type="image/png", #original_filename="background.png">], "id"=>"385"}
My JS is very simple:
` $('#fileupload').fileupload({
dataType: 'json',
url: '/my_url',
done: function (e, data) {
console.log('done');
}
});`
What would be helpful for me to know is how I can strip the file data from the POSTed parameters given above and pass it to paperclip. I'm sure that I'll have to assign the attachment attribute a value of File.open(...), but I dont know what source of my file is.
I've spent a ridiculous amount of time trying to figure this out and I can't seem to get it. I've tried uploading directly to s3, but the chain of events was terribly confusing, so I want to get this simple pass-through example completed first. Thanks so much for any help you cna give!
You need a few more pieces and it will help if you can show the exact code you're using.
Paperclip can post to S3 by using:
http://rubydoc.info/gems/paperclip/Paperclip/Storage/S3
When your controller creates a User model, it is sending along all the params. This is called "mass assignment" (be sure to read about attr_accessible).
When your model receives the params, it uses the Paperclip AWS processor, which uploads it.
You need the AWS gem, a valid bucket on S3, and a config file.
Try this blog post and let us know if it helps you:
http://blog.trydionel.com/2009/11/08/using-paperclip-with-amazon-s3/
UPDATE 2013-04-03: Pleases see Chloe's comment below-- you may need an additional parameter, and the blog post may be outdated.
If you want to do it manually, approach it like this:
# In order to get contents of the POST request with the photo,
# you need to read contents of request
upload = params[:file].is_a(String)
file_name = upload ? params[:file] : params[:file].original_filename
extension = file_name.split('.').last
# We have to create a temp file which is going to be used by Paperclip for
# its upload
tmp_file = "#{Rails.root}/tmp/file.#{extension}"
file_id = 0
# Check if file with the name exists and generate unique path
while File.exists?(tmp_file) do
tmp_file_path = "#{Rails.root}/tmp/file#{file_id}.#{extension}"
id += 1
end
# Let's write the file from post request to unique location
File.open(tmp_file_path, 'wb') do |f|
if upload
f.write request.body.read
else
f.write params[:file].read
end
end
# Now that file is saved in temp location, we can use Paperclip to mimic one file
# upload
#photo = Photo.new :photo => File.open(tmp_file_path)
# We'll return javascript to say that the file is uploaded and put its thumbnail in
# HTML or whatever else you wanted to do with it
respond_to do |format|
if #photo.save
render :text => "Success"
else
render :text => #photo.errors
end
end
You can rewrite your create or whatever you use as the url to which you are POSTing the form.
This bit:
"files"=>[#<ActionDispatch::Http::UploadedFile:0x132263b98 #tempfile=# <File:/var/folders/5d/6r3qnvmx0754lr5t13_y1vd80000gn/T/RackMultipart20120329-71039-1b1ewde-0>
is the part (I think) that holds the file contents that are posted in the form.
In Rails, the User model will have a helper: has_attached_file
Passing the [:params] to the User.create method allows that helper to pick up the file contents, do any processing on them (eg resizing etc based on attributes supplied to the helper) and then push the image(s) to your storage (eg S3 or whatever - S3 credentials are passed to the helper).
Hopefully that explains the 'how does it do it?' question
re the jQuery bit.. not sure what the code should be there, but why not use the Rails form with :remote => true and handle the response in jquery?

How do I get the base URL (e.g. http://localhost:3000) of my Rails app?

I'm using Paperclip to allow users to attach things, and then I'm sending an email and wanting to attach the file to the email. I'm trying to read the file in and add it as an attachment, like so:
# models/touchpoint_mailer.rb
class TouchpointMailer < ActionMailer::Base
def notification_email(touchpoint)
recipients "me#myemail.com"
from "Touchpoint Customer Portal <portal#touchpointclients.com>"
content_type "multipart/alternative"
subject "New Touchpoint Request"
sent_on Time.now
body :touchpoint => touchpoint
# Add any attachments the user has included
touchpoint.assets.each do |asset|
attachment :content_type => asset.file_content_type,
:body => File.read(asset.url)
end
end
end
This gives me the following error No such file or directory - /system/files/7/original/image.png?1254497688 with the stack trace saying it's the call to File.read. When I visit the show.html.erb page, and click on the link to the image, which is something like http://localhost:3000/system/files/7/original/image.png?1254497688, the image is displayed fine.
How can I fix this problem?
Typically root_url should provide this.
File.read is expecting a file path, not a url though. If you are generating the images, you should call the image generating code and return the bytes of the generated image instead of calling File.read(…)
asset.url returns the URL to the file. This is usually /system/classname/xx/xx/style/filename.ext. You'd put this in an image_tag.
You want asset.path. It returns the full path to the file, which will usually be something like /home/username/railsapp/public/system/classname/xx/xx/style/filename.ext
HTH.
request.env["HTTP_HOST"]
I don't know why this one line of code is so elusive on the web. Seems like it should be up front and center.
as ZiggyTheHamster is saying: the asset.url is the generated url that would be used on webpages (which is why you're getting the unix-style directory slashes, as pointed out in the comments.)
asset.path should give you the OS-aware path to the file, but even that isn't needed with paperclip.
Paperclip::Attachment is already an IOStream.
You just need :body => asset like so:
touchpoint.assets.each do |asset|
attachment :content_type => asset.file_content_type,
:body => asset
end

Resources