Skip to content

Releases: palkan/action_policy

0.7.0

20 Jun 23:17
Compare
Choose a tag to compare

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

02 Sep 11:01
Compare
Choose a tag to compare

Changes

  • Drop Ruby 2.5 support.

Features

  • Added inline_reasons: true option to allowed_to? to avoid wrapping reasons.

See #186 for discussion.

  • Add strict_namespace: option to policy_for behaviour.

Fixes

  • Explicit context were not merged with implicit one within policy classes (#173).

0.5.0

29 Sep 13:17
Compare
Choose a tag to compare

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 and default_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! and allow! 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

12 Dec 02:37
Compare
Choose a tag to compare

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" 🎸

02 Apr 23:13
Compare
Choose a tag to compare

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 for authorize! 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}

0.2.0

17 Jun 11:53
Compare
Choose a tag to compare
0.2.0 Pre-release
Pre-release

Highlights

  • JRuby compatibility

  • Added reasons.details:

    rescue_from ActionPolicy::Unauthorized do |ex|
      ex.result.reasons.details #=> { stage: [:show?] }
    end

See Changelog for more.

0.1.0 "Snowy Pittsburgh"

17 Apr 12:25
Compare
Choose a tag to compare
Pre-release

RailsConf 2018 special pre-release.

See slides.