How do I conditionally disable Ramaze layout? - ruby

I'd like a controller method to respond by disabling/denying layout if the request happens to be an ajax request (i.e., request.xhr? == true).
The following doesn't seem to work -- it returns the layout nonetheless
class FooController < Ramaze::Controller
layout :default
def bar
if request.xhr?
layout nil
"return something here" #just return this string without the layout
else
... #return with full layout
end
end

You can bypass view and layout rendering by calling respond! like this :
respond!(body, status, 'Content-Type' => 'whatever/foo')
Where body is your (json ?) body, status the HTTP response code.
You can then provide a hash with returned headers.
However, you might be interested in provides that can handle requests differently if they end, for instance, with '.json'. See http://ramaze.net/documentation/file.views.html#View_Mapping for more info on this.

Related

How to restrict the ajax call from out side of the browser in django

i am working in a project, there is no user authentication and authorization. Bascially i am calling ajax in client side and it executes a view in django and return a json out. How can i validate this request is only coming from browser and how to restrict the if this not coming from the browser or any manual script?
You can use request.is_ajax() method
HttpRequest.is_ajax()
Returns True if the request was made via an XMLHttpRequest, by checking the HTTP_X_REQUESTED_WITH header for the string 'XMLHttpRequest'. Most modern JavaScript libraries send this header. If you write your own XMLHttpRequest call (on the browser side), you’ll have to set this header manually if you want is_ajax() to work.
If a response varies on whether or not it’s requested via AJAX and you are using some form of caching like Django’s cache middleware, you should decorate the view with vary_on_headers('HTTP_X_REQUESTED_WITH') so that the responses are properly cached.
docs
Im updating my answer to fit what we commented above
In your views
from django.core import signing
from django.views.generic import View, TemplateView
from django.http import HttpResponseBadRequest
class BrowserView(TemplateView):
template_name = 'yourtemplate.html'
def get_context_data(self, **kwargs):
ctx = super(BrowserView, self).get_context_data(**kwargs)
ctx['token'] = signing.dumps(self.request.session_id)
return ctx
class AjaxView(View):
def get(self, *args, **kwargs):
if self.request.is_ajax():
try:
sign = signing.loads(self.request.GET.get('token'), max_age=(20))
if sign == self.request.session_id:
## return ajax
return HttpResponseBadRequest('You are not authorized to see this page')
except signing.BadSignature:
return HttpResponseBadRequest('You are not authorized to see this page')
else:
return HttpResponseBadRequest('You are not authorized to see this page')
In your template
In this case I used a meta tag, but you get the idea
<meta name="validation" content="{{token}}" />
In your javascript
var t = document.querySelector("meta[name='validation']").getAttribute('content');
$.ajax({
url:'yoururl',
data: yourData + '&token=' + t,
type: 'get',
success: function(response){
// do whatever
},
error: function(e){
console.log(e);
}
});
I don't believe it's possible to 100% prevent this, but there are some things you can do:
a set-cookie header w/some unique ID on the page, but not on API responses.
if the cookie isn't received by your API, return a 401.
tracking API calls per unique ID could be a good indicator of "proper" usage.
associate IDs w/IPs.
the tracking metrics can be combined w/a threshold that blocks requests if exceeded.
you can check the referrer header (easy to spoof).
finally, lookup the is_ajax method of Django's, but this just checks for an XMLHttpRequest header (again, easy to spoof).

Scrapy check if image response is 404

I want to process image URLs, I enabled and configured as Scrapy Docs; but what happens if the image URL returns 404 or is redirected. I want to log that, save the failed URLs and the HTTP error/redirect code. Where can I put the code to do that?
It is completely wrong to handle that in the pipleline, because the response would go throw all the middlewares back to your spider then to your pipleline, while your purpose is just logging the failure.
You should build your own middleware to handle any HTTP response code.
By default, scrapy allows responses with statues codes between 200 and 300. You can edit that by listing the statue codes that you would like to receive like this:
class Yourspider(spider):
handle_httpstatus_list = [404, 302] #add any other code you need
Then you should build your middleware and add it to your configuration like this:
DOWNLOADER_MIDDLEWARES = {
'myProject.myMiddlewares.CustomSpiderMiddleware': SELECT_NUMBER_SUITS_FOR_YOU,
}
in your CustomSpiderMiddleware check the status like this:
process_spider_input(response, spider):
if response.status == 404
#do what ever you want
You have to create your custom pipeline, inherit it from the Imagepipeline, then override the item_completed method, as mentioned in the documentation
def item_completed(self, results, item, info):
image_paths = [x['path'] for ok, x in results if ok]
if not image_paths:
raise DropItem("Item contains no images")
item['image_paths'] = image_paths
return item
and lastly in the settings.py add your custom pipeline
ITEM_PIPELINES = {
'myproject.mypipeline': 100,
}

Why is it stating I am rendering or calling render twice?

I have written the following test which tries to update an already published post to saved. Meaning the user has published a post and now wants to mark it as saved. Which I do not allow.
it "should not update a post from published to saved" do
#post = FactoryGirl.create(:post, blog_id: #blog.id, saved: false, published: true)
put :update, :id => #post.id, post: {title: 'Sample Title', content: #post.content, saved: true}
expect(response.status).to eql 422
end
This particular test states:
AbstractController::DoubleRenderError:
Render and/or redirect were called multiple times in this action.
Which should not be the case because if we look at the method thats throwing it:
def post_controller_save(post, params)
do_not_save_published_post(post, params)
binding.pry
publish_post(post, params)
if post.save
set_tags(post, params)
set_categories(post, params)
render json: post, status: 200
else
render json: {:errors => post.errors}, status: 422
end
end
The first check we do is do_not_save_published_posts(post, params) (notice the binding.pry after it).
So if we follow this, we see the method in question (which is a private method):
def do_not_save_published_post(post, params)
if (post.published && params[:post][:saved])
binding.pry
render json: {:errors => 'Cannot save a published post.'}, status: 422
return
end
end
This method checks if the post in question is published. and that the params for the post object contains a saved parameter. If both of these are true, we will render an error and return. The key here is to notice this binding.pry.
In the test, it reaches this break point and then typing exit causes the return to be skipped and the binding.pry out side this method to be caught.
This SHOULD NOT HAPPEN. It should render me json with a status of 422. Is the fact that this, do_not_save_published_post is a private method a contributing factor?
Your call to do_not_save_published_post is just an ordinary method call, and returning from this method will behave like normal Ruby in that it will continue executing code after the method call.
You probably want to change your do_not_save_published_post to published_post?, move it to your model, have it return a boolean, and do your render logic in the controller.

Redirect user in Grails if browsing an action

I have a Grails controller action that is used for Ajax purposes, though you can still navigate and view the page in the browser.
class QuoteController {
def quoteService
/**
* This page uses the ajaxRandom function defined below to display random quotes.
*/
def random = {
def randomQuote = quoteService.getRandomQuote()
[quote:randomQuote]
}
/**
* I do not want this to be a valid page, but maintain its use as a simple Ajax method.
*/
def ajaxRandom = {
def randomQuote = quoteService.getRandomQuote()
response.outputStream << "<q>${randomQuote.content}</q><p>${randomQuote.author}</p>"
}
}
Is there a way to redirect if someone visits the URL via browser while maintaining the method's Ajax functionality from within a page?
def ajaxRandom = {
if(!request.xhr) { // this calls the dynamic method request.isXhr()
redirect action: 'random'
} else {
def randomQuote = quoteService.getRandomQuote()
response.outputStream << "<q>${randomQuote.content}</q><p>${randomQuote.author}</p>"
}
}
This works because most of the Ajax JS Libraries add the X-Requested-With header to the request. Grails add this isXhr() method dynamically to the HttpServletRequest class.
// test whether the current request is an XHR request
HttpServletRequest.metaClass.isXhr = {->
'XMLHttpRequest' == delegate.getHeader('X-Requested-With')
}
A simple way is to append a param to the url when calling it via ajax e.g. ?ajax=true
Then check for it and redirect if it's not there (such as when a use hits it with their browser).
If that is too easy to work around, inspect the request to see what is different between a browser request and an ajax request.
cheers
Lee
If you AJAX requests are always POSTS then you could check the method and assume a POST is an AJAX call because it's pretty hard for the average user to create a POST accidentally, where as they can always GET any URL (if they know of it)
Hope this helps.

Controlling Merb authentication errors

Hey there, im a little bit confused about handling invalid user authentication request, at login controller. So, i already have modified login view, but cant figure out where to put the exception handling block. It should work like this: you login - if its incorrect you will see warning message at /login .
Any ideas ?
What strategy have you chosen ? In my custom Strategy, I call the class method 'authenticate' on my User class:
class User
def self.authenticate(login, password)
u = User.first(:conditions => ['email = ?', login]) # find a user with this login
if u && u.authenticated?
return u
else
nil
end
end
end
Also, you might want to look at the source code of merb-auth-more/mixins/salted_user which is a module that is automatically mixed into your User class.
you would put your exception handling action in the exceptions controller
# handle NotAuthorized exceptions (403)
def not_authorized
render :format => :html
end
and to customise the view you would create a template in app/views/exceptions/not_authorized.html.haml

Resources