pundit-expected-attribute-values

CI Gem Version

Expected values for Pundit strong parameters. Works with Pundit 2.6+ expected_attributes / expected_attributes_for_action and Rails params.expect.

Declare which scalar values each attribute may have during mass assignment (for example, admins may set role to manager or user, while managers may only set role to user).

Keys stay in expected_attributes_for_action; allowed values live in expected_attribute_values_for_action.

Requirements

  • Ruby >= 3.3
  • Pundit >= 2.5 (ships a compatibility shim for expected_attributes until Pundit 2.6 is released)
  • Rails >= 7.0 (uses params.expect)

Installation

gem "pundit-expected-attribute-values"
bundle install
rails generate pundit:expected_attribute_values:install

Manual setup

# app/policies/application_policy.rb
class ApplicationPolicy
  include Pundit::ExpectedAttributeValues::Policy
end

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  include Pundit::Authorization
  include Pundit::ExpectedAttributeValues::Authorization
end

Usage

Policy

class UserPolicy < ApplicationPolicy
  def expected_attributes_for_action(_action)
    [:name, :email, :role]
  end

  def expected_attribute_values_for_action(_action)
    { role: :allowed_roles }
  end

  private

  def allowed_roles
    return %w[user manager admin] if user.admin?
    return %w[user] if user.manager?

    []
  end
end

Action-specific value rules (optional):

def expected_attribute_values_for_update
  { role: %w[user] }
end

Value sources: static arrays, callables (-> { ... }), or method references (:allowed_roles).

Controller

def update
  authorize @user
  if @user.update(expected_attributes(@user))
    redirect_to @user
  else
    render :edit
  end
end

Allowed values for forms or APIs:

pundit_expected_attribute_values_for(@user, :role)
# => ["user", "manager"]

Unexpected values

# config/initializers/pundit-expected-attribute-values.rb
Pundit::ExpectedAttributeValues.configure do |config|
  config.invalid_behavior = :strip # default — omit unexpected values
  # config.invalid_behavior = :raise
end

With :raise, unexpected values raise Pundit::ExpectedAttributeValues::UnexpectedValue:

rescue_from Pundit::ExpectedAttributeValues::UnexpectedValue, with: :unprocessable

Manual filtering

attrs = expected_attributes(@user)
# or on an extracted hash:
Pundit::ExpectedAttributeValues.filter(attrs, policy(@user), action: "update")

Testing

RSpec

# spec/support/pundit-expected-attribute-values.rb
require "pundit/expected_attribute_values/rspec"

expect(user_policy).to permit_expected_value(:role, "user")
expect(user_policy).not_to permit_expected_value(:role, "admin")
expect(user_policy).to permit_expected_values(:role).matching(%w[user manager])

Minitest

require "pundit/expected_attribute_values/minitest"

assert_permits_expected_value user_policy, :role, "user"
refute_permits_expected_value user_policy, :role, "admin"
assert_expected_values user_policy, :role, %w[user manager]

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install.

Releasing

  1. Update the version in lib/pundit/expected_attribute_values/version.rb.
  2. Add a dated section to CHANGELOG.md.
  3. Commit, tag (git tag vX.Y.Z), and push the tag.
  4. GitHub Actions publishes the gem to RubyGems when a v* tag is pushed. Configure trusted publishing on RubyGems.org for this repository (recommended), or publish locally with bundle exec rake release after configuring RubyGems credentials.

Contributing

See CONTRIBUTING.md. Bug reports and pull requests are welcome on GitHub.

License

The gem is available as open source under the terms of the MIT License.