No release in over a year
A Rails Controller Module that uses CanCan's permitted attribs instead of typical parameter allowlisting.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 3.2
= 6.1.7.3
~> 3.9
~> 1.4

Runtime

~> 3.5.0, >= 3.5.0
 Project Readme

Use CanCan's :permitted_attributes method to automatically determine controller permitted parameters.

CanCan provides a way to set permitted attributes, so why build something else?

Install (add to Gemfile)

gem 'cancancan_resource_controller', '~> 1'

Usage:

(Optional) create init file: config/initializers/cancancan_resource_controller.rb and populate it with the following:

require "cancancan_resource_controller"
# default values shown
CanCanCan::NestedAssignmentAndAuthorization.configure do |config|
  # Allows for stopping unauthorized actions without raising errors
  # - Will let root object (and valid, other nested objects) save, even if an invalid nested object exists, if true
  config.silence_raised_errors = false
  # Auto-determine what action to auth on nested associations (:create, :update, :destroy)
  # - :create if is a new record
  # - :update if pre-existing record
  # - :destroy if :_destroy parameter is present
  # - will use the action of the root object if set to false
  config.use_smart_nested_authorizations = true
  # Set to `true` if you're nesting parameter data under the resource_key
  # - i.e. params => {user: {email: 'test', name: 'fun'}}
  # Set to `false` if resource parameter data is direct in in params.
  # - i.e. params => {email: 'test', name: 'fun'}
  config.use_resource_key_in_params = false
end

Mainly built out the :create, :update, and :destroy methods. We also have the :index and :show methods, but I would recommend overriding those.

class UsersController < ActionController::Base
  include CanCanCan::AbstractResourceController

  # index, update, create, destroy methods are now provided and backed by CanCan's Ability settings.

  # All actions use the following to pull the object from the database:
  # `@resource ||= @resource_class.find(params[:id])`
  # if you need to locate the object yourself, or apply additional logic, you can use a `before_action` hook.

  # almost all methods will render a @resource object
  # - :index renders a @resources object
  # i.e.:
  # respond_to do |format|
  #   format.html # Renders the default
  #   format.json { render json: @resource }
  # end
end

Handing associations in your ability.rb

class User < ApplicationRecord
  has_many :vehicles, inverse_of: :user
  accepts_nested_attributes_for :vehicles, allow_destroy: true
end
class Vehicle < ApplicationRecord
  has_many :vehicles_parts
  has_many :parts, through: :vehicles_parts
  belongs_to :user
end
class Parts < ApplicationRecord
  has_many :vehicles_parts
  has_many :vehicles, through: :vehicles_parts
end

class Ability
  include CanCan::Ability

  def initialize(user = nil)
    # Nested Attribs
    # - `association_name + '_attributes'`
    # - :vehicles_attributes will be used to permit it's usage in your controller
    can :update, User, [:first_name, :last_name, :vehicles_attributes]

    # Add/Remove IDs from has_many assocation
    # - part_ids
    can :update, Vehicle, [:make, :model, :part_ids]
  end
end

Implementing Pagination on :index

class UsersController < ActionController::Base
  include CanCanCan::AbstractResourceController

  protected

  # Use a gem or implement manually, like so
  def respond_with_resources
    page     = params[:page]&.to_i || 1
    per_page = params[:per_page]&.to_i || 10
    offset   = per_page * (page - 1)
    @resources = @resources.limit(per_page).offset(offset)
    super
  end
end

Implementing search on :index

class UsersController < ActionController::Base
  include CanCanCan::AbstractResourceController

  protected

  # - can be used for searching or whatever
  def index_resource_query resource_query
    return resource_query
  end
end