Rails Autosave form with jquery - ruby-on-rails

I am working on application where a a user can create a blog post and the blog post periodically updates every so often. I found a jQuery autosave plugin for handling the autosave but I am still running into problems.
When I debug using firebug I only see the GET request so therefore the page does not get updated and I am not sure how to call POST after the GET request.
It does not update as I type or every 3 seconds but it updates when I click outside of a form field. Anyway to have it so it updates every 3 seconds or so?
My code is listed below
application.js
jQuery(function($) {
$("#main-form").autosave({
callbacks: {
trigger: ["change", function() {
var self = this;
$("[name=save]").click(function() {
self.save();
});
}],
save: {
method: "ajax",
options: {
success: function() {
alert("saved!");
}
}
}
}
});
});
post_controller.rb
def update
#post = Post.find(params[:id])
respond_to do |format|
if #post.update_attributes(params[:post])
format.html { redirect_to semester_post_path, notice: 'post was successfully updated.' }
format.json { head :ok }
else
format.html { render action: "edit" }
format.json { render json: #post.errors, status: :unprocessable_entity }
end
end
end

I'm sure you've moved on, but just to close the gap on this post. OnChange takes place when a field loses focus, so what you're seeing seems to be functioning as designed and normal for that design.
Here's a link to question/answer using timeouts to autosave via AJAX.
Autosave Opinion:
I'm not sure you really want envoke autosave until the document has been formally submitted for several reasons but I'll post my favorite 2.
Some forms tend to have a lot of moving parts for the back end storage and that first commit should be intentional before stuffing a bunch of data into tables. (IMHO)
another rationale behind leaving them alone (not auto-saving) before the first "real" submit is because until they hit submit they might not really want you to have that information in your system.
How often have you started a form on the web and then decided you didn't want to fill out that information after all? ... it would frustrate me to get a flyer or email or call from a site I actually decided to bail out of registration for!

Related

Rails Best_in_place ajax:success not being recognized

My Rails app contains an Excel-like editable table, using best_in_place fields throughout. They work perfectly fine upon page load and I have no problem calling coffeescript functions on ajax:success after a user edits a best_in_place field.
Since this is an Excel-like table, users can click a link to add a new placeholder row to the table. My create.js.erb file adds the row without a page reload. The new row has several table cells with best_in_place functionality, and updating them updates the database, so far so good.
The problem is that when a user then edits a best_in_place fields in one of the new rows, ajax:success does not fire, therefore my coffeescript functions do not initiate.
I've confirmed the new table cells have the exact same class and data attributes as the existing table cells (ajax:success is read on the class name).
Question- in this scenario, how do I initiate my coffeescript function if ajax:success is not being recognized?
Milestone controller, both create and update actions
def create
#payment_schedule = PaymentSchedule.find(params[:id])
build_default_milestone # this builds a placeholder milestone
if #milestone.save
increment_milestone_positions # this relates to a sortable table
respond_to do |format|
format.js
format.html { redirect_to :back }
end
else
respond_to do |format|
format.js
format.html { redirect_to :back }
end
end
end
def update
#milestone = Milestone.find(params[:id])
respond_to do |format|
if #milestone.update(milestone_params)
update_milestone_amounts
format.html { redirect_to(:back) }
format.json { respond_with_bip(#milestone) }
else
format.html { redirect_to(:back) }
format.json { respond_with_bip(:back) }
end
end
end
Create.js.erb
$('#milestone-body').prepend('<%= escape_javascript(render partial: 'row_add', locals: { milestone: #milestone }) %>');
Coffeescript function
update-percent is the class name of the best_in_place field in question. This function fires perfectly for the existing rows, just not the new ones.
$('.update-percent').on 'ajax:success', (event, data, status, xhr) ->
...
Any suggestions on how to solve this?
The issue is resolved. The problem was not that ajax:success wasn't firing, it's that (for reasons still unknown) I had to read ajax:success at the table body level instead of the table cell in question. Apparently this is a somewhat common issue, where when adding new elements to the DOM after it's originally loaded, you need to read ajax:success higher up the DOM.
Thank you to those who provided input.
are you using turbo links? I think best in place binds to document ready which acts funky if you are using turbo links. If so, remove it from your application.html.erb and application.js file and try again.

Displaying an error message without reloading the page in Rails

I have a page that lets one create records - if the validations aren't satisfied, it redirects to the same page and shows an error message. Here's that snip from the controller:
def create
#signature = Signature.new(signature_params)
if #signature.save
redirect_to "/thanks"
else
redirect_to :back, :notice => error_messages(#signature)
end
end
The trouble is, this is resulting in a full page refresh - so the error message isn't visible because the input form is placed under the fold of the page. I can place it at the top of the page, of course, but is there a way to show the message without reloading the page? Thanks.
OK, so here's what I've settled on:
1) I'm handling validation on the client side with HTML5 "required" attributes - they were created for this explicit purpose and no other gems or plugins are needed. They are supported in all major browsers. Details in this article.
2) I've moved the error messages to the top of the page to handle the case in which a user either is on an old or mobile browser or has JavaScript disabled. Error messages must work with a complete request-response cycle (even if this means re-loading the page) before they work with anything else - this is the unobtrusive JavaScript approach.
3) For the AJAX version, I'm going to be using remote: => true on the form element as explained in the Rails guides. I might be making this open source once I'm done with the callback part of it, and will post a link here.
Obviously, handling errors with flash is the most uniform & DRY way to show the user what's going on, but if you're willing to think outside the box, you'll be able to use Ajax to accomplish a similar job by just handling the errors yourself:
Code Example
#app/controllers/signatures_controller.rb
def create
#signature = Signature.new(signature_params)
if #signature.save
#success = "true"
end
respond_to do |format|
format.js { #errors = error_messages(#signature) }
format.html {
if #success.defined?
redirect_to "/thanks"
else
redirect_to :back, :notice => error_messages(#signature)
end
}
end
end
#app/views/signatures/create.js.erb
<% unless #success.defined? %>
alert(<%=j #errors.inspect() %>)
<% end %>
#app/assets/javascripts/signatures.js
$(document).on("submit", "#signature_form", function() {
$.ajax({
url: "/signatures"
type: "POST"
data: $(this).parent().serialize(); //serialize the form (not the button)
error: function() {
alert("Sorry, there was an error!");
}
});
});
You'd actually be better using JSON for this. If you like the idea, I can refactor it to include JSON for you!

Error in handling reponse from remote true Rails

I am using Rails remote true for ajax calls, but I have error in handling the response form controller.
What I am doing is I have placed a form in partial which I render in the view for the first time, and I have also given it a id in html options for form_for. I have also applied some jQuery on that form like on save and cancel button and one script for date picker on one of its field.
As I handle the response from server using format.js for rendering js file, in which I have placed the code as follows
if #vairable.save
format.js { render 'some-file' }
else
format.js { render 'something'}
end
If the variable saved successfully I close the form properly, but if validations occur I render the form again by writing JavaScript code in js.erb file. I have problem in handing this response. The errors are displaying properly but when the form renders again with errors, the jQuery events applied to its fields and button, do not work. The jQuery events don't take place.
This problem only occurs when the model validations occurs and the validation rails are displayed with the new render form.
You should wrap your response in a respond_to block like this:
respond_to do |format|
if #variable.save
format.js { render 'some-file' }
else
format.js { render 'something'}
end
end
Edit: Your jQuery tags should be changed to $(document).on(...). Eg.
#change this:
$("#your-target-id").click(function(){
alert("This doesn't work after your have submitted via ajax")
});
#to this:
$(document).on("click", "#your-target-id", function() {
alert("This should work after ajax submission, and when errors are displayed");
});

Rails returns outdated information after doing a save()

I have a model Question which has_many Options.
In an action I modify the Options of the a Question object and then return the Question object as a json. (This is used in an ajax call). The problem is, the returned json is not up to date and doesn't reflect the modifications I made.
def action
question = Question.find(:id)
question.options.each do |op|
op.blah += 1
end
respond_to do |format|
if question.save()
format.json { render json: {question: question.to_json(:include => :options)} }
else
blah blah
end
end
end
Weird because you edit the items in place, then save (and verified that they are saved to db --since refresh works). So the render to json should work.
You could always do explict reload calls, like
format.json { render json: {question: question.reload.to_json(:include => :options)} }
But it would be very weird if that would be the cause, since you actually just saved that data.
But yesterday I had a similar problem, and actually what happened that I did a replaceHtml of a div, but my inserted data did not have the same surrounding div. So the first time it updated correctly, and the second time it just showed the old data (while in fact it did nothing, because it did not find the div to replace).
So in short: if simply refreshing works, imho it is not the database and it is not caching, but will most likely be something in your javascript: the updating of the screen that is going wrong.
Hope this helps.
question.options.each do |op|
op.blah += 1
op.save
end
You forgot to save options after modification.

Calling Rails update Method via Inline Edit

I was putting together a quick inline editing feature in my first Rails app and just as I was getting it working it occurred to me that I may be violating RESTful principles. The edit updated an image name. To do so, it submits, via PUT to Image#update and passes the new modified name as image[name].
The database gets updated properly, but I need that value back so that my markup can reflect the name change. To do that, I was calling /images/:id.json, but that got me wondering whether a PUT request can "validly" (in that RESTful sort of way) return a value like this.
Thoughts?
Update: For whatever it's worth, I'm using jQuery and the jEditable plugin to do the inline editing. Here's my jEditable code:
$(document).ready( function() {
$('h2').editable(
'/images/' + $('#image-id').val() + '.json',
{
method: 'PUT',
name: 'image[name]',
submitdata: { authenticity_token: $('#auth-token').val() },
submit: 'Save',
cancel: 'Cancel'
}
);
})
And my Image#update method as it exists right now:
def update
#image = Image.find( params[:id] )
if #image.update_attributes( params[:image] )
flash[:notice] = "Successfully updated image."
respond_to do |format|
format.html { redirect_to #image }
format.json { render :json => #image.to_json }
end
else
render :action => 'edit'
end
end
If your concern is just that your update method with JSON provide a response body and not just a 200 OK (Rails's head :ok) then I don't think you need to be worried. The default response is 200 OK so the only difference between what you're doing and what Rails does by default (in its scaffolds) is that you're also including a response body. As far as I can tell proper REST etiquette only requires that you return a 200 OK and doesn't care about the response body, which is in line with what you're doing.
Beyond that all your code looks excellent.

Resources