How to keep file field value when validation failed - ruby-on-rails

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)

Related

Ruby on Rails, Formtastic Gem image upload

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.

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.

Can I stop Rails from storing invalid attributes on the model after update is called?

I've been developing on Rails for awhile and can't believe I haven't ran into this problem - maybe I am missing something simple?
My edit page displays information about the model being viewed. The model's to_s method returns the name attribute in this case, which is displayed in breadcrumbs and the page header.
I have a validation that the name cannot be blank and a simple update method:
def update
#model.update(permitted_params)
respond_with #model
end
The default ActionController responder will render my edit page automatically when #model is invalid, which it does. But #model still retains the invalid attributes so my breadcrumbs and page header are blank as they both display model.name which is "".
I could solve this by
def to_s
name.presence || name_was
end
But this application will be fairly large and most of my models will follow this same view pattern with the header containing a model attribute that could be invalid. I feel like using this pattern in to_s on all of my models will be frustrating to keep up with.
My current solution is to define this method in my custom responder, which reloads the #model if it is invalid:
class ApplicationResponder < ActionController::Responder
def initialize(*)
super
#resource.reload if has_errors?
end
end
This works but now any invalid request has an extra call to the database when the model is reloaded. Probably not a big deal, but still a code smell in my opinion.
Is there something I can do to stop Rails from keeping invalid attributes on #model after update? I am using Rails 4.1.0beta1 and Ruby 2.1 and have tried on Rails 4.0.0 as well.
Why not also provide some client-side validations to prevent users from submitting invalid details in the first place?
If you provided validations that give the user feedback before the page is re-rendered, you won't have the problem of ever having to work out how to display that invalid data (since it sounds like you are displaying data on the edit page itself).
I would recommend you check out Parsley.js or other similar JS based client-side validation.
The kind of behavior you are seeing, where they are still "stored" in the model object is a good thing in general because it allows you to automatically repopulate the input fields in a form with those incorrect values, so that a user can see what they entered wrong and change it.
If you are wanting to maintain certain 'correct' values statically on the page, like in a breadcrumb, I would copy those values off into their own variables and track them separately. For the breadcrumb on the application I work on, we actually store the link history in the browsers IndexedDB, and don't rely on what the current value of an object in the database is.
From my experience, most of the time the identifying attribute of an object, like it's name, isn't editable. If it is, I tend to make the name of my page something a little more general, like 'Edit Profile,' instead of 'Edit ', or 'Edit Organization' instead of 'Edit Name_of_Organization.'
If you really want to keep rendering the original name, I would just save that and track it through hidden HTML inputs. What you're doing with the to_s method isn't foolproof: if a user enters an invalid name that's not blank, you're going to render that invalid name.

Captcha with Multipart Form Rails

I have a multipart form that I need a captcha for at the end. Essentially, a user is allowed to create/update a draft but not submit it for admin review until everything is done. There is a captcha meant for the last submission but the problem is that when I add it to the form, I can't use any of the other submit buttons because the captcha isn't filled out. Is there any way around this?
I'm using simple_captcha and Rails 3.2.
Thanks!
I haven't used simple_captcha before, but seems like you are doing #object.save_with_captcha in every case. You have multiple options to solve this, but one i came up with is:
In the controller, verify if all the fields (mandatory only i guess) are filled, and if they are, then save your object using #object.save_with_captcha, otherwise do the usual #object.save which wont trigger the captcha validation. Something like this:
def create
#object = MyObject.new(params[:my_object])
if #object.has_mandatory_fields_filled?
#object.save_with_captcha
else
#object.save
end
end
In the has_mandatory_fields_filled? method you would check that all the mandatory fields of your form are not empty/nil etc.

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