简体   繁体   中英

How do I respond to CanCan::AccessDenied with an AJAX JSON response?

I want to respond to CanCan::AccessDenied with JSON if the request is via AJAX, but it is always responding with status 200 and a redirect regardless. I want to implement this answer: https://stackoverflow.com/a/10013873/148844 . I don't know how it is overriding the status 302 to 200, let alone not rendering JSON. I also tried format.js but that didn't work.

application_controller.rb
class ApplicationController < ActionController::Base
  include CanCan::ControllerAdditions

  rescue_from CanCan::AccessDenied do |exception|
    flash[:warning] = exception.message
    logger.info exception
    respond_to do |format|
      logger.info "format: " + format.to_s
      format.html do
        if user_signed_in? && current_user.type
          redirect_to "/dashboard"
        else
          redirect_to root_path
        end
      end
      format.json do
        render json: {success: false, message: 'Access Denied: '+exception.message}, status: 401
      end
    end
  end
CoffeeScript
$.post "/topics/order", {'id_order[]': arr}, (data, textStatus, jqXHR) ->
  ...
Gemfile
gem 'cancancan', '~> 1.10'
Console
Started POST "/topics/order" for ::1 at 2018-09-14 14:44:33 -0400
...
You are not authorized to access this page.
format: #<ActionController::MimeResponds::Collector:0x0000000d4b2a28>
Redirected to http://localhost:3000/dashboard
Completed 200 OK in 314ms (ActiveRecord: 28.0ms)

https://github.com/CanCanCommunity/cancancan#4-handle-unauthorized-access

https://api.rubyonrails.org/classes/ActionController/MimeResponds.html#method-i-respond_to


I've done some testing and added

  format.json { head :forbidden, content_type: 'text/html' }
  format.js   { head :forbidden, content_type: 'text/html' }

To the top of respond_to block and it does work. When moved to the bottom of the block, it doesn't work. Rails seems to be responding to the very first format it sees, regardless of the format!

I added json as the dataType to the post and now it is working.

$.post "/topics/order", {'id_order[]': arr}, (data, textStatus, jqXHR) ->
  ...
, 'json'

https://api.jquery.com/jquery.ajax/#jQuery-ajax-settings

dataType (default: Intelligent Guess (xml, json, script, or html))
Type: String
The type of data that you're expecting back from the server. If none is specified, jQuery will try to infer it based on the MIME type of the response (an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string). The available types (and the result passed as the first argument to your success callback) are:

"json" : Evaluates the response as JSON and returns a JavaScript object. Cross-domain "json" requests that have a callback placeholder, eg ?callback=?, are performed using JSONP unless the request includes jsonp: false in its request options. The JSON data is parsed in a strict manner; any malformed JSON is rejected and a parse error is thrown. As of jQuery 1.9, an empty response is also rejected; the server should return a response of null or {} instead. (See json.org for more information on proper JSON formatting.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM