Reputation: 970
I have a number of existing methods within a controller. Each one of those methods needs validation.
To do this I have created a validation method within the application controller.
I want to call this validation method from the start of each individual method, which will check that the user has the required groups before continuing. The validation method returns true or false. If the validation methods returns false, the browser is redirected to a 'validation failed' page and the rest of that method is not executed. The original method is called using JQuery.
I will show some code and then explain what the problem is:
Jquery Ajax Request: (generic code but just to illustrate)
jQuery.ajax({
url:"examplecontroller/examplemethod/" + ID,
success: function(data,textstatus,XMLHttpRequest)
{
}
})
Method JQuery Request Calls:
def examplemethod
id = ExampleDatabase.find(params[:id])
#redirect to validationFail page if validation check returns false#
render "/validationFail" if !(check_groups(id, "type"))
...other code etc...
render :text => done
end
End Of Validation Method:
def check_groups(id, type)
... other code etc ....
if userGroups.include? requiredGroup then
return true
else
return false
end
end
Regarding this line which calls the validation method-
render "/validationFail" if !(check_groups(id, "type"))
I did it like this because I just want a short, concise, one-line bit of code that I can just stick at the beginning of each method which either validates, and allows the rest of the method to be executed. Or it doesn't validate and it stops execution of the rest of the method.
My problem is that having the second 'render' line seems to invalidate the first one. If I have the second 'render' line in, the first one does not redirect to the 'validation fail' page. If I take the second validation line out, then there is no response to the JQuery Ajax call (assuming the method validates and is executed fully). This causes an error in Firebug, and obviously my AJAX 'success' code is not executed.
I know I could use IF statements to render one or the other, ie:
def examplemethod
id = ExampleDatabase.find(params[:id])
if !(check_groups(id, "type")) then
render "/validationFail"
else
...other code etc...
render :text => done
end
end
But I don't really want to go through and restructure each method like that, I'd rather just use a simple line at the beginning of each method that either returns true and continues, or returns false and doesn't continue.
It's strange (to my limited knowledge) that the second render affects the first, seeing as I thought using render would stop subsequent code executing...I've looked into using redirect_to instead of the first render, but I couldn't get this to work.
Can anyone suggest a better way of doing this?
Upvotes: 0
Views: 285
Reputation: 16084
I think what you're looking for here is a before_filter
. before_filters
allow you to execute code and render content before selected actions, cancelling the action if the filter returns false. The documentation for filters can be found here, but for a piece of example code, you're likely looking for something like this:
def TestController < ApplicationController
before_filter :check_groups
def examplemethod
id = ExampleDatabase.find(params[:id])
render :text => 'done'
end
private
def check_groups
if !(check_groups(id, "type"))
render '/validationFail'
return false
end
end
end
Returning false in the before_filter
will halt execution of the action, preventing other filters (or the action itself) from being called. If you use this method all over the place, you can even put it in your application controller, and you can throttle which methods before_filter
executes on by reading up more on it in the documentation.
Upvotes: 1