Skip Strong Parameters validation of nested attributes with CanCan


Consider the following case: you want to expose an API that allows to create a Post resource under authorization control, passing contextually an array of nested comments that require authorization too,

post: {
          title: "Lorem Ipsum",
          comments: [{body: "..."}, {body: "..."}]
        }


Suppose to have the urgency of acting separately on post and comments authorization depending on specific conditions, relying on strong_parameters to verify which attributes to allow for mass updating. This topic was fairly discussed by CanCan users and different solution were proposed. At Sellf we decided to concentrate on satisfying the following needs:

  • demand to CanCan the initialization of the resource, which means applying the attributes in the hash conditions specified through CanCan Abilities;
  • preserve the params sent by a client through the POST request;
  • avoid ActiveSupport::HashWithIndifferentAccess error due a lack of Strong Parameters validation;
  • authorizing Post attributes in a first attempt (skipping nested comments authorization).

Basing on that, we decided to adopt the following solution that applies to Post controller:

class PostsController < ApplicationController

  check_authorization
  before_filter :custom_load_and_authorize_resource, only: [:create]
  load_and_authorize_resource :post, except: [:create]

  def create
    Rails.logger.info "Here it is: " + @post.inspect
    if @post.save
      render status: 201,
              json: @post
    else
      render status: 422,
              json: @post.errors
    end
  end

  def custom_load_and_authorize_resource
    @post = Post.new
    current_ability.attributes_for(:create, Post).each do |key, value|
      @post.send("#{key}=", value)
    end
    filtered_params = params[:post].dup
    filtered_params.delete(:comments)
    @post.attributes = filtered_params
    authorize! :create, @post
  end
end

As you can notice, the custom_load_and_authorize_resource method parses the ability attributes, behaving like the standard implementation of CanCan load_and_authorize_resource method for create actions. What we do in addition is to duplicate the parameters and delete the unnecessary nested resource to restrict the authorization on post attributes.

Questo articolo è stato pubblicato in Blog da r4m . Aggiungi il permalink ai segnalibri.