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.