I use Attachinray with Cloudinary, for direct upload. Everything works very well, except the fact that when I try to save files in my controller, I do not have the original filenames.
Here is a sample of my code:
class User
has_attachments :pictures
end
My form :
= simple_form_for #user do |f|
= f.attachinary_file_field :pictures, as: :attachinary
= f.submit t('.submit')
Once my files are uploaded, when I submit the form, I lost original filenames. Here is what I get for one file :
{"public_id"=>"ryfeummp2ikmzkss4cfy", "version"=>1427873505, "signature"=>"8475fccf9914dd05f6fg622ee39c1cb7ddd25f11", "width"=>78, "height"=>100, "format"=>"png", "resource_type"=>"image", "created_at"=>"2015-03-24T14:48:25Z", "tags"=>["development_env", "attachinary_tmp"], "bytes"=>19882, "type"=>"upload", "etag"=>"1fefdabba402263d18a92238ba4275c9", "url"=>"http://res.cloudinary.com/dd9blzv7x/image/upload/v1427873505/ryfeummp2ikmzkss4cfy.png", "secure_url"=>"https://res.cloudinary.com/dd9blzv7x/image/upload/v1427873505/ryfeummp2ikmzkss4cfy.png"}
Does anyone know if it's possible to keep track of the original filename ?
If you wish to have the original image's filename, you can use something like the following in your controller code:
params[:user][:pictures].each do |picture|
# Do whatever you need with picture.original_filename
end
If you need to store them in your DB, you'll probably need to permit it first and not access them directly.
Alternatively, you can tell Cloudinary to set the uploaded image's filename as the original filename:
f.attachinary_file_field :pictures, as: :attachinary, cloudinary: {use_filename: true}
Note that random characters are added in default. For more information:
http://support.cloudinary.com/hc/en-us/articles/202520762-How-to-upload-images-while-keeping-their-original-filenames-
Related
world!
After implementing Cloudinary's Active Storage Integration, it's easy to make it work in a form.
We just need to add to our simple_form_for a
<%= f.input :photo, as: :file %>
BUT, if we want to use the Cloudinary Upload Widget, there's no straightforward way of adding this file to the form.
What I have tried is:
1- let the widget upload the picture;
2- update the value of a hidden input with the url of the uploaded picture;
3- in the controller, when creating the model, download the picture and attach it to the model:
require 'open-uri'
file = URI.open(photo_url)
#user.photo.attach(io: file, filename: 'profile_photo.jpg')
# [...]
private
def photo_url
params.require(:user).permit(:photo_url)[:photo_url]
end
It works, BUT it uploads twice the same picture and - IMHO - is extremely inefficient.
Any ideas?
Thank you!
Good Luck, Have Fun!
In my form I have field for file uploading which is done with default rails methods, looking like this(I'm using simple_form here, to be clear):
= f.input :spec_url, as: :file
It generates nice and easily field with which user can select any file from his hard drive. But i would like to give users opportunity to simply type this information. since this is field for URL, it should be string field, possible to just fill in, WITH POSSIBILITY to upload something.
How can I achieve this? Some gems maybe?
You will need to have two fields (a string and a file):
= f.input :spec_url, as: :string, id: 'url-field'
= f.input :spec_file, as: :file, id: 'file-field'
Add some javascript (I'm using CoffeeScript) which will set the file name on the spec_url field:
$ ->
$('#file-field').on 'change', (e) =>
$('#url-field').val($(e.target).val())
And then you can do some conditional statements in your Ruby code:
if params[:object][:spec_file]
# Upload file
object.spec_url = params[:object][:spec_file].original_filename
else
# Open URL
object.spec_url = params[:object][:spec_url]
end
Add attr_accessor :spec_file to your model:
attr_accessor :spec_file
This is just a rough idea since I'm not sure what the context is. You might need to modify and style some of the code.
Update
You might also find this question helpful: Rails: upload a file OR store a url
I'm trying to use if-else to render some default image (being a user's avatar) if the 'user' doesn't have an avatar. (This is to avoid the depressing missing.png image). But it's not working so far.
Here is my view (view.html.haml file):
...
.user_avatar
-img_path = defined?(#user.avatar.url) ? "#{user.avatar.default_url}" : "#user.avatar.url"
%img{:src => img_path}
...
Here is my model:
...
attr_accessible :name, :avatar
has_attached_file :avatar :default_url => "assets/images/default_icon.png"
...
Note that if I used #user.avatar.icon.url in the img tag, it will work.
The problem is you are just generating a string, not evaluating the code. When you do:
"#{user.avatar.default_url}"
You are getting just exactly that string. What you probably meant to do was:
#user.avatar.default_url
Not as a string. This way it actually gets evaluated. The same thing goes for "#user.avatar.url".
EDIT
Change:
-img_path = defined?(#user.avatar.url) ? #user.avatar.default_url : #user.avatar.url
To:
-img_path = defined?(#user.avatar.url) ? #user.avatar.url : #user.avatar.default_url
In other words, if the user has a defined avatar URL, then use it, else use the default URL.
Also, consider throwing this in to a method on user, like User#avatar_url, which can do this if/else logic itself.
I think what you're after is:
.user_avatar
-img_path = defined?(#user.avatar.url) ? #user.avatar.url : #user.avatar.default_url
%img{:src => img_path}
To begin with, please check that the url to you default image is correct, if the image is in the app/assets/images folder, default_icon.png should suffice as a url.
Secondly, instead of manually writing the %imgtag, consider using a helper:
= image_tag #user.avatar.url
Thirdly, although I can't test it right now I'm pretty sure that the point of defining a default_url in paperclip is to be able to just call #user.avatar.url and having it return the default url automagically if there is not avatar.
In other words: doing it like your proposal kinda defeats the purpose.
My five cents is that the image url you've provided is wrong and that once you have the correct url, my code above will suffice.
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)
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?