Staying RESTful while performing AJAX server-side validations? - ruby-on-rails

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.

Related

Mobile API and params verification

I'm writing my first mobile API an I can't find the best way to validate params, entities etc.
Now I do somethig like this before_filter :verify_adding, :only => :add and verify every param and entity in this verify methods. It doesn't look like elegant solution.
Please, suggest the best way to do such verifications
It's not the Rails way of validating input data.
Mostly you build an object using params and call the valid? function.
Because validation is a cross cutting concern which means that it will happen in different layers of your application, so it will be a good practice to put it somewhere so that you'd be able to call it somewhere else.
If your objects are ActiveRecord objects then the best place and way of validation is adding validation rules to your domain object which is an ActiveRecord derived object.
If not you can add ActiveModel modules to your domain object and use validation rules just like a regular rails app.

Rails - ping user without authenticating?

So I'm writing a Facebook clone for a school project using Rails and I need some way to keep track of which users are logged in. At the moment, I'm a bit time-pressed, so I decided just to update the User model every time they visit a page with a last_seen attribute.
Problem is, the user model requires revalidation to successfully update_attributes. So I'm wondering two things:
Is there a better way to do this that I'm missing?
If not (or if it would take too long) is there a way to bypass the validation?
to 1.: I cant give you an exact answer but I think itwould be better to deal with this problem using a javascript on the clientside with a timer that sends an ajax request all xxx secounds and an action that receives this requests and saves it in a seperate table associated with the User.
to 2.: Yes there are some ways to bypass validations The most pragmatic way is to bypass the :validate => false option when saving the object but then you can use update_attributes:
object.save(:validate => false)
So there is also the possibility to use conditional validations that are only used when a specific condition is complyed. There is a railscast about that => http://railscasts.com/episodes/41-conditional-validations .

Prevent modification ("hacking") of hidden fields in form in rails3?

So lets say I have a form for submitting a new post.
The form has a hidden field which specify's the category_id. We are also on the show view for that very category.
What I'm worried about, is that someone using something like firebug, might just edit the category id in the code, and then submit the form - creating a post for a different category.
Obviously my form is more complicated and a different scenario - but the idea is the same. I also cannot define the category in the post's create controller, as the category will be different on each show view...
Any solutions?
EDIT:
Here is a better question - is it possible to grab the Category id in the create controller for the post, if its not in a hidden field?
Does your site have the concept of permissions / access control lists on the categories themselves? If the user would have access to the other category, then I'd say there's no worry here since there's nothing stopping them from going to that other category and doing the same.
If your categories are restricted in some manner, then I'd suggest nesting your Post under a category (nested resource routes) and do a before_filter to ensure you're granted access to the appropriate category.
config/routes.rb
resources :categories do
resources :posts
end
app/controllers/posts_controller
before_filter :ensure_category_access
def create
#post = #category.posts.new(params[:post])
...
end
private
def ensure_category_access
#category = Category.find(params[:category_id])
# do whatever you need to do. if you don't have to validate access, then I'm not sure I'd worry about this.
# If the user wants to change their category in their post instead of
# going to the other category and posting there, I don't think I see a concern?
end
URL would look like
GET
/categories/1/posts/new
POST
/categories/1/posts
pst is right- never trust the user. Double-check the value sent via the view in your controller and, if it does't match something valid, kick the user out (auto-logout) and send the admin an email. You may also want to lock the user's account if it keeps happening.
Never, ever trust the user, of course ;-)
Now, that being said, it is possible to with a very high degree of confidence rely on hidden fields for temporal storage/staging (although this can generally also be handled entirely on the server with the session as well): ASP.NET follows this model and it has proven to be very secure against tampering if used correctly -- so what's the secret?
Hash validation aka MAC (Message Authentication Code). The ASP.NET MAC and usage is discussed briefly this article. In short the MAC is a hash of the form data (built using a server -- and perhaps session -- secret key) which is embedded in the form as a hidden field. When the form submission occurs this MAC is re-calculated from the data and then compared with the original MAC. Because the secrets are known only to the server it is not (realistically) possible for a client to generate a valid MAC from the data itself.
However, I do not use RoR or know what modules, if any, may implement security like this. I do hope that someone can provide more insight (in their own answer ;-) if such solutions exist, because it is a very powerful construct and easily allows safe per-form data association and validation.
Happy coding.

Backbone.js server-side validation and other server-side errors

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.

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