Rails paperclip, Edit form file_field not assigned - forms

I used paperclip to attach an avatar onto my user, in my Model:
has_attached_file :avatar,
:styles => {square_tiny: '50x50#', square_small: '100x100#', square: '200x200#'}
I have a form
<%= form_for(#user_profile,
:url => { :controller => :user_profiles, :action => :update_general_info, :id => #user_profile.id },
:html => { :multipart => true,
:class=> "form-horizontal" }) do |f| %>
<div class="control-group">
<%= f.label :avatar, :class => "control-label" %>
<div class="controls">
<%= f.file_field :avatar %>
</div>
</div>
....
<% end %>
The upload works perfect, but I come back and EDIT my user, the file field says 'no file chosen'. And since I am validating presence of that avatar, every time a user edit his details, he has to upload his avatar again...
How do I work around that?
I thought the :multipart => true would help but it didn't.

There is absolutely no good way for a page to set a value to a file field, and that's for security reasons.
If the browser allowed a page or a JS script to set a value to a file field that would allow a malicious page to preset the file field value with some system or passwords file. And that would be a massive security hole.
What I do in that case is I display the already saved file as a link that the user can click to download. You can then provide little AJAX links to delete (the file is deleted with an AJAX call and the link replaced with a new file input) and replace (the link is replaced with a file input).
Your last option would be to use AJAX to upload the file. If you use AJAX for a file upload you'll POST to a hidden frame so the file input will keep its selected value.
Either way keep in mind that any change to file field value has to be user initiated.

Related

Displaying Rails Required Fields Form Errors All At Once

I'm using the Rails form and I'm also using Bootstrap tabs. I have 4 tabs that a user fills out and on the 4th tab is the submission button. I have a number of required: true fields in the form, and when I go to click on the submit button leaving any of these fields blank, the pop-up saying "Please fill out this field" appears.
Question: How can I just have a box appear with ALL the error messages, instead of each individual error message appearing one at a time?
I've read a number of posts, and have tried most suggestions (with exception to ones that include JS, as I'm hoping there is a strong solution not including JS). I put below some code below my submit button that I tried but it doesn't display anything as the individual box error message I think overrides it.
Any help is appreciated.
_Form:
<%= form_for(#property, html: { multipart: true }) do |p| %>
...
<%= p.file_field :picture, :multiple => true, name: "property_attachments[picture][]", size: 2 %>
<%= p.submit "Submit", class: 'btn btn-primary' %>
<% if #property.errors.any? %>
<div id="error_explanation">
<div class="alert alert-danger">
The form contains <%= pluralize(#property.errors.count, "error") %>.
</div>
<ul>
<% #property.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<% end %>
Figured it out and learning a lot about Rails Forms. I was using required: true for a number of fields and this created individual pop-ups on each error one by one. I removed all of the required: true fields and then added validations in the model (eg. validates: :price, presence: true) and then the error message I used above in my question displayed any missing fields.

Why Isn't The Partial File Automatically Created?

Getting through Michael Hartl's tutorial great; I've encountered a few snags along the way but nonetheless, it's working out better than I expected.
My question, is regarding the partial file. In the tutorial if I have read correctly, chapter 5- it advises to edit the 'application.html.erb' file with...
'<!DOCTYPE html>
<html>
<head>
<title><%= full_title(yield(:title)) %></title>
<%= stylesheet_link_tag "application", media: "all",
"data-turbolinks-track" => true %>
<%= javascript_include_tag "application", "data-turbolinks-track" => true %>
<%= csrf_meta_tags %>
<%= render 'layouts/shim' %>
</head>
<body>
<%= render 'layouts/header' %>
<div class="container">
<%= yield %>
</div>
</body>
</html>'
The tutorial then says if this line worked I should find a file called 'app/views/layouts/_shim.html.erb' and I cannot find it, thus, it was not automatically created, further not allowing me to pull up the referring static page in my browser (which may or may not be related).
Thanks in advance.
Of course, to get the partial to work, we have to fill it with some content; in the case of the shim partial, this is just the three lines of shim code from Listing 5.1; the result appears in Listing 5.10.
So yes. You have to create partial file by yourself and fill it with proper content. In case you code editor doesn't support partial extraction.
For example:
Using rails.vim plugin for VIM there is the possibility to extract selected lines into partial by using Rextract <partial_name> command. Which creates new file, moves selected lines into it and replace selected lines from source file with <%= render :partial => '<partial_name>' %>

How to get the name of the current user in Refinery?

In RefineryCMS, for some functionality I have to store the present logged in user's first name and last name.
How to get logged in user's first name and last name?
While going through this implementation, I found that refinery user table does not have column to store first name, last name or any basic details about user.
So, first step is to create a migration file having first_name, last_name etc as per requirement.
$ rails generate migration AddFirstNameLastNameToRefineryUsers
first_name:string last_name:string
Then run
$ rake db:migrate
Now, create a decorators for user model.
Path :: /app/decorators/models/refinery/user_decorator.rb
Create a decorator : Refinery Documentation Link for Creating Decorator
Add this line inside that model
attr_accessible :first_name, :last_name
validates :first_name,:last_name, :presence => true
Now add this line at view area
/app/views/users/new.html.erb
<div class='field'>
<%= f.label :first_name %>
<%= f.text_field :first_name, :class => 'larger widest' %>
</div>
<div class='field'>
<%= f.label :last_name %>
<%= f.text_field :last_name, :class => 'larger widest' %>
</div>
Now, Rails will save the values, when user makes first time login.

select and onChange in a Ruby on Rails form

I browsed all SO questions and answers about this topic but I'm still unable to make my scenario work.
I want to trigger a click button action when a dropdown menu option is selected ; seems simple and should be very common with AJAX.
Here are the relevant excerpts of my code:
<%= form_for(#test, :html => {:id => "form_id", :name => "MyForm", :remote => "true"}) do |form| %>
<%= form.label "Menu1" %>
<%= form.select (:Menu1, [["Option1","value1"],["Option2","value2"]], :html_options=>{:onChange=>"javascript: this.form.apply_button_name.click();"}) %>
<!-- more select menus and text fields here -->
<div class="actions">
<%= form.submit "Apply", :name => "apply_button_name", :remote => "true" %>
</div>
<% end %>
I used ":remote => "true" both for the form and the button because that's the only way to get AJAX working. I also tried with and without explicit "html_options" and "javascript:", after I browsed some SO answers that suggested that but that did not help. I also tried onSelect, and onClick instead of onChange, but still no luck.
The generated HTML is the following:
Menu1
<select id="test_Menu1" name="test[Menu1]"><option value="value1">Option1</option>
<option value="value2" selected="selected">Option2</option></select>
As you can see, there's no onChange event handler in the HTML code ; WHY? Anyone is seeing what am I doing wrong?
Thanks for any help.
Modify your call to form.select, like this:
<%= form.select :Menu1, [["Option1","value1"],["Option2","value2"]], {},
:onChange=>"javascript: this.form.apply_button_name.click();" %>
If you examine the documentation for:
API Dock Ruby on Rails select
You will see that the select form helper takes the form:
select(object, method, choices, options = {}, html_options = {})
If you don't pass anything for the option hash (in your case this will be an empty hash), the form thinks that your html_options hash are your options hash, and gets confused.
A way to check this is to add something like {:onchange=> "alert('Hello');"} and either see if the event successfully triggers, or alternatively, in your actual web page, right click on the select element and inspect it. If no onchange option is present in the html, that means that your rails form helper is indeed confusing the html_options with the other options. So, what you should have:
<%= form.select (:Menu1, [["Option1","value1"],["Option2","value2"]], {}, {:onChange=>"handler();"} %>
MAKE SURE TO INCLUDE THE EMPTY HASH FOR THE OPTIONS BEFORE THE HTML OPTIONS AND YOU SHOULD BE FINE. I don't think you even need to have the html_options and javascript stuff you have.
Lastly, if onChange doesn't work, try to use onchange with no capital C.

Persisting form data on view after file upload post from same view

I have a view to edit some document details and upload two related images. I want this view to post to two different actions on my controller, one for saving all the form fields and one to do the file upload.
I have one form around the main form and a multipart form around the file uplaod input
<% using (Html.BeginForm("Edit", "Document", FormMethod.Post,
new { enctype = "multipart/form-data" })) { %>
<% =Html.TextBoxFor(model => model.Document.Title) %>
<%= Html.TextBoxFor(model => model.Document.Description) %>
//and then another multipart form around the file upload part like this
<% using(Html.BeginForm("FileUpload", "Document", FormMethod.Post, new { enctype = "multipart/form-data" }))
<input type="file" id="fileUpload" name="iamge" size="30" />
<input type="submit" value="Upload" />
<% { %>
<input type="submit" value="Save" />
<% } %>
The file upload is happening correctly on posting the inner form but I want the controller to return the compelte model to the main view again with all the form fields persisited. The view is strongly typed so I thought I would post the whole model to the file upload action using the inner form. Can I get away with having just one multipart form that will post the files and the form data regardless of what input element is clicked? Is this good practice. At the end of the day all I want is to make sure all my form data is persisted on the Edit form after my file upload.
How can I pass the model data to the file upload action from the inner form?
You don't need the inner form I don't think. You can just have the outer form, which should parse in your model if you set up the action arguments. You could then have a different logic path in terms of, for instance, persisting other model elements depending on whether any files had been posted.
You would then be able to pass the model that had been posted back, back into the view.