Ruby on Rails, Formtastic Gem image upload - ruby-on-rails

I'm uploading an Image to my Image model using formtastic Gem.
User model has many images
I've created my form using formtastic gem:
= semantic_form_for #user, :remote => true, :html => { :class => 'formtastic' } do |f|
= f.semantic_fields_for :images, #image do |image|
= image.input :file
:label => false,
:as => :file
It is required to upload an image. The form has two more fields Name and description!
After choosing a file to upload it shows the chosen file name.
If I fill out all the required fields and hit submit it works perfectly fine but If I hit submit before filling out all required field then form will ask me to fill out required fields and also asks me choose the file again.
Expected behavior is that form should only ask me to fill out missing required field and it should remember previously chosen file.
Does anyone know why it's doing this?
Any help will be greatly appreciated

When the form is submitted, the file is attached to the request. When the error page returns, the values of the form fields are supplied by the server from the submitted info to rewrite the page. However, the server does not know anything about where the file came from on your system, so cannot re-fetch the file from your system to pre-populate the form.
Anything that would pre-populate the file field would have to have the ability to go into the filesystem on your computer. This is only allowed if you browse to the file yourself.
A couple of solutions are proposed here:
How to persist file upload fields after a rails validation error.
The first couple answers recommend using an attachment-management gem like Paperclip; if you want to avoid using another gem I like the third, which recommends client-side validation of the data through javascript - basically prevent the user from submitting the form to the server with bad info in the first place. Of course you still want to validate on the server side.

Related

Preventing users of my web application from modifying image id while uploading to cloudinary

I am building a rails web application where users can upload images from the browser to cloudinary. I am thinking a bit ahead, and want to prevent users from playing with the parameters being passed, in order not to have undesirable output in may pages (empty images).
In my view I have the code for the cloudinary uploader:
<%= form_tag(some_path, :method => :post) do %>
<%= cl_image_upload_tag(:image_id) %>
...
<% end %>
Now, when the user upload the image it goes directly to cloudinary, and the process returns :image_id. When the user accepts the image, I receive it in my controller like this:
if params[:image_id].present?
preloaded = Cloudinary::PreloadedFile.new(params[:image_id])
raise "Invalid upload signature" if !preloaded.valid?
#model.image_id = preloaded.identifier
end
That image ID gets saved in my database for future retrieve.
Now what if the user uses a tool such as "curl", or any other method that would allow him to modify the returned :image_id before submitting it to the controller ? I will have a wrong value in my database that would be difficult to find and an empty image when I try to show it in my pages. What is the best method of avoiding this ?
Regards,
When using cl_image_upload_tag, the value of params[:image_id] will contain a signature. The signature is validated by PreloadedFile#valid? You can know for sure that this public_id and version were returned by Cloudinary. If needed, you can also verify the version (unix timestamp) is reasonably recent.

Paperclip - Image attributes not passed in the query INSERT

I have all the default settings from paperclip's website. When I create a new application and put the settings in, once I save my model, the 'photo' paperclip attribute gets saves nicely, all is fine (here is the SQL INSERT sample):
"photo"=>#<ActionDispatch::Http::UploadedFile:0x007f990a3d92d0
#original_filename="Screen Shot 2011-10-21 at 6.02.56 AM.png",
#content_type="image/png", #headers="Content-Disposition: form-data;
name=\"event[photo]\"; filename=\"Screen Shot 2011-10-21 at 6.02.56
AM.png\"\r\nContent-Type: image/png\r\n"
and I get:
[paperclip] Saving attachments
Now in my app other app where I use Devise and Cancan, I have the exact same Paperclip setting, I do get the
[paperclip] Saving attachments.
But, It does not save the 'photo' and don't see the photo attributes getting defined at all.
Now I've seen a similar post that gets solved adding
attr_accessible photo
to the model, and I did that, and still it's not working.
I've been wasting so many hours on this, sometimes I feel like I should have just created my own image upload...
Any idea? Thx!
and by the way. Same issue on a simple scaffold object where I add
attr_accessible :photo
If you're using a framework like jQuery Mobile or some sort of AJAX/PJAX mechanism, your uploads will be lost as POST in Ajax, since JS cannot read your local files...
You'll have to use some uploadify-like plugin or submit your form the "regular" way.
Edit:
To make things clear, the easiest way will be to add data-ajax="false" as a form attribute. In Rails 3, using the form helper, you'd write something along those lines:
<%= form_for (#my_object, html: {data: {ajax: false}}) do |f| %>
...
<% end %>

How to update avatar/photo of a model directly?

This is rails 3.0.x. I was just wondering how to update an attribute of a model's photo/avatar directly without prompting the user to upload from his/her system?
I am using Paperclip to attach a photo to a model; It has the extension so that a user can use a URL to upload a photo. This works.
Now, I was looking at Canvas2Image, and it returns an image of the canvas so user's can download them.
I was wondering how to use the URL that Canvas2Image returns so I can update the current model's photo directly?
For now, I have this form that prompts the user to update the current model's avatar/photo:
<% form_for(#prototype,
:url=>{:controller=>"prototypes",
:action=>"update"},
:html => { :multipart => true }) do |f| %>
<%= f.file_field :avatar %><br><br>
<%= f.text_field :image_url %><br><br>
<%= submit_tag "Save Prototype" %>
<% end %>
Any help is appreciated, thanks!
From your link to Canvas2Image above it looks to me like you are trying to handle Base64-encoded images (like data:image/octet-stream;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wB).
Paperclip expects a Tempfile object, which is created behind the scenes for you when you upload an image. It is possible to fake a Tempfile by using a StringIO object and adding content_type and original_filename instance methods.
I posted a gist with the code I used to accomplish this in one of my projects. https://gist.github.com/1012107.
For you to do something similar you'd need to remove the beginning portion of the Canvas2Image URIs data:image/octet-stream;base64, and use the remaining Base64 code as the image_data. You'd need a way to provide or work around the content-type and filename.
If you just want to use normal URLs like http://example.com/image.jpg then you have several available options.
You could simply save the URL and use it as an image source on your pages. I know this isn't always an option, and you have no control over the availability of the image.
Otherwise, there are several utilities such as net/http and curl that you could use to download the image. If you think you want to go this route then you might also consider downloading the images using delayed jobs or a similar background process. That way your UI doesn't hang if the image download is slow.
If you want to fetch the gravatar using users' email address you can use the following code snippet.
In a helper:
def avatar_url(user)
gravatar_id = Digest::MD5.hexdigest(user.email.downcase)
return "http://gravatar.com/avatar/#{gravatar_id}.png?s=48&d=#{CGI.escape(default_url)}"
end
In your view:
<%= link_to(image_tag(avatar_url(user)), user_path(user))%>
That's it! You need not to ask user to upload your photo in your system. It will show the photo of his gravatar account. Please let me know whether it solves your problem.
This link might be what you're looking for
However, if you haven't done much work with paperclip yet, I would recommend you to swap to CarrierWave.
The same thing is done with two lines of code:
#prototype.image_remote_url = canvas2image_url #you should change this
#prototype.save

How to keep file field value when validation failed

I have a classic rails 3 form with a file field, everything works fine, upload works and data is saved to database.
When a validation failed, for example, title is missing, then the user is sent back to the form with a render :action => new. Normal. But the problem here, is that the user have to select another time its file.
Any way to avoid that?
Typically you don't want to process files until after validations have run or you're going to repeatedly store files that possibly don't have the associated records. Gems like Paperclip and attachment_fu do this.
If you would rather store the file the first time it's submitted and is valid you can store the file and then do a quick check in your view to see if it's already set for the object you're building a form for, e.g:
<% unless foo.attachment? %>
# file field
<% end %>
Make sense?
You can't. It is security issue.
You can hack it in some browsers, but generally you can't do it
I know the question is old, but now the carrierwave gem has something to retain the file field when the validation fails.
https://github.com/carrierwaveuploader/carrierwave#making-uploads-work-across-form-redisplays
Basically, you will have to add a hidden_field avatar_cache if your model has an uploader mounted on avatar file. You will have to add it to the permit list in the controller (so that Rails wont restrict the field from being submitted to the server)

Keep form data when form is loaded a second time

I have a from that does two things.
Gets user text input.
Users can select an image or upload their own.
Problem occurs when user uploads their image.
The file field must submit the information to upload the image. It does all works.
But when the form is shown with the uploaded image, the text the user entered is gone. I understand that the instance variables won't keep the data.
How can I make this work so the text is not lost?
Must I use AJAX?
Thank you in advance.
if you are using form_for,
# your_controller.rb
def new # method where you show the form
#some_model = SomeModel.new(params[:some_model])
end
# new.html.haml - i like haml
- form_for #some_model do
... # all your inputs (they will be pre-set if you submit the form and it stays in new method
if you are using form_tag
# new.html.haml
- form_tag do
= text_field_tag :some_attribute_name, params[:some_attribute_name]
= select_tag :another_attribute_name, options_for_select(['option1', 'option2', 'and so on'], params[:another_attribute_name])
so depends on what you using, choose the respective way ;-) hope this helps =)
HOWEVER
i think the image should be submitted together with the form and saved together, i.e. it shouldn't be a separate process, unless of course you are talking about the form is saved and you are redirecting to an edit page... either way, both methods should work =)

Resources