Return error to ajax on action decision - ajax

I have a controller action which looks like so -
def upvote
#post = Post.find(params[:id])
if user_has_rated_post?
# I want to interrupt AJAX here
redirect_to[:forum, #post.question], :notice => "You already voted for this post"
else
#post.upvote
add_rating_to_post(1, #post)
#post.save
redirect_to[:forum, #post.question], :notice => "Post Up Voted"
end
end
and I have an AJAX call to up vote a post, which works perfectly fine except I need it to stop the AJAX call if the first condition, user_has_rated_post? is met.
So the question is how can I interrupt or force an error to return to AJAX, or should I be trying to go about this another way?

Yes you have to return something that jQuery(or your AJAX solution) interprets as an error. Then you will have to handle this error in javascript code(or just do nothing if that fits). I think anything above 400 is by convention considered an error. See the list of HTTP status codes and pick the one that suits you most http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html. Here I would bet on 403 - The server understood the request, but is refusing to fulfill it. You can always just render 500, but I think it's better to be specific.

Related

How to pass django error status to ajax

Using django rest framework with backbone.
Current situation:
Whenever an ajax call fails, django responds through get_error_response
As soon as get_error_response gets invoked, django raises a error on client side too, as i am not handling this error in django(server) side.
views.py snippet
def get_error_response(self):
return Response(
self.serializer.errors, status=status.HTTP_400_BAD_REQUEST
)
Requirement:
I want to be able to pass all error statuses to $ajax.fail() promise, and handle it there on client side, thereby enabling me to show the error messages to user.
Note:something like the code given below is what i am expecting. But the problem is, this response would got to $ajax.done promise(), wheras i want it in $ajax.fail() promise
def get_error_response(self):
return Response({
"msg":self.serializer.errors, "error_status":status.HTTP_400_BAD_REQUEST
})
Do ask if more clarity is required.
No matter if you're using a Response from Django Rest Framework or the normal Django HttpResponse you always need to pass the keyworded argument status in order to make the response actually have the correct status code thus invoking the correct handler in your front end code.
What your last example does is only passing a data or content argument which is making the response class default to a 200 status code.
return Response(your_data, status=404)

Requests for a form that submits through ajax multiply with each subsequent submit

I have a form that makes an ajax request, the problem is that every time I click on it, the amount of times it makes that request multiplies.
Now I'm sure it's because of the way I've set up submit-intercept but I don't know how else to do it whilst still encapsulating it as a single component.
I'm using react as my view layer and I've attached a function that contains code to intercept the request and this function is called in both the afterMount callback and the after_update callback; if I don't do this then either the form submit is never intercepted or it only intercepts it once and then just does a normal submit.
Now obviously it's multiplying because those events fire and add an extra submit-handler.
I'm using opal and react.rb so the code might look a little odd.
Here's my function that intercepts the submit action on the form
def set_up_login_form
puts 'setting up form'
login_form = Element["#login_form"]
login_form.on :submit do |event|
unless login_state == :processing
event.prevent_default
username = login_form.find('#username').value
password = login_form.find('#password').value
login!
self.username = username
self.handle_login_submit({username: username , password: password})
end
end
end
Here are my call backs:
after_mount do
fix_button #untill materialize.js gets fixed
set_up_login_form
end
after_update do
set_up_login_form
end
I was able to reduce the amount of requests made by checking if the component state was already in the middle of a request, whilst this doesn't reduce the amount of submit handlers being added it does stop a good amount from doing anything, but it doesn't stop the actual multiplying of handlers being added.
I don't know why I didn't think of it till a colleague mentioned it but by moving the form to a sub-component I can now run the intercept code on the form components mount which only happens when it's rendered so problem solved!

How do I add custom logging for which route is satisfying a request in Sinatra?

I'm working on a Sinatra app that has a bunch of routes of all sorts. I'd like to add some custom logging that logs the params of the get or post call that ends up generating the response for the request. I realize I could subclass the get/post definition to wrap the block with a logging call. But I suspect there is a more appropriate approach.
You can use Sinatra's before hook in your controller, and print out some information contained on the request
before do
if request.request_method == :get || request.request_method == :post
puts request.path_info, params.inspect # check out the request variable for more info you might like to ouput
end
end

Cucumber, selenium, ruby: best practices to check 301 redirect

I need to check 301 redirect.
So I have old URLs that should redirect to new ones.
What are the best practices to verify it?
Now I'm thinking about simple way: navigate to an old URL and check that the new URL is correct and corresponding page displays. Can I check that it was 301 redirect?
I found the following article: http://www.natontesting.com/2010/09/06/announcing-responsalizr-test-http-response-codes-in-ruby/
but after redirection I see the current status code =200
any suggestion how can I catch 301 status code?
Thank you in advance
Don't do it in a feature spec. In a feature spec (cucumber), you test the site how the user sees it, and the user doesn't care what the status code was. If you really care about the response, do it in a controller or better request spec. With rspec, it could look like this:
describe 'redirects' do
context 'on GET /old_users' do
before do
get '/old_users'
end
it 'redirects /old_users to /users' do
expect(response).to redirect_to('/users')
end
it 'responds with a 301 - Permanently moved' do
expect(response.status).to eq(301)
end
end
end
https://www.relishapp.com/rspec/rspec-rails/docs/request-specs/request-spec

Grab Facebook signed_request with Sinatra

I'm trying to figure out whether or not a user likes our brand page. Based off of that, we want to show either a like button or some 'thank you' text.
I'm working with a sinatra application hosted on heroku.
I tried the code from this thread: Decoding Facebook's signed request in Ruby/Sinatra
However, it doesn't seem to grab the signed_request and I can't figure out why.
I have the following methods:
get "/tab" do
#encoded_request = params[:signed_request]
#json_request = decode_data(#encoded_request)
#signed_request = Crack::JSON.parse(#json_request)
erb :index
end
# used by Canvas apps - redirect the POST to be a regular GET
post "/tab" do
#encoded_request = params[:signed_request]
#json_request = decode_data(#encoded_request)
#signed_request = Crack::JSON.parse(#json_request)
redirect '/tab'
end
I also have the helper messages from that thread, as they seem to make sense to me:
helpers do
def base64_url_decode(payload)
encoded_str = payload.gsub('-','+').gsub('_','/')
encoded_str += '=' while !(encoded_str.size % 4).zero?
Base64.decode64(encoded_str)
end
def decode_data(signed_request)
payload = signed_request.split('.')
data = base64_url_decode(payload)
end
end
However, when I just do
#encoded_request = params[:signed_request]
and read that out in my view with:
<%= #encoded_request %>
I get nothing at all.
Shouldn't this return at least something? My app seems to be crashing because well, there's nothing to be decoded.
I can't seem to find a lot of information about this around the internet so I'd be glad if someone could help me out.
Are there better ways to know whether or not a user likes our page? Or, is this the way to go and am I just overlooking something obvious?
Thanks!
The hint should be in your app crashing because there's nothing to decode.
I suspect the parameters get lost when redirecting. Think about it at the HTTP level:
The client posts to /tab with the signed_request in the params.
The app parses the signed_request and stores the result in instance variables.
The app redirects to /tab, i.e. sends a response with code 302 (or similar) and a Location header pointing to /tab. This completes the request/response cycle and the instance variables get discarded.
The client makes a new request: a GET to /tab. Because of the way redirects work, this will no longer have the params that were sent with the original POST.
The app tries to parse the signed_request param but crashes because no such param was sent.
The simplest solution would be to just render the template in response to the POST instead of redirecting.
If you really need to redirect, you need to carefully pass along the signed_request as query parameters in the redirect path. At least that's a solution I've used in the past. There may be simpler ways to solve this, or libraries that handle some of this for you.

Resources