Releases: palkan/action_policy
0.7.0
Features
-
Support callable objects as scopes:
class PostPolicy < ApplicationPolicy relation_scope AuthorizedPosts end class AuthorizedPosts def self.call(policy, relation) user = policy.user user.admin? ? relation : relation.where(user: user) end end
Changes
-
Drop Ruby 2.6 support.
-
Prism is now used as a parser for debugging utils.
0.6.0
0.5.0
This release includes a bunch of minor features and improvements based on the community requests and suggestions.
Features
- Added
Result#all_details
to return all collected details in a single hash.
See #130 for some example use cases.
-
Added
default:
option to the.lookup
method anddefault_authorization_policy_class
callback to behaviours. -
Add
skip_verify_authorized!
to Rails controllers integration.
This method allows you to skip the verify_authorized
callback dynamically.
- Added
allowance_to
method to authorization behaviours.
This method is similar to allowed_to?
but returns an authorization result object.
Changes
- The
deny!
andallow!
methods are now parts of the core API.
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)
.
- Rule aliases are now supported in
allowed_to?
/check?
calls within policies.
Misc
- Dropped Ruby 2.4 support.
0.4.0
Features
- Optional authorization context. (#95)
In addition to allow_nil: true
, we now have an option to skip the context altogether:
class OptionalRolePolicy < ActionPolicy::Base
authorize :role, optional: true
end
policy = OptionalRolePolicy.new
policy.role #=> nil
- Rails generators. (#87)
Now you can use action_policy:install
and action_policy:policy MODEL
Rails generators.
- New instrumentation event:
action_policy.init
.
Triggered every time a new policy object is initialized.
Changes
- Composed matchers are supported in authorization target testing.
Now you can write tests like this:
expect { subject }.to be_authorized_to(:show?, an_instance_of(User))
0.3.0 "A denial" 🎸
Seattle.rb special.
tl;dr scopes; instrumentation; i18n integration; better testing and debugging.
Features
Scopes
Action Policy provides a universal API for defining different scoping rules: for different kinds of data (e.g. Active Record relations or Action Controller parameters) and different contexts (via the _named scopes).
For example, when you want to scope Active Record collections depending on the current user permissions:
class PostsController < ApplicationController
def index
@posts = authorized_scope(Post.all)
end
end
class PostPolicy < ApplicationPolicy
relation_scope do |relation|
next relation if user.admin?
relation.where(user: user)
end
end
And then in your test you check that the correct scope has been applied:
describe UsersController do
subject { get :index }
it "has authorized scope" do
expect { subject }.to have_authorized_scope(:active_record_relation)
.with(PostPolicy).with_target { |target|
# add additional exceptions for the matched target (`Post.all` in our case)
# if you want to make sure that the scope has been applied to the correct data
}
end
end
📖 Read the docs.
Failure reasons enhancements: full_message
and arbitrary details
When the i18n
gem is available in your app, the reasons
object implements the #full_messages
and the result
object implements the #message
method, which generates the failure messages using the locales (similarly to ActiveMode::Errors
):
action_policy:
policy:
post:
show?: "You cannot view this post"
class ApplicationController < ActionController::Base
rescue_from ActionPolicy::Unauthorized do |ex|
p ex.result.reasons.full_messages #=> ["You cannot view this post"]
end
end
📖 Read the docs.
You can now add a custom meta data to your failure reasons to provide more context:
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
📖 Read the docs.
RSpec DSL
Custom DSL for writing policy specs has been addedL
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
📖 Read the docs.
Debugging helpers
Added Policy#pp(rule)
method to print the annotated rule source code.
It aims to help debugging complex policy rules:
def edit?
binding.pry
(user.name == "John") && (admin? || access_feed?)
end
pry> pp :edit?
MyPolicy#edit?
↳ (
user.name == "John" #=> false
)
AND
(
admin? #=> false
OR
access_feed? #=> true
)
)
📖 Read the docs and check the PR#63.
Other
- Added ActiveSupport-based instrumentation.
📖 Read the docs.
-
Added
#implicit_authorization_target
.See #35.
Implicit authorization target (defined by
implicit_authorization_target
) is used when no target specified forauthorize!
call.For example, for Rails controllers integration it's just
controller_name.classify.safe_constantize
. -
Added Symbol lookup to the lookup chain.
For instance, lookup will implicitly use AdminPolicy
in a following case:
# admin_controller.rb
class AdminController < ApplicationController
authorize! :admin, to: :update_settings
end
- Adde ability to pass authorization context explicitly.
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}