Confirm leave page unless they clicked the save button - ruby-on-rails

I have a form where I create a model and I want a dialoge box to appear if the user navigates away from the page, unless they click the save/create button.
I have this javascript code that works anytime the user leaves the page; meaning this dialoge still appears when the user clicks save/create.
#javascripts/workouts.js.coffee
window.confirmExit = () ->
"Your changes will not be saved.";
#workouts/new.html.haml
= render 'form'
:javascript
window.onbeforeunload = confirmExit
#workouts_form.html.haml
= simple_form_for(#workout) do |f|
# some input fields
= f.button :submit
Now I know that I only want the confirm exit called if the submit button is not clicked, but I am not sure how to go about doing this.

What I usually do is I only show the confirmation when changes actually have been made to the form. To do that, you'll need to scan the forms on your page, serialize them and store it in memory. Then, when the user leaves the page, serialize the form again and see if there is a difference.
Otherwise, you might want to bind some function to submit event of the form, setting some global boolean like window.formSubmitted to true. Check that variable when leaving the page to determine if you want to show the confirmation box.

So I figured it out, at least it works for chrome and safari although right now I am under the impression that it will not work for ie. What I did was create a boolean that is set to false and only set to true when the submit button is selected.
#javascripts/workouts.js.coffee
window.submitButtonClicked = false
window.confirmExit = () ->
if window.submitButtonClicked
null
else
"Your changes will not be saved."
$(document).ready ->
$('#target').submit ->
window.submitButtonClicked = true
#workouts/new.html.haml
:javascript
window.onbeforeunload = confirmExit
#workouts_form.html.haml
#target
= simple_form_for(#workout) do |f|
# some input fields
= f.button :submit
I hope this helps anyone who was curious. Note that the #target line is actual haml and not a comment.

Related

Submit button with Options

For one form, I want to have two submit buttons , named:
Appove, Decline
when the user clicks on Approve it should send approve: true as well
when the user clicks on Decline it should send approve: false as well
Basically the buttons should work like a checkbox
Is this possible with Rails and how to implement it? Thanks
If you're using the standard submit form helper, you will get returned a param with the key "commit". You can test for this in your controller code.
<%= f.submit 'Approve' %>
<%= f.submit 'Decline' %>
in the controller...
def create
approved = params[:commit] == 'Approve'
The approved variable will then contain true or false and you can use it as needed in the rest of the action / method.
You can do it but you need js/jquery for this. You will have hidden checkbox that you will check in proper way and two buttons.
Lets assume that your form has id 'form'. And you checkbox has id 'approve_checkbox'
In this case you need submit function for something like this.
$('#approve_button').on('click', function(e){
e.preventDefault();
$('#approve_checkbox').prop('checked', true);
$('#form').submit();
});
$('#decline_button').on('click', function(e){
e.preventDefault();
$('#approve_checkbox').prop('checked', false);
$('#form').submit();
});
Of course you can simplify this code, but I think idea is clear.

Search across multiple controllers

So I'm working on a Rails project in which I have a frontend interacting with multiple controllers to retrieve information. I have instructors and courses controllers and I am trying to implement a search feature where I can select which controller to search from using a drop down box, and when I click the search button, it will only search the selected controller.
My search box on the home page looks like this:
http://i.stack.imgur.com/o7yzk.png (SO won't let me embed an image)
The code to make it is below:
<%= form_tag(params[:option], :method => "get", id: "search-form") do %>
<%= select(:option,options_for_select([['Instructors', 'instructors'], ['Courses', 'courses'],['Departments','departments']])) %>
<%= text_field_tag :search, params[:search] %>
<%= submit_tag "Search", :name => nil, html: {class: "button button-red"}%>
<% end %>
Special note on line 1 where I use params[:option], this populates with the information from the 'option' field, so if I select 'Instructors', the option becomes instructors.
Problem: On the homepage when I enter a name and click search the url that is created is as follows:
http://0.0.0.0:3000/?utf8=%E2%9C%93&option=%2Finstructors&search=John
and it takes me right back to the homepage. I can see in the debug information, that it isn't even getting to the right controller, it's only looking at the static pages controller.
If I click the search button again it brings me to the correct page with the correct search results:
http://0.0.0.0:3000/instructors?utf8=%E2%9C%93&option=%2Finstructors&search=john
I'm using Solr to do the searching, and I have everything working properly except this pathing issue which requires multiple clicks. My controller code for instructors index looks like this:
def index
if params[:search] != ''
#search = Instructor.search do
fulltext params[:search]
end
#instructors = #search.results
else
#instructors = Instructor.all
end
end
I feel like I am making an architectural mistake somewhere, and any input would be appreciated.
I feel like I am making an architectural mistake somewhere, and any input would be appreciated.
Exactly right. The mistake is this: params[:option] is a serverside value. In order to get to the server, you are creating a request using the form submission. The form decides where to submit using the serverside params[:option]. It's like trying to pull yourself by your own bootstraps.
In more detail, what happens is this:
The serverside receives the request for your /
The serverside renders your form. The form's action is set to params[:option], but such an option is not set. The default value for a form action when it is not specified is the same page you're on.
The clientside displays the form. The user selects Instructors and submits the form.
The clientside contacts the form's action (i.e. the same page), and transfers the form's values (option and search)
The serverside / receives the request, and renders the form
This time, params[:option] is set to instructors
The client submits the form again; this time, the form has a correctly set action (the received params[:option] from the last cycle)
Two easy approaches to solve this would be:
Use JavaScript to dynamically modify the form's action attribute as the option is selected
Make a dedicated search controller/action that will handle search for both kinds, depending on the value of params[:option]
Make another action at serverside that will redirect your request to one of the other two actions, depending on the value of params[:option]

Preserving form values on redirects

I have a form that creates a new PlanEntry.
At the top of this form I have this link to upload a video as part of the PlanEntry:
<%= link_to "Upload Video", new_video_sources_path %>
This takes a user to another form to upload the video. When successful, it returns back to the new PlanEntry form.
This works fine if the user always starts by uploading a video, but in some instances they may already draft things like a 'title' and 'description'. In these cases, these values are lost when the user returns to the form after uploading the video.
How can I preserve these values?
I figured it out, but in a bit of a roundabout way. Basically I replaced the line above with this:
<%= f.submit "Upload Video", :name=>"commit", :value=>"Upload Video" %>
This is a second button to submit the PlanEntry form. Now in my controller I check to see which button was clicked in the submission. If it was the "Upload Video" button, I save all the parameters to the session, and redirect to the upload video form.
if params[:commit] == "Upload Video"
session[:plan_entry] = params[:plan_entry]
redirect_to new_video_sources_path
else
...
end
When the video is uploaded it redirects back to the new PlanEntry form. In my PlanEntry#new controller I check if there are existing session variables. If so, I grab them and then clear them.
if session[:plan_entry].present?
#plan_entry.assign_attributes(session[:plan_entry])
session[:plan_entry] = nil
end

rails validation confirmation after form submit

I've got a form with a date and I want prompt the user if they submit the form outside of a range, but still give them the opportunity to submit outside the range.
For instance (pseudocode)
if date < start_date and current_user.admin?
answer = ask 'are you sure you want to submit below the date range?'
elsif date > end_date
answer = ask 'are you sure you want to submit over the date range?'
else
answer = 'yes'
end
if answer == 'yes'
submit
else
return to original form
end
I was thinking one solution would be a multi-form wizard type of implementation but is there an easier way?
For instance, first I would show the original form with the date field. Then when the user hits the 'submit' button check with the server if we have to ask the user to confirm their out of range date, if so show a partial and wait for them to hit the 'confirm' or 'yes' button.
To me it sounds like you should have an intermediary action in your controller which you submit the form to. This intermediary action validates the form parameters, and renders the partial or just submits the form accordingly. The partial's submit button would contain a link to the final action which deals with submission.

Ruby on Rails 3, forms, ajax, nested, in-place editing, one-by-one. Best practice

Assume, that I have a complex nested form with many fields.
I want to edit its fields one-by-one in ajax way, so that every time I see form - it is in 'show' style (without fields to change information), but with possibility to switch any particular field or group of fields to 'edit' mode with it's own 'save' or 'update' button.
Solving this kind of problem, I ended up with two ways:
Extended use of Ryan Bates' complex-form-examples.
The disadvantage of this way is that every field (or group of fields) requires it's own code (i.e. javascript: 'insert_fields'), which renders corresponding 'edit' style form, so it results in page is overwhelmed by javascripts.
Second - is unified procedure of loading corresponding edit partials through ajax through special controller action (i.e. get_partial), which "render :do updates" given field's area by 'edit' form.
For given field or group of fields i have partials for 'edit' and for 'show'. When i need to switch that field to edit mode i send request (link_to ...,'/.../get_partial?partial=foo',:remote => true) with necessary params by ajax, and some controller#action renders that partial by javascript.
I think that second approach is better one, but I can't figure out how optimize it the best.
Are there any more elegant solutions to this problem?
What if you generated a normal 'edit' form (with all the nested fields, etc), and then had the javascript hide the fields and add the text of the field and an edit link next to it. So for example say your form looks like:
= form_for #foo do |f|
= f.text_field :name
and your javascript would do this to it (1):
= form_for #foo do |f|
= f.text_field :name, :class => "hide"
<the value of the field here>
= link_to "edit", "#"
then make your javascript add a click event to the edit links that, when clicked, does:
= form_for #foo do |f|
= f.text_field :name
= f.submit "Save"
then you'd need more javascript that makes the save button submit the form (ajax), and go back to (1) above

Resources