- Fix generated policies' outdated Ruby API (to work with Ruby 3.2).
- Fix loading of Rails scope matchers. (@palkan)
- Add support to assert context in test matchers (@matsales28)
- Allow omitting authorization record if
with
is provided. (@palkan)
- Fix policy lookup when a namespaced record is passed and the strict mode is used. (@palkan)
- Expose
#authorized_scope
as helper. (@palkan) - [Fixes #207] refinement#include deprecation warning on Ruby 3.1
- Drop Ruby 2.5 support.
- [Closes #186] Add
inline_reasons: true
option toallowed_to?
to avoid wrapping reasons. (@palkan) - [Fixes #173] Explicit context were not merged with implicit one within policy classes. (@palkan)
- Add
strict_namespace:
option to policy_for behaviour ([@kevynlebouille][]) - Prevent possible side effects in policy lookup (@tomdalling)
The previous release had incorrect dependencies (due to the missing transpiled files).
- Add
ActionPolicy.enforce_predicate_rules_naming
config to catch rule missing question mark (@skojin)
- Upgrade to Ruby 3.0. (@palkan)
-
Add support for RSpec aliases detection when linting policy specs with
rubocop-rspec
2.0 (@pirj) -
Fix
strict_namespace: true
lookup option not finding policies in global namespace (@Be-ngt-oH)
- Move
deny!
/allow!
to core. (@palkan)
Now you can call deny!
and allow!
in policy rules to fail- or pass-fast.
BREAKING. Pre-check name is no longer added automatically to failure reasons. You should specify the reason
explicitly: deny!(:my_reason)
.
-
Add
Result#all_details
to return all collected details in a single hash. (@palkan) -
Add
default
option to lookup anddefault_authorization_policy_class
callback to behaviour. (@palkan) -
Add
skip_verify_authorized!
to Rails controllers integration. (@palkan)
This method allows you to skip the verify_authorized
callback dynamically.
This method is similar to allowed_to?
but returns an authorization result object.
- Support aliases in
allowed_to?
/check?
calls within policies. (@palkan)
- Add strict_namespace option to lookup chain. (@rainerborene)
- Fix symbol lookup with namespaces. (@palkan)
Fixes #122.
- Separated
#classify
-based and#camelize
-based symbol lookups. (@Be-ngt-oH)
Only affects Rails apps. Now lookup for :users
tries to find UsersPolicy
first (camelize),
and only then search for UserPolicy
(classify).
See PR#118.
- Add
#cache(*parts, **options) { ... }
method. (@palkan)
Allows you to cache anything in policy classes using the Action Policy cache key generation mechanism.
- Handle versioned Rails cache keys. (@palkan)
Use #cache_with_version
as a cache key if defined.
- Fix regression introduced in 0.4.0 which broke testing Class targets. (@palkan)
- Add
action_policy.init
instrumentation event. (@palkan)
Triggered every time a new policy object is initialized.
- Fix policy memoization with explicit context. (@palkan)
Explicit context (authorize! context: {}
) wasn't considered during
policies memoization. Not this is fixed.
- Support composed matchers for authorization target testing. (@palkan)
Now you can write tests like this:
expect { subject }.to be_authorized_to(:show?, an_instance_of(User))
- Fix Rails generators. (@palkan)
Only invoke install generator if application_policy.rb
is missing.
Fix hooking into test frameworks.
- Improve pretty print functionality. (@palkan)
Colorize true/false values.
Handle multiline expressions and debug statements (i.e., binding.pry
).
- Add Rails generators. (@nicolas-brousse)
Adds action_policy:install
and action_policy:policy MODEL
Rails generators.
- Optional authorization target. (@somenugget)
Allows making authorization context optional:
class OptionalRolePolicy < ActionPolicy::Base
authorize :role, optional: true
end
policy = OptionalRolePolicy.new
policy.role #=> nil
- Fixed thread-safety issues with scoping configs. (@palkan)
Fixes #75.
- Fixed bug with missing implicit target and hash like scoping data. (@palkan)
Fixes #70.
- Added ActiveSupport-based instrumentation. (@palkan)
See PR#4
- Allow passing authorization context explicitly. (@palkan)
Closes #3.
Now it's possible to override implicit authorization context
via context
option:
authorize! target, to: :show?, context: {user: another_user}
authorized_scope User.all, context: {user: another_user}
- Renamed
#authorized
to#authorized_scope
. (@palkan)
NOTE: #authorized
alias is also available.
- Added
Policy#pp(rule)
method to print annotated rule source code. (@palkan)
Example (debugging):
def edit?
binding.pry # rubocop:disable Lint/Debugger
(user.name == "John") && (admin? || access_feed?)
end
pry> pp :edit?
MyPolicy#edit?
↳ (
user.name == "John" #=> false
)
AND
(
admin? #=> false
OR
access_feed? #=> true
)
)
See PR#63
- Added ability to provide additional failure reasons details. (@palkan)
Example:
class ApplicantPolicy < ApplicationPolicy
def show?
allowed_to?(:show?, object.stage)
end
end
class StagePolicy < ApplicationPolicy
def show?
# Add stage title to the failure reason (if any)
# (could be used by client to show more descriptive message)
details[:title] = record.title
# then perform the checks
user.stages.where(id: record.id).exists?
end
end
# when accessing the reasons
p ex.result.reasons.details #=> { stage: [{show?: {title: "Onboarding"}] }
See palkan#58
The goal of this DSL is to reduce the boilerplate when writing policies specs.
Example:
describe PostPolicy do
let(:user) { build_stubbed :user }
let(:record) { build_stubbed :post, draft: false }
let(:context) { {user: user} }
describe_rule :show? do
succeed "when post is published"
failed "when post is draft" do
before { post.draft = false }
succeed "when user is a manager" do
before { user.role = "manager" }
end
end
end
end
- Added I18n support (@DmitryTsepelev)
Example:
class ApplicationController < ActionController::Base
rescue_from ActionPolicy::Unauthorized do |ex|
p ex.result.message #=> "You do not have access to the stage"
p ex.result.reasons.full_messages #=> ["You do not have access to the stage"]
end
end
- Added scope options to scopes. (@korolvs)
See #47.
Example:
# users_controller.rb
class UsersController < ApplicationController
def index
@user = authorized(User.all, scope_options: {with_deleted: true})
end
end
# user_policy.rb
describe UserPolicy < Application do
relation_scope do |relation, with_deleted: false|
rel = some_logic(relation)
with_deleted ? rel.with_deleted : rel
end
end
- Added Symbol lookup to the lookup chain (@DmitryTsepelev)
For instance, lookup will implicitly use AdminPolicy
in a following case:
# admin_controller.rb
class AdminController < ApplicationController
authorize! :admin, to: :update_settings
end
- Added testing for scopes. (@palkan)
Example:
# users_controller.rb
class UsersController < ApplicationController
def index
@user = authorized(User.all)
end
end
# users_controller_spec.rb
describe UsersController do
subject { get :index }
it "has authorized scope" do
expect { subject }.to have_authorized_scope(:active_record_relation)
.with(PostPolicy)
end
end
- Added scoping support. (@palkan)
See #5.
By "scoping" we mean an ability to use policies to scope data.
For example, when you want to scope Active Record collections depending on the current user permissions:
class PostsController < ApplicationController
def index
@posts = authorized(Post.all)
end
end
class PostPolicy < ApplicationPolicy
relation_scope do |relation|
next relation if user.admin?
relation.where(user: user)
end
end
Action Policy provides a flexible mechanism to apply scopes to anything you want.
Read more in docs.
- Added
#implicit_authorization_target
. (@palkan).
See #35.
Implicit authorization target (defined by implicit_authorization_target
) is used when no target specified for authorize!
call.
For example, for Rails controllers integration it's just controller_name.classify.safe_constantize
.
- Consider
record#policy_name
when looking up for a policy class. (@palkan)
-
Add
did_you_mean
suggestion toUnknownRule
exception. (@palkan) -
Add
check?
as an alias forallowed_to?
in policies. (@palkan) -
Add ability to disable per-thread cache and disable it in test env by default. (@palkan)
You can control per-thread cache by setting:
ActionPolicy::PerThreadCache.enabled = true # or false
We cache namespaced policy resolution for better performance (it could affect performance when we look up a policy from a deeply nested module context).
It could be disabled by setting ActionPolicy::LookupChain.namespace_cache_enabled = false
. It's enabled by default unless RACK_ENV
env var is specified and is not equal to "production"
(e.g. when RACK_ENV=test
the cache is disabled).
When using Rails it's enabled only in production mode but could be configured through setting the config.action_policy.namespace_cache_enabled
parameter.
- [Fix #18] Clarify documentation around, and fix the way
resolve_rule
resolves rules and rule aliases when subclasses are involved. (@brendon)
-
Use
send
instead ofpublic_send
to get theauthorization_context
so that contexts such ascurrent_user
can beprivate
in the controller. (@brendon) -
Fix railtie initialization for Rails < 5. (@brendon)
rescue_from ActionPolicy::Unauthorized do |ex|
ex.result.reasons.details #=> { stage: [:show?] }
end
- Add
ExecutionResult
. (@palkan)
ExecutionResult contains all the rule application artifacts: the result (true
/ false
),
failures reasons.
This value is now stored in a cache (if any) instead of just the call result (true
/ false
).
- Add
Policy.identifier
. (@palkan)
- Fix modules order in
ActionPolicy::Base
. (@ilyasgaraev)
- Initial pre-release version. (@palkan)