Backbone.js server-side validation and other server-side errors - ruby-on-rails

How do you roll back model changes when encountering server-side errors (e.g. validation errors)?
Given that certain validation must be done on the server side, what is the appropriate way to do this with backbone.js (Rails backend)?
When saving a backbone model, client-side validation fires which gives the appropriate user experience if validation fails (views of that model don't update). However, if server-side validation fails, the model and all of its views have already been updated (with invalid data) before the PUT to the server.
There seem to be a few problems with this.
All views are updated before the model has been server-side validated.
If, for instance, you have a list of models with a popup edit
dialog, the model in the list is updated with potentially
non-validatable info after you call Model.save but before it has
been server-side validated and PUT'ed.
If the server returns an error (e.g. 422 error), no 'rollback' of the model occurs. The unvalidatable data is just sitting there like a turd. This is really the bad one.
Am I using backbone.js wrong? Is there a well-known way to handle this (very common) scenario? I understand I can do some manual caching of the old values, etc, but it's kind of a smelly solution.
Thanks!

Don't know if I am doing this wrong (new to BackboneJS), but I had the same problem and here's how I solved it:
I do all my validations server-side
Instead of doing a normal model.save, I make a standard ajax call to the server and return an error message or a success message containing the attributes of the modified model. If it is a success, I can then do model.set with the returned attributes in order to update the model and the corresponding view.
If you want to do client-side validation first, I guess you could do a save with the { silent: true } option, so that views are not updated, then do the ajax call, and see what needs to be done according to the response (restore original values for the model if error or update views if success)
Hope this helps.
ps: this works, but does not feel "clean". If there's a better solution, I would also love to read it

What I would do is on the server side make sure you catch any errors and before returning the response query for the original record from the DB and return that as JSON along with the error response. Then you could just do this:
model.save({}, {
error: function(model, response){
model.set(response);
}
});
Assuming your views are then watching for change events on the model, they will update accordingly.

Related

A way to make use of form automagic for a controller without a model

I have a controller without a model that handles a very cyclical task.
The user is basically filling out a form, sending it up to the server for some minor analysis, and then the server regurgitates nearly the same thing back to the user.
The user makes some adjustments, and the process starts over again.
There is nothing to save or store from this process, so it doesn't have a model.
The form i am working with has a large number of fields to deal with. Is there a way I can pass the params hash back into the view with the least amount of mess getting the fields repopulated?
Basically, I would want to tweak a couple of values in the params hash, but more or less pass the hash back so that it can repopulate the view nearly exactly how it was when it was submitted.
The old way of using OpenStruct seemed ideal.
Will this help?
In controller action, just initialize a variable like #params (or some thing like this), so that can be able to use all the values in the params can be available in that view page.
Maybe an ActiveForm is good for your application. It use to manage (new/create/validate/...) forms with no or several models.
https://github.com/realityforge/rails-active-form

When to use render vs redirect_to when handling error validations

I have a fairly complex view that has multiple forms, lots of validations on those forms, paginations, and other features. When validations fail, I like to use render because then you can be more specific about what errors occurred in the forms. However, when I use render different compiler errors crop up such as "undefined method `total_pages' for []:Array" and "undefined model_name". Is this a situation when I have to use redirect_to or is it feasible to somehow work around the errors that are coming up when the view is being rendered. Thanks a bunch!
You should grasp things in their perspective.
Why is render used instead of redirect:
when you use render, you pass the instantiated object
this object, newly created or updated, received some params
when attempting to save the object, validation was triggered and, if unsuccessful, added errors to the current instance
so your object in memory contains validation errors.
But when you use redirect, you restart with a fresh stack which doesn't know anything about the former object in memory, there could not be any magic:
either the object is saved and you can get the persisted data from database
or if it's not saved, you can have some information you previously stored in session
To answer your question a bit closer: before you use render, you have to instantiate all objects needed by the page.
It's just logic the view fails if the expected instance variables are missing.
First, these are not compiler error - its run-time errors.
Second, you should either check your data in the controller to make sure its being served properly for rendering OR do some conditional blocks in the view in order to cope with this different data structures.
Lastly, redirect_to is just a technique of moving the user around, it could be used here but you still need to handle those errors, even in the redirected-to page...
HTH

Staying RESTful while performing AJAX server-side validations?

My Rails application has a number of forms. When Joe uses my app, I want each form to provide him with immediate visual feedback as to the validity of his input for each field. One field checks the format of his email address - pretty simple. But another allows him to associate the current resource with a number of other resources, and complex business rules apply. If the form is incomplete or invalid, I want to prevent Joe from moving forward by, for example, disabling the 'submit' button.
I could duplicate the validations that appear in my Rails code by writing JavaScript that does the validation in the browser as well. But this smells bad - any time business rules change, I'll need to update them in two places with two different languages and two sets of tests.
Or I could add a single method to the controller for the resource called 'validate'. It would accept form data in an AJAX request, and return a response that could then be used inside Joe's form to provide real-time validation feedback. Unlike the 'create' action, the 'validate' action would not change the state of the server. The only purpose of 'validate' would be to provide a validation response.
The dilemma is that I don't like adding actions to RESTful controllers in Rails. But I like even less the idea of duplicating validation code in two different contexts.
I noticed this SO question, which touches on this subject. But I'm not interested in a plugin or piece of technology. Nor do I consider this question necessarily Rails-specific. I'm more interested in how best to handle this kind of problem in general in a Web application.
I also notice this SO question, which doesn't include the constraint of maintaining a RESTful architecture.
Given the need to dynamically validate form data with complex business rules in a Web application, and the desirability of maintaining a REST-like server architecture, what is the cleanest, most maintainable way to accomplish both at the same time?
I see no problem in creating a validator "processing resource" that can accept an entity and ensure that it passes all validation rules.
You could do this either with a global validator
POST /validator
where the validator will have to identify the passed representation and perform the appropriate rules, or you could create subresources,
POST/foo/validator
As long as these urls are discovered via hypermedia and the complete representation to validate is passed as a body of the request, I see no REST constraints being violated.
I hope I understood correctly, but you could send the javascript requests to the same create action. For example:
def create
#data = DataObject.new(params[:data])
if request.xhr?
response = #data.valid? ? { :success => true } : { :errors => #data.errors }
render :json => response
return
end
# #data.save etc..
end
I'm actually using something like this in a multistep wizard (one page form, with hidden css sections).
You are right not to duplicate validation logic on client (javascript) and server side). But adding validation resources also adds maintenance effort and costs server network calls. I like to do basic validation on client side (better user experience) and for data consistency on server side also.
Why don't you attach your model with validation metadata and then the forms + javascript for validation gets generated. On the final submit you also do a final validation on server side based on the model.
I am sure some generic validation logic is possible with Ruby. I guess also some existing validation frameworks could be reused.

Rails Form Validations for Multi-Model Forms

I am trying to build a Rails app with multiple models in a single form, and multiple forms on a single page. To make that work (according to my limited knowledge), I have to drop out of the scaffold code and the "form_for :model" helper and use "form_tag" instead. However when I do that, I lose the ability to automatically catch and report form validation errors in the view (with the error message in the flash[:error] and have the invalid fields highlighted.
If I have a controller method for a form that has to validate data from multiple models, how to I pass the validation errors back to the form? What do I have to do to get the invalid fields highlighted?
(For the longest time I didn't "get" Rails forms, because I thought they were useless Ruby wrappers for HTML code. Now that I am working in a non-Rails environment, I realize how much hard work they save because validation is tied to ActiveRecord validaions, and if a validation fails, the form can be reposted with the invalid fields hightlighted and a useful message in flash[:error]).
To add multiples models to a simple form, after rails 2.3 you just have to add accepts_nested_attributes_for in your model, the model that will be connected with your controllers and views, change the views to support information from another models (with field_for) and maybe build the reference objects in your controllers. Check these links:
http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes.
http://github.com/alloy/complex-form-examples

Rails best practice for having same form on multiple pages

I am developing an Rails 2.3.1 Web site. Throughout the Web site, I need to have a form for creating Posts on various pages (Home page, Create Posts page, Post listing page, Comment listing page, etc. -- suffice to say this form needs to be on many pages served by a variety of controllers). Each of these pages displays a wide variety of other information that is retrieved in the corresponding controller/action. Ex, the home page lists latest 10 posts, content pulled from the DB, etc.
So, I've moved the Post creation form into its own partial, and included this partial on all the necessary pages. Note that the form in the Partial POSTs to /questions (which routes to PostsController::create -- this is default rails behavior).
The problem I am running into is when the the Posts form is not completed correctly, by default the PostsController::create method render's questions/new.html.erb, even if the form was submitted from the home page (/home/index.html.erb).
I tried changing the form in the partial to submit the "submitting_controller" and "submitting_action", and in PostsController::create, when #post.save? == false, I render action => "../submitting_controller/submitting_action" (Which is slightly hacky, but lets you render actions from non-PostsController's).
This seemed to work OK on the surface. The incomplete form was rendered in the view that submitted it with all the correct #post.errors message, etc. The problem was ALL the other data on the pages didnt show up, because the actual submitting_controller/submitting_action methods weren't called, just the associated view. (Remeber, I did a render which preserves instance objects, rather than a redirect_to which does not preserve the #post instance object which has all the error messages and submitted values.)
As far as I can see I have two options:
1) I can store the #post object in the session when #post.save? fails in PostsController::create, redirect_to submitting_controller/submitting_action, at which point i pull the #post object out of the session and use it to re-populate the form/error messages. (As far as I understand, storing objects in the session is BAD practice in rails)
2) I can move all the logic used to pull non-post creation form data from the various submitting_controller/submitting_action, put it in the ApplicationController, create a giant switch statement in PostsController::create for submitting_controller/submitting_action and call the methods in the ApplicationController to grab all the extra data needed for each submitting page's render.
Thoughts on the best way to do this within Rails?
By any chance is your Post model in a belongs_to relationship with each model who's controller you'll be using to render your form? Are you doing any special processing in the Post controller beyond Post.create(params[:post])?
If you answered yes to the first question and no to the second, you could get by with minimal mangling by adding accepts_nested_attributes_for to each of the controllers on which a user can create a post.
Regardless, Robertpostill is correct in that this is probably when to start looking at AJAX, to just replace the section of the page. The only problem is what to do if a user has javascript disabled. Personally I like to do design for the non-javascript case and add convenience methods.
As for thoughts on what you consider your two options,
1) I've used this method to store a shallow copy of an object in the flash hash. Preserving it across redirects. However this might not work for you given the variable nature of posts. As you can only send about 4K worth of data, and that includes other information in addition to your shallow copy.
2) See robertpostill's response
This is about the point that you move from full page updates to updating sections of a page through the use of AJAX. There are a bunch of things you should consider but the most rails-esque approach would be to split the response between an AJAX response and a plain HTML response. Check out this ONLamp article, this register article or the awesome agile web development with rails book. Essentially your controller renders a new div replacing the old div containing the result of submitting the partial.
In your question you mention two approaches and so I'll try and give you some pointers on why and why not here:
Option 1) Ths option is not so bad with a couple of tweaks. The main tweak is is to store the object in a serialized form in the DB. Then simply pass around the ID of the serialized object. Your upsides are that the session data gets persisted so recovering a a session is neater and your session stays light. The downside of this is that having a bucket of session cruft in your DB will pollute your app and you'l need to do some thinking as to how you expire unused session cruft from the DB. I've never seen this end well...
Option2) Eeek not inside the application_controller! :) Seriously, keep that as your weapon of last resort. You can pop things insde the helpers though and get access to those methods inside your controllers and views. However the testing of that stuff is not so easy so be careful before choosing that route. Switch statements can be replaced in OO apps with a little thinking, certainly in his case you can use option hashes to get a railsy way of having some smarts about the state of the app at the time the request is made.

Resources