129
votes

In my action I wish to only respond with processing if it was called from an AJAX request. How do I check?

I want to do something like this:

def action
   @model = Model.find(params[:id])

   respond_to do |format|

      if (wasAJAXRequest()) #How do I do this?

         format.html #action.html.erb

      else

         format.html {redirect_to root_url}
   end
end
5

5 Answers

253
votes

You can check for a header[X-Requested-With] to see if it is an AJAX request. Here is a good article on how to do it.

Here is an example:

if request.xhr?
  # respond to Ajax request
else
  # respond to normal request
end
15
votes

If you're using :remote => true in your links or forms, you'd do:

respond_to do |format|
  format.js { #Do some stuff }

You can also check before the respond_to block by calling request.xhr?.

6
votes

Update:

As of Rails 6.1.0, xhr?() does actually (finally) return a boolean value.

https://github.com/rails/rails/commit/0196551e6039ca864d1eee1e01819fcae12c1dc9#diff-60b77e427ea7ba142faa477fac10b8d0134cede4e35a3b1953c425200fadf1acL267-L269


Original Answer:

The docs say that request.xhr?

Returns true if the “X-Requested-With” header contains “XMLHttpRequest”....

But BEWARE that

request.xhr? 

returns numeric or nil values not BOOLEAN values as the docs say, in accordance with =~.

irb(main):004:0> /hay/ =~ 'haystack'
=> 0
irb(main):006:0> /stack/ =~ 'haystack'
=> 3
irb(main):005:0> /asfd/ =~ 'haystack'
=> nil

It's based on this:

# File actionpack/lib/action_dispatch/http/request.rb, line 220
def xml_http_request?
  @env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/
end

so

env['HTTP_X_REQUESTED_WITH'] =~ /XMLHttpRequest/  => 0

The docs:

http://apidock.com/rails/v4.2.1/ActionDispatch/Request/xml_http_request%3F

1
votes

I like using before_action filters. They are especially nice when you need the same filter/authorization for multiple actions.

class MyController < AuthController
  before_action :require_xhr_request, only: [:action, :action_2]

  def action
    @model = Model.find(params[:id])
  end

  def action_2
    # load resource(s)
  end

  private

  def require_xhr_request
    redirect_to(root_url) unless request.xhr?
  end
end
1
votes
request.xhr? 

if this return 0 then it means its an ajax request, else it will return nil