Git Product home page Git Product logo

pundit's Introduction

Pundit

Main Code Climate Inline docs Gem Version

Pundit provides a set of helpers which guide you in leveraging regular Ruby classes and object oriented design patterns to build a straightforward, robust, and scalable authorization system.

Links:

Sponsored by: Varvet

Varvet logo

Installation

Please note that the README on GitHub is accurate with the latest code on GitHub. You are most likely using a released version of Pundit, so please refer to the documentation for the latest released version of Pundit.

bundle add pundit

Include Pundit::Authorization in your application controller:

class ApplicationController < ActionController::Base
  include Pundit::Authorization
end

Optionally, you can run the generator, which will set up an application policy with some useful defaults for you:

rails g pundit:install

After generating your application policy, restart the Rails server so that Rails can pick up any classes in the new app/policies/ directory.

Policies

Pundit is focused around the notion of policy classes. We suggest that you put these classes in app/policies. This is an example that allows updating a post if the user is an admin, or if the post is unpublished:

class PostPolicy
  attr_reader :user, :post

  def initialize(user, post)
    @user = user
    @post = post
  end

  def update?
    user.admin? || !post.published?
  end
end

As you can see, this is a plain Ruby class. Pundit makes the following assumptions about this class:

  • The class has the same name as some kind of model class, only suffixed with the word "Policy".
  • The first argument is a user. In your controller, Pundit will call the current_user method to retrieve what to send into this argument
  • The second argument is some kind of model object, whose authorization you want to check. This does not need to be an ActiveRecord or even an ActiveModel object, it can be anything really.
  • The class implements some kind of query method, in this case update?. Usually, this will map to the name of a particular controller action.

That's it really.

Usually you'll want to inherit from the application policy created by the generator, or set up your own base class to inherit from:

class PostPolicy < ApplicationPolicy
  def update?
    user.admin? or not record.published?
  end
end

In the generated ApplicationPolicy, the model object is called record.

Supposing that you have an instance of class Post, Pundit now lets you do this in your controller:

def update
  @post = Post.find(params[:id])
  authorize @post
  if @post.update(post_params)
    redirect_to @post
  else
    render :edit
  end
end

The authorize method automatically infers that Post will have a matching PostPolicy class, and instantiates this class, handing in the current user and the given record. It then infers from the action name, that it should call update? on this instance of the policy. In this case, you can imagine that authorize would have done something like this:

unless PostPolicy.new(current_user, @post).update?
  raise Pundit::NotAuthorizedError, "not allowed to update? this #{@post.inspect}"
end

You can pass a second argument to authorize if the name of the permission you want to check doesn't match the action name. For example:

def publish
  @post = Post.find(params[:id])
  authorize @post, :update?
  @post.publish!
  redirect_to @post
end

You can pass an argument to override the policy class if necessary. For example:

def create
  @publication = find_publication # assume this method returns any model that behaves like a publication
  # @publication.class => Post
  authorize @publication, policy_class: PublicationPolicy
  @publication.publish!
  redirect_to @publication
end

If you don't have an instance for the first argument to authorize, then you can pass the class. For example:

Policy:

class PostPolicy < ApplicationPolicy
  def admin_list?
    user.admin?
  end
end

Controller:

def admin_list
  authorize Post # we don't have a particular post to authorize
  # Rest of controller action
end

authorize returns the instance passed to it, so you can chain it like this:

Controller:

def show
  @user = authorize User.find(params[:id])
end

# return the record even for namespaced policies
def show
  @user = authorize [:admin, User.find(params[:id])]
end

You can easily get a hold of an instance of the policy through the policy method in both the view and controller. This is especially useful for conditionally showing links or buttons in the view:

<% if policy(@post).update? %>
  <%= link_to "Edit post", edit_post_path(@post) %>
<% end %>

Headless policies

Given there is a policy without a corresponding model / ruby class, you can retrieve it by passing a symbol.

# app/policies/dashboard_policy.rb
class DashboardPolicy
  attr_reader :user

  # `_record` in this example will be :dashboard
  def initialize(user, _record)
    @user = user
  end

  def show?
    user.admin?
  end
end

Note that the headless policy still needs to accept two arguments. The second argument will be the symbol :dashboard in this case, which is what is passed as the record to authorize below.

# In controllers
def show
  authorize :dashboard, :show?
  ...
end
# In views
<% if policy(:dashboard).show? %>
  <%= link_to 'Dashboard', dashboard_path %>
<% end %>

Scopes

Often, you will want to have some kind of view listing records which a particular user has access to. When using Pundit, you are expected to define a class called a policy scope. It can look something like this:

class PostPolicy < ApplicationPolicy
  class Scope
    def initialize(user, scope)
      @user  = user
      @scope = scope
    end

    def resolve
      if user.admin?
        scope.all
      else
        scope.where(published: true)
      end
    end

    private

    attr_reader :user, :scope
  end

  def update?
    user.admin? or not record.published?
  end
end

Pundit makes the following assumptions about this class:

  • The class has the name Scope and is nested under the policy class.
  • The first argument is a user. In your controller, Pundit will call the current_user method to retrieve what to send into this argument.
  • The second argument is a scope of some kind on which to perform some kind of query. It will usually be an ActiveRecord class or a ActiveRecord::Relation, but it could be something else entirely.
  • Instances of this class respond to the method resolve, which should return some kind of result which can be iterated over. For ActiveRecord classes, this would usually be an ActiveRecord::Relation.

You'll probably want to inherit from the application policy scope generated by the generator, or create your own base class to inherit from:

class PostPolicy < ApplicationPolicy
  class Scope < ApplicationPolicy::Scope
    def resolve
      if user.admin?
        scope.all
      else
        scope.where(published: true)
      end
    end
  end

  def update?
    user.admin? or not record.published?
  end
end

You can now use this class from your controller via the policy_scope method:

def index
  @posts = policy_scope(Post)
end

def show
  @post = policy_scope(Post).find(params[:id])
end

Like with the authorize method, you can also override the policy scope class:

def index
  # publication_class => Post
  @publications = policy_scope(publication_class, policy_scope_class: PublicationPolicy::Scope)
end

In this case it is a shortcut for doing:

def index
  @publications = PublicationPolicy::Scope.new(current_user, Post).resolve
end

You can, and are encouraged to, use this method in views:

<% policy_scope(@user.posts).each do |post| %>
  <p><%= link_to post.title, post_path(post) %></p>
<% end %>

Ensuring policies and scopes are used

When you are developing an application with Pundit it can be easy to forget to authorize some action. People are forgetful after all. Since Pundit encourages you to add the authorize call manually to each controller action, it's really easy to miss one.

Thankfully, Pundit has a handy feature which reminds you in case you forget. Pundit tracks whether you have called authorize anywhere in your controller action. Pundit also adds a method to your controllers called verify_authorized. This method will raise an exception if authorize has not yet been called. You should run this method in an after_action hook to ensure that you haven't forgotten to authorize the action. For example:

class ApplicationController < ActionController::Base
  include Pundit::Authorization
  after_action :verify_authorized
end

Likewise, Pundit also adds verify_policy_scoped to your controller. This will raise an exception similar to verify_authorized. However, it tracks if policy_scope is used instead of authorize. This is mostly useful for controller actions like index which find collections with a scope and don't authorize individual instances.

class ApplicationController < ActionController::Base
  include Pundit::Authorization
  after_action :verify_authorized, except: :index
  after_action :verify_policy_scoped, only: :index
end

This verification mechanism only exists to aid you while developing your application, so you don't forget to call authorize. It is not some kind of failsafe mechanism or authorization mechanism. You should be able to remove these filters without affecting how your app works in any way.

Some people have found this feature confusing, while many others find it extremely helpful. If you fall into the category of people who find it confusing then you do not need to use it. Pundit will work fine without using verify_authorized and verify_policy_scoped.

Conditional verification

If you're using verify_authorized in your controllers but need to conditionally bypass verification, you can use skip_authorization. For bypassing verify_policy_scoped, use skip_policy_scope. These are useful in circumstances where you don't want to disable verification for the entire action, but have some cases where you intend to not authorize.

def show
  record = Record.find_by(attribute: "value")
  if record.present?
    authorize record
  else
    skip_authorization
  end
end

Manually specifying policy classes

Sometimes you might want to explicitly declare which policy to use for a given class, instead of letting Pundit infer it. This can be done like so:

class Post
  def self.policy_class
    PostablePolicy
  end
end

Alternatively, you can declare an instance method:

class Post
  def policy_class
    PostablePolicy
  end
end

Plain old Ruby

Pundit is a very small library on purpose, and it doesn't do anything you can't do yourself. There's no secret sauce here. It does as little as possible, and then gets out of your way.

With the few but powerful helpers available in Pundit, you have the power to build a well structured, fully working authorization system without using any special DSLs or funky syntax.

Remember that all of the policy and scope classes are plain Ruby classes, which means you can use the same mechanisms you always use to DRY things up. Encapsulate a set of permissions into a module and include them in multiple policies. Use alias_method to make some permissions behave the same as others. Inherit from a base set of permissions. Use metaprogramming if you really have to.

Generator

Use the supplied generator to generate policies:

rails g pundit:policy post

Closed systems

In many applications, only logged in users are really able to do anything. If you're building such a system, it can be kind of cumbersome to check that the user in a policy isn't nil for every single permission. Aside from policies, you can add this check to the base class for scopes.

We suggest that you define a filter that redirects unauthenticated users to the login page. As a secondary defence, if you've defined an ApplicationPolicy, it might be a good idea to raise an exception if somehow an unauthenticated user got through. This way you can fail more gracefully.

class ApplicationPolicy
  def initialize(user, record)
    raise Pundit::NotAuthorizedError, "must be logged in" unless user
    @user   = user
    @record = record
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      raise Pundit::NotAuthorizedError, "must be logged in" unless user
      @user = user
      @scope = scope
    end
  end
end

NilClassPolicy

To support a null object pattern you may find that you want to implement a NilClassPolicy. This might be useful where you want to extend your ApplicationPolicy to allow some tolerance of, for example, associations which might be nil.

class NilClassPolicy < ApplicationPolicy
  class Scope < ApplicationPolicy::Scope
    def resolve
      raise Pundit::NotDefinedError, "Cannot scope NilClass"
    end
  end

  def show?
    false # Nobody can see nothing
  end
end

Rescuing a denied Authorization in Rails

Pundit raises a Pundit::NotAuthorizedError you can rescue_from in your ApplicationController. You can customize the user_not_authorized method in every controller.

class ApplicationController < ActionController::Base
  include Pundit::Authorization

  rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

  private

  def user_not_authorized
    flash[:alert] = "You are not authorized to perform this action."
    redirect_back(fallback_location: root_path)
  end
end

Alternatively, you can globally handle Pundit::NotAuthorizedError's by having rails handle them as a 403 error and serving a 403 error page. Add the following to application.rb:

config.action_dispatch.rescue_responses["Pundit::NotAuthorizedError"] = :forbidden

Creating custom error messages

NotAuthorizedErrors provide information on what query (e.g. :create?), what record (e.g. an instance of Post), and what policy (e.g. an instance of PostPolicy) caused the error to be raised.

One way to use these query, record, and policy properties is to connect them with I18n to generate error messages. Here's how you might go about doing that.

class ApplicationController < ActionController::Base
 rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized

 private

 def user_not_authorized(exception)
   policy_name = exception.policy.class.to_s.underscore

   flash[:error] = t "#{policy_name}.#{exception.query}", scope: "pundit", default: :default
   redirect_back(fallback_location: root_path)
 end
end
en:
 pundit:
   default: 'You cannot perform this action.'
   post_policy:
     update?: 'You cannot edit this post!'
     create?: 'You cannot create posts!'

This is an example. Pundit is agnostic as to how you implement your error messaging.

Manually retrieving policies and scopes

Sometimes you want to retrieve a policy for a record outside the controller or view. For example when you delegate permissions from one policy to another.

You can easily retrieve policies and scopes like this:

Pundit.policy!(user, post)
Pundit.policy(user, post)

Pundit.policy_scope!(user, Post)
Pundit.policy_scope(user, Post)

The bang methods will raise an exception if the policy does not exist, whereas those without the bang will return nil.

Customize Pundit user

On occasion, your controller may be unable to access current_user, or the method that should be invoked by Pundit may not be current_user. To address this, you can define a method in your controller named pundit_user.

def pundit_user
  User.find_by_other_means
end

Policy Namespacing

In some cases it might be helpful to have multiple policies that serve different contexts for a resource. A prime example of this is the case where User policies differ from Admin policies. To authorize with a namespaced policy, pass the namespace into the authorize helper in an array:

authorize(post)                   # => will look for a PostPolicy
authorize([:admin, post])         # => will look for an Admin::PostPolicy
authorize([:foo, :bar, post])     # => will look for a Foo::Bar::PostPolicy

policy_scope(Post)                # => will look for a PostPolicy::Scope
policy_scope([:admin, Post])      # => will look for an Admin::PostPolicy::Scope
policy_scope([:foo, :bar, Post])  # => will look for a Foo::Bar::PostPolicy::Scope

If you are using namespaced policies for something like Admin views, it can be useful to override the policy_scope and authorize helpers in your AdminController to automatically apply the namespacing:

class AdminController < ApplicationController
  def policy_scope(scope)
    super([:admin, scope])
  end

  def authorize(record, query = nil)
    super([:admin, record], query)
  end
end

class Admin::PostController < AdminController
  def index
    policy_scope(Post)
  end

  def show
    post = authorize Post.find(params[:id])
  end
end

Additional context

Pundit strongly encourages you to model your application in such a way that the only context you need for authorization is a user object and a domain model that you want to check authorization for. If you find yourself needing more context than that, consider whether you are authorizing the right domain model, maybe another domain model (or a wrapper around multiple domain models) can provide the context you need.

Pundit does not allow you to pass additional arguments to policies for precisely this reason.

However, in very rare cases, you might need to authorize based on more context than just the currently authenticated user. Suppose for example that authorization is dependent on IP address in addition to the authenticated user. In that case, one option is to create a special class which wraps up both user and IP and passes it to the policy.

class UserContext
  attr_reader :user, :ip

  def initialize(user, ip)
    @user = user
    @ip   = ip
  end
end

class ApplicationController
  include Pundit::Authorization

  def pundit_user
    UserContext.new(current_user, request.ip)
  end
end

Strong parameters

In Rails, mass-assignment protection is handled in the controller. With Pundit you can control which attributes a user has access to update via your policies. You can set up a permitted_attributes method in your policy like this:

# app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
  def permitted_attributes
    if user.admin? || user.owner_of?(post)
      [:title, :body, :tag_list]
    else
      [:tag_list]
    end
  end
end

You can now retrieve these attributes from the policy:

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def update
    @post = Post.find(params[:id])
    if @post.update(post_params)
      redirect_to @post
    else
      render :edit
    end
  end

  private

  def post_params
    params.require(:post).permit(policy(@post).permitted_attributes)
  end
end

However, this is a bit cumbersome, so Pundit provides a convenient helper method:

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def update
    @post = Post.find(params[:id])
    if @post.update(permitted_attributes(@post))
      redirect_to @post
    else
      render :edit
    end
  end
end

If you want to permit different attributes based on the current action, you can define a permitted_attributes_for_#{action} method on your policy:

# app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
  def permitted_attributes_for_create
    [:title, :body]
  end

  def permitted_attributes_for_edit
    [:body]
  end
end

If you have defined an action-specific method on your policy for the current action, the permitted_attributes helper will call it instead of calling permitted_attributes on your controller.

If you need to fetch parameters based on namespaces different from the suggested one, override the below method, in your controller, and return an instance of ActionController::Parameters.

def pundit_params_for(record)
  params.require(PolicyFinder.new(record).param_key)
end

For example:

# If you don't want to use require
def pundit_params_for(record)
  params.fetch(PolicyFinder.new(record).param_key, {})
end

# If you are using something like the JSON API spec
def pundit_params_for(_record)
  params.fetch(:data, {}).fetch(:attributes, {})
end

RSpec

Policy Specs

Pundit includes a mini-DSL for writing expressive tests for your policies in RSpec. Require pundit/rspec in your spec_helper.rb:

require "pundit/rspec"

Then put your policy specs in spec/policies, and make them look somewhat like this:

describe PostPolicy do
  subject { described_class }

  permissions :update?, :edit? do
    it "denies access if post is published" do
      expect(subject).not_to permit(User.new(admin: false), Post.new(published: true))
    end

    it "grants access if post is published and user is an admin" do
      expect(subject).to permit(User.new(admin: true), Post.new(published: true))
    end

    it "grants access if post is unpublished" do
      expect(subject).to permit(User.new(admin: false), Post.new(published: false))
    end
  end
end

An alternative approach to Pundit policy specs is scoping them to a user context as outlined in this excellent post and implemented in the third party pundit-matchers gem.

Scope Specs

Pundit does not provide a DSL for testing scopes. Test them like you would a regular Ruby class!

Linting with RuboCop RSpec

When you lint your RSpec spec files with rubocop-rspec, it will fail to properly detect RSpec constructs that Pundit defines, permissions. Make sure to use rubocop-rspec 2.0 or newer and add the following to your .rubocop.yml:

inherit_gem:
  pundit: config/rubocop-rspec.yml

External Resources

Other implementations

License

Licensed under the MIT license, see the separate LICENSE.txt file.

pundit's People

Contributors

bemurphy avatar benkoshy avatar brendanthomas1 avatar burgestrand avatar chrisalley avatar deefour avatar dgmstuart avatar ecbypi avatar envek avatar etiennebarrie avatar iamvery avatar iangreenleaf avatar jiazhen avatar jnicklas avatar johanandre avatar johno avatar justin808 avatar linuus avatar marceloaguimaraes avatar maxcal avatar olleolleolle avatar pcriv avatar qwyng avatar rrrene avatar tagliala avatar thomasklemm avatar timolehto avatar twalpole avatar ucarion avatar yhirano55 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pundit's Issues

[question]Can I call other policy's method?

Hi

for example , I have two models with the has_many relations:

Goods has_many Orders

I want to ensure only the Goods' owner can modify the orders.
I created two policy classes

class GoodsPolicy
   def admin?
     # some approach to judge weather the user is an admin and can modify the goods.
   end
end

class OrderPolicy
    def edit?
      authorize @order.goods, :admin?
    end
end

To use the authorize method in a policy class, I must add this to the OrderPolicy class:

  include Pundit

  def current_user
    @user
  end

My question is that this is an right usage of Pundit? Or there is an more ideal approach?

BR.

A can? helper method

Its sometimes nice to know what a user can do in the view layer to show/hide UI elements for a better user experience. Some of these authorization gems provide a can? method for this purpose. Do you see a feature like this being a good fit with pundit?

An example use case could be something like can :edit?, @article which we could then resolve the policy class based on the passed in model (like you do already).

I would be happy to implement this feature if you think it would be a good fit.

Edit: I see the policy helper method now, which I had overlooked. You can delete this feature request, sorry.

pundit_user not working

Hi, tested with Pundit v. 0.2.1 . My application uses other names besides 'user' for user roles so as per docs I tried pundit_user in my controllers.

Here's a toy example that demonstrates the problem (for me at least):

class ThingysController < ApplicationController
  include Pundit

  def pundit_user
    WeirdlyNamedUser.new
  end

  def index
    @thingy = Thingy.new
    authorize @thingy
  end
end

When I go to /thingys I get

Name Error in ThingysController#index
undefined local variable or method `current_user' for #<ThingysController:0x007ff1f3d56a78>

Authorize related object when using pundit gem

If I have user object and user has one basicinfo. In user show action I have:

def show
  @user = User.find params[:id]
  authorize @user
end

And in show.html.erb I must show user's basicinfo, such as:

User name is: <%= @user.basicinfo.name %>

In this case should I also authorize basicinfo in user show action?

def show
  @user = User.find params[:id]
  authorize @user
  authorize @user.basicinfo, :show?
end

Restrict access to an action without resource?

Hi

I'm trying to move away from CanCan and use Pundit instead but have some questions.

  1. Is it possible to restrict access to actions that doesn't have a resource?
    Example:
    I have a dashboard controller which has no model, it just gathers information from other resources. But I need to pass a record or model to authorize, right?
    So, "authorize ?????"
  2. How does Pundit compare with other solutions, such as Authority?

Undefined Method When Raising NotAuthorizedError

I have a User class, with the following:

class User < ActiveRecord::Base
  validates :name, presence: true
  # ...
  def to_s
    self.name.titleize
  end
end

This makes sense because I will ever have records in my data base without a name, however when authorizing on new and create actions I'm validating a user without a name. The validation work as expected, but when the user is not authorized the error message is as one might expect.

undefined method `titleize' for nil:NilClass

This is because of the following string interpolation.

raise NotAuthorizedError, "not allowed to #{query} this #{record}"

This might want to be considered while looking at other error related issues like #68 and #66.

pundit cant find policy while using namespace

I'm using standard "admin" namespace, yet if i use 'authorize' method in it, pundit still looks for "standard" class.
eg i have admin::userscontroller, and in my policies, directory 'admin' with admin::userpolicy but all the time i get
'unable to find policy UserPolicy' error.

Authorize collection of records

Hello! Thank you for this nice gem.

Is there a way to authorize an array of items? What is convenient way to do that?

I want to do something like in controller

    authorize array_of_records 

because I want to ensure that all records are can be used in current action by current user. And it's not just

   array_of_records.each { |r| authorize r}

There is more logic involved in terms how the items in this array are related to each other.

What I think is may be we can have something like

    def self.create?
      ...
    end

in policies. And if it is not defined it would just go through each records as I've written upper.

It is possible to get if it is array just by class, also may be it can be ActiveRecord or ActiveRecord::Relation.

What do you think?

P.S. Googling leaded to this question on SO, so I guess there is another guy intersted in it

Thanks!

Policy generator does not work with rails 3.0.17

rails 3.0.17
thor 0.14.6
pundit 0.1.0

$ bundle exec rails g pundit:policy workflow_template
      create  app/policies/workflow_template_policy.rb
(erb):1:in `template': undefined method `module_namespacing' for #<Pundit::Generators::PolicyGenerator:0x106ad6108> (NoMethodError)
        from (eval):1:in `template'
        from /Users/trek/dev/some_project/.bundle/gems/pundit-0.1.0/lib/generators/pundit/policy/policy_generator.rb:7:in `create_policy'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/task.rb:22:in `send'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/task.rb:22:in `run'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/invocation.rb:118:in `invoke_task'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/invocation.rb:124:in `invoke_all'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/shell.rb:14:in `map'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/core_ext/ordered_hash.rb:75:in `each'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/invocation.rb:124:in `map'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/invocation.rb:124:in `invoke_all'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/group.rb:226:in `dispatch'
        from /Users/trek/dev/some_project/.bundle/gems/thor-0.14.6/lib/thor/base.rb:389:in `start'
        from /Users/trek/dev/some_project/.bundle/gems/railties-3.0.17/lib/rails/generators.rb:163:in `invoke'
        from /Users/trek/dev/some_project/.bundle/gems/railties-3.0.17/lib/rails/commands/generate.rb:10
        from /Users/trek/dev/some_project/.bundle/gems/polyglot-0.3.1/lib/polyglot.rb:64:in `polyglot_original_require'
        from /Users/trek/dev/some_project/.bundle/gems/polyglot-0.3.1/lib/polyglot.rb:64:in `require'
        from /Users/trek/dev/some_project/.bundle/gems/activesupport-3.0.17/lib/active_support/dependencies.rb:242:in `require'
        from /Users/trek/dev/some_project/.bundle/gems/activesupport-3.0.17/lib/active_support/dependencies.rb:225:in `load_dependency'
        from /Users/trek/dev/some_project/.bundle/gems/activesupport-3.0.17/lib/active_support/dependencies.rb:597:in `new_constants_in'
        from /Users/trek/dev/some_project/.bundle/gems/activesupport-3.0.17/lib/active_support/dependencies.rb:225:in `load_dependency'
        from /Users/trek/dev/some_project/.bundle/gems/activesupport-3.0.17/lib/active_support/dependencies.rb:242:in `require'
        from /Users/trek/dev/some_project/.bundle/gems/railties-3.0.17/lib/rails/commands.rb:17
        from script/rails:6:in `require'
        from script/rails:6

How to test applications

Hi

Do you have any sample applications available or documented how you test the policies and perhaps how you test applications that use Pundit for authorization?

Thanks,
Hakon

How about passing the scope of the current Service/Controller to the policy?

in pundit / lib / pundit.rb now:

def authorize(record, query=nil)
  query ||= params[:action].to_s + "?"
  @_policy_authorized = true
 unless policy(record).public_send(query) #line 58
   raise NotAuthorizedError, "not allowed to #{query} this #{record}"
  end
 true
end

we change the line:58 and respective dependencies to

unless policy(record, self).public_send(query)

Policy for #index?

Sorry, I didn't see another place to ask a question about Pundit...

The generated ApplicationPolicy includes a policy method for #index?

  def index?
    false
  end

I'm curious what the "pundit way" would be to, e.g., show/hide a link to an index action based on the criteria of the current_user?

The pundit helper provided, #policy, requires a model to determine which Policy class to return. It doesn't seem like providing a model object would make sense for the index action though.

I'm just doing MyPolicySubclass.new(current_user,nil).index? currently. Is that "right"?

CHANGELOG

A CHANGELOG would be nice so we know exactly what changes were introduced from one version to another.

Authorizing controller actions with no associated model

Pundit looks great for authorizing models but in some instances I need to authorize controller actions (with no associated model) as well. A simple check whether the user is logged in or not will suffice most of the time. However, sometimes the ability to view a controller action is based on a user role, i.e. user can view settings page if administrator but not if regular user.

What are the best practices for these situations? Any clarifications would be appreciated on how all the authorization pieces fit together.

Run Policy generator on scaffold

When scaffolding a model it would be nice if its corresponding policy was created. Eg, scaffold customer creates a CustomerPolicy at the same time.

Pundit resources

Hello.

I wish to see something similar to

load_and_authorize_resource # CanCan

at pundit. Need I create new gem || push to this?

Policy Inheritiance

Hi I really like what you guys have done here, but would it be possible for you to add an example to the docs to show how to achieve reuse/inheritance of policies and scopes?

For instance in an app with Opportunities, Leads and Tasks they might share common auth logic: They get assigned either to individuals or sales groups on creation and those not assigned cannot perform any actions on them or view them. So for instance the view scope would be (pseudo-code) "where user_ids.includes?(currentuser.id) || assigned_groups.includes? (current_user.groups)" and this would be shared for Opportunities, Leads and Tasks.

Show user only their boxes

So I have a model called Mybox and I only want users to see their own myboxes. Right now it lists all users boxes on index, is there a way to limit that?

# GET /myboxes
# GET /myboxes.json
def index
 if params[:tag]
   @myboxes = Mybox.tagged_with(params[:tag])
 else
   @myboxes = Mybox.all
 end
end

# GET /myboxes/1
# GET /myboxes/1.json
def show
  @mybox = Mybox.find(params[:id])
  authorize(@mybox)
end

Default scope argument for policy_scope

Was wondering if the scope argument for policy_scope couldn't be inferred too?

class PostsController < ApplicationController
  def index
    @posts = policy_scope
  end
end

I have a working patch but, still unsure if it's a good idea or not.

Thanks for the gem! Nice work.

Possible documentation issue?

Hi there,

I really like the look of much of this as a way of breaking out CanCan classes, but I'm a bit concerned by one point in the documentation.

In README.md it says:

Pundit adds a method called verify_authorized to your controllers. 
This method will raise an exception if authorize has not yet been called. 
You should run this method in an after_filter to ensure that you haven't 
forgotten to authorize the action. For example:
class ApplicationController < ActionController::Base
  after_filter :verify_authorized, :except => :index
end

There's a really big issue here for authorisation, which is that the action has been performed already at this point! For example:

class PostsController < ApplicationController
  ...
  def destroy
    @post = Post.find(params[:id])
    @post.destroy
  end
  ...
end

Using the documentation example this will raise an exception, but the post will already have been destroyed by this point, so the exception doesn't really help!

I considered opening a pull request for this, but thought it might be better to discuss before doing anything, as other than "don't", it's a bit difficult to know how to rewrite it.

Any thoughts?

policy pattern question

Hi, this is just a question issue about patterns you like for a certain type of policy.

Given a Company model that has many Messages, say that the policy for message creation on a company only requires you have show access on a company.

I can see two immediate ways to handle this:

  • authorize @company, :show? in the controller at messages#create
  • Make a MessagePolicy that can fire up a CompanyPolicy in its implementation and rely on that

I'm curious how you prefer to handle cases where your permission is based on another resource than the immediate at hand.

Thanks for the library, I've enjoyed reading and trying it out.

Inherited resources + strong_parameters + pundit ugly code

Hello!

In my gem integration inherited_resources + strong_parameters + pundit, I need to write something like this:

  def permitted_params
    params.fetch(:user, {}).permit(*policy(User).permitted_attributes)
  end

But this is ugly. I can't write params.require(:user).permit... because I get exception like ActionController::ParameterMissing: param not found: user in new action.

Maybe, it's better to make a method like

class UsersController < InheritedResources::Base
  permitted_params
end

So, it will assign params for new, edit, create, destroy actions?

New gem for rails 4?

Can you push up a new gem that includes the rails 4 merge? I'm bundling from the github repo but would prefer to point to a stable gem on rubygems. Thanks!

1558490

Generated ApplicationPolicy #index?

I'm confused as to why the default generated index policy looks like this:

def index?
  scope.exists?
end

In the example scope where(:published => true) that would throw an exception on the empty set, which in this case doesn't really mean failed authorization, it might really be empty. Perhaps this is why the verify_authorization is suggesting skipping index, because you just need to rely on the scope finder all the time instead?

verify_authorized can only track authorize usage in controllers

When I include Pundit in a service object I'm able to authorize inside my service object. For instance:

UserCreator  = Struct.new(:params, :current_user) do
  include Pundit
  def create()
      authorize self, :create?
   end
end

This way after_filter :verify_authorized in my controller does not work, because
of @_policy_authorized is an instance variable of the including class.

Maybe it's possible to change it this way:

module Pundit
  class NotAuthorizedError < StandardError; end
  class NotDefinedError < StandardError; end

  extend ActiveSupport::Concern

  class << self

     def policy_authorized?
       !! @policy_authorized
     end

     def policy_authorized=(new_value)
         @policy_authorized=new_value 
     end

     def reset_policy_authorized
         policy_authorized = false
     end
  end 
   ...

  def verify_authorized
     raise NotAuthorizedError unless Pundit.policy_authorized?
  end

  ...

   def authorize(record, query=nil)
     query ||= params[:action].to_s + "?"
     Pundit.policy_authorized= true
     ...
   end

But this require a before filter which calls Pundit.reset_policy_authorized

current_user.can? helpers

After setting up pundit, I found it inconvenient to use the default 'policy' helper in views as I would often be testing for authorizations against different models than the one loaded by the controller. I like the current_user.can_xxx? syntax used in many authorization libraries so I came up with a simple concern to add these helpers to a user model.

It can be cleaned up a bit but is this something that might be accepted into the library if I put together a pull request?

module PunditUser

  extend ActiveSupport::Concern

  def method_missing(meth, *args)
    if meth.to_s =~ /^can_(.+)$/
      Pundit.policy!(self, *args).send(meth.to_s.sub(/^can_/,''))
    else
      super
    end
  end

end

Custom Error Messages (different from #38)

I have read through the open issues, and I wanted to see if there is potential for this functionality. There are some cases in which the policies fail for different reasons.

If I have a User who has had their account suspended, I may want to tell them that they cannot create a new Record because their account is suspended. If their account is not suspended, I may tell them they cannot create a new Record because they have exceeded their limit.

Both of these happen from the same action:

def create
  @record = Record.new
  authorize @record
end

I don't believe passing the third argument of a custom message here (#38) solves the problem. I do, however, believe giving the exception more details and letting the rescue handle it gracefully solves this and #38.

If I could do this (over simplified for example):

rescue_from Pundit::NotAuthorizedError do |exception|
  if exception.query == 'create?' && current_user.limit_reached?(exception.record)
    flash[:error] = 'You have reached your limit, consider upgrading your account.'
  else
    flash[:error] = 'You are not authorized to do that.'
  end
  redirect_to root_path
end

Thoughts? I could work on a feature like this if it was a desire.

Specs fail in ruby 1.8.7

I don't know if 1.8.7 is even supported, if it isn't it would be nice if it could be specified in the gemspec. Don't worry, I'm not using 1.8, I have just taken to making sure specs run lowest possible version if I'm to contribute to a project.

/System/Library/Frameworks/Ruby.framework/Versions/1.8/usr/bin/ruby -S rspec ./spec/pundit_spec.rb --color
.....................F.FFFF....

Failures:

  1) Pundit#verify_authorized does nothing when authorized
     Failure/Error: controller.authorize(post)
     NoMethodError:
       undefined method `public_send' for #<PostPolicy:0x110b575c8>
     # ./lib/pundit.rb:51:in `authorize'
     # ./spec/pundit_spec.rb:188

  2) Pundit#authorize infers the policy name and authorized based on it
     Failure/Error: controller.authorize(post).should be_true
     NoMethodError:
       undefined method `public_send' for #<PostPolicy:0x110b4bde0>
     # ./lib/pundit.rb:51:in `authorize'
     # ./spec/pundit_spec.rb:199

  3) Pundit#authorize can be given a different permission to check
     Failure/Error: controller.authorize(post, :show?).should be_true
     NoMethodError:
       undefined method `public_send' for #<PostPolicy:0x110b466d8>
     # ./lib/pundit.rb:51:in `authorize'
     # ./spec/pundit_spec.rb:203

  4) Pundit#authorize works with anonymous class policies
     Failure/Error: controller.authorize(article_tag, :show?).should be_true
     NoMethodError:
       undefined method `public_send' for #<#<Class:0x110b40468>:0x110b40850>
     # ./lib/pundit.rb:51:in `authorize'
     # ./spec/pundit_spec.rb:208

  5) Pundit#authorize raises an error when the permission check fails
     Failure/Error: expect { controller.authorize(Post.new) }.to raise_error(Pundit::NotAuthorizedError)
       expected Pundit::NotAuthorizedError, got #<NoMethodError: undefined method `public_send' for #<PostPolicy:0x110b3ac48>> with backtrace:
         # ./lib/pundit.rb:51:in `authorize'
         # ./spec/pundit_spec.rb:213
         # ./spec/pundit_spec.rb:213
     # ./spec/pundit_spec.rb:213

Design question

Heyhey,

got a smaller design question. I'm having this structure:

Project.has_many :courses
Course.belongs_to :project

as well as a User can organize some (not all) Pojects. When a user can organize a Project, he's able to create (but not destroy) Courses. So, how would I describe the permission check for creating a Course for a specific Project?

Ideas that come to my mind:

class ProjectPolicy < ApplicationPolicy
  # ...

  def create_course?
    @record.organizers.include?(@user)
  end
end

and check via policy(@project).create_course? in the view.

class CoursePolicy < ApplicationPolicy
  # ...

  def create?
    @record.project.organizers.include?(@user)
  end
end

and check via policy(Course.new(project: @project)).create?. As a side note, I can't use @project.courses.build here because I iterate over @project.courses and don't want unsaved records. That's why I use Course.new(...) here.

I like the latter more, but I ponder about instantiating just another Course object for authorization.. Well, any ideas for this rather not that important design question? :) Maybe other ideas than the ones I had?

Rspec controller tests

Hi.
I'm using pundit(0.2.1) with rspec-rails(~2.14) in my rails 4 projects

It's great to use it with policy and view specs. But I confuse with controller and feature(capybara 2) types

When running tests I got errors:
undefined method 'authorize' for #<ArticlesController:0xb9b39fc>
# ./app/controllers/articles_controller.rb:6:in 'show'
# ./spec/features/authentication_spec.rb:6:in 'block (3 levels) in <top (required)>'
The same thing with my capybara feature.

But it works in development mode.

I found interesting hook that fixes controller group problem only. But I don't like it

# spec_helper.rb
config.before do
  if defined?(controller)
    controller.extend Pundit
  end
end

Thanks for any help and ideas

Testing pundit policies

Hey there,

thanks for this great gem!

While trying to spec the policies I came across the RSpec matchers provided by the gem, but could not entirely figure out how to make things work. Could you maybe give a short example in the Readme or Wiki?

I'd like to share my own solution. Maybe you could open the Wiki so that people can document best practices for everyone to get to speed quickly.

A sample test for the AccountPolicy class.

# spec/policies/account_policy_spec.rb
require 'spec_helper'

describe AccountPolicy do
  let(:account) { Fabricate(:account) }
  let(:admin)   { Fabricate(:user) }
  let(:member)  { Fabricate(:user) }
  subject       { AccountPolicy }

  context 'admin' do
    before do
      Fabricate(:membership, user: admin, account: account, admin: true)
    end

    it { should permit(admin, account, :index?) }
    it { should permit(admin, account, :show?) }
    it { should permit(admin, account, :create?) }
    it { should permit(admin, account, :new?) }
    it { should permit(admin, account, :update?) }
    it { should permit(admin, account, :edit?) }
    it { should permit(admin, account, :destroy?) }
  end

  context 'member' do
    before do
      Fabricate(:membership, user: member, account: account, admin: false)
    end

    it { should permit(member, account, :index?) }
    it { should permit(member, account, :show?) }
    it { should permit(member, account, :create?) }
    it { should permit(member, account, :new?) }
    it { should_not permit(member, account, :update?) }
    it { should_not permit(member, account, :edit?) }
    it { should_not permit(member, account, :destroy?) }
  end
end

Defining the permit matcher.

# spec/support/matchers/policy_matcher.rb
RSpec::Matchers.define :permit do |user, record, action|
  match do |policy|
    policy.new(user, record).public_send(action)
  end

  failure_message_for_should do |policy|
    "Expected #{ policy.to_s } to permit #{ action.to_s } on #{ record.to_s } but it didn't."
  end

  failure_message_for_should_not do |policy|
    "Expected #{ policy.to_s } to forbid #{ action.to_s } on #{ record.to_s } but it didn't."
  end
end

And enabling the loading of custom matchers and more in the spec_helper.rb.

# spec/spec_helper.rb

# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
Dir[Rails.root.join("spec/support/**/*.rb")].each {|f| require f}

RSpec.configure do |config|
  # ...
end

Hopefully this is of use for people looking to test their policies.

Thanks again!

Best, Thomas

Best practices for authorizing a collection action?

This is really just a question of aesthetics, but I'm convinced I'm not using Pundit effectively here. I'm having trouble explaining this clearly, but hopefully I'll get my message across:

I'd like to be able to authorize whether or not a user can access #index on a model. In my particular case, let's say I have Essays and Topics -- a topic has_many essays. If you created a topic, you can see what essays others have written on that topic (this would be the EssaysController#index action). I want to have an access-denied exception if a user tries to see what essays have been written about a subject she did not create.

I've implemented this by doing:

class EssaysController
  def index
    @topic = Topic.find(params[:topic_id])
    authorize @topic, :list_essays?

    @essays = @topic.essays
  end
end

class TopicPolicy
  def list_essays?
    user == topic.creator
  end
end

What I don't like about this is that I'm calling #authorize in my essay controller, but it's going to talk to the topic policy. Is there a cleaner way of doing this?

Edit: Another unsavory aspect to this method is that it doesn't work well if I call verify_policy_scoped after index actions; my implementation doesn't necessarily need to call policy_scoped.

I am totally conscious of the fact that this is a relatively benign issue, but I'd rather use my tools in the best possible way to produce easy-to-follow code.

policy on user object actions

Rails 3.2.13
ruby 1.9.3p327 (2012-11-10) [i386-mingw32]

It is baffling me a lot. Works in debugger but not at run time.

Here is my situation. High level users (director, admin etc.) can edit other users.

class UserPolicy < Struct.new(:user, :otheruser)
    def edit?
        allow = user.director? or user == otheruser
        debugger
        allow =  (user.admin? and (not otheruser.director?) and (not otheruser.admin?)) unless allow
    end
end

in controller:

def edit
   @user = User.find(params[:id])   
   authorize @user 
end

Debugger:

when it breaks, allow is set to false which is incorrect. by executing the previous line again it gets set to true. Not able to figure out what is going on here. What am I missing?

in lines from debugger console:

9 end
10
11 def edit?
12 allow = user.director? or user == otheruser
13 debugger
=> 14 allow = (user.admin? and (not otheruser.director?) and (not otheruser.admin?)) unless allow
15 end
16
17 def update?
18 edit?
(rdb:1) allow
false
(rdb:1) user == otheruser
true
(rdb:1) allow = user.director? or user == otheruser
true
(rdb:1)

Guest users (no current_user)

What's the recommended way to scope collections on a controller when a user isn't logged in, and a current_user isn't available?

As in a public listing available to non-registered users, and a private one for logged-in ones.

Define Default query

I currently am working on refactoring some code and noticed on my policies, I had mostly repeated code (method calls) within the policy check methods. I.E. within something like

def index?
my_authorize_method
end

I dug into the pundit code and found the method that I would be interested in changing.

def authorize(record, query=nil)
query ||= params[:action].to_s + "?"
@_policy_authorized = true
unless policy(record).public_send(query)
raise NotAuthorizedError, "not allowed to #{query} this #{record}"
end
true
end

I would like to make it so that the default for query isn't set permanently to nil, but can optionally be specified by the policy class, much like it is possible in models to specify the class to use as the policy class. In other words, within, defining your policy you could do something like

class PostPolicy < Struct...
default_authorizer :my_default
def my_default
#authorize here
end
end

DoubleRenderError in rails 4

Ive read through #52, #53, and #95. Im still unclear what the fix is to get past a DoubleRenderError caused by the redirect_to associated with Pundit::NotAuthorizedError. Am I correct to infer from reading the other issues that its ultimately a missing authorize call? Ive double checked my app and each action is covered by an authorize call and a policy...and my application controller containers after_action calls for verify_authorized and verify_policy_scoped. Is jnicklas suggesting in issue #53 that we should be using a before_action not after_action for that? I hate to clog up the issue tracker, but I can't get past this double render error.

Abandoned?

I noticed there hasn't been any commits in a couple of months.
Has this been abandoned?

best way to authorize noncrud actions with pundit?

# policy
class ContactPolicy
  attr_reader :user, :contact

  def initialize(user, contact)
    @user = user
    @contact = contact
  end

  def number?
    true
  end

# controller

    class ContactsController < ApplicationController

      before_filter :load_object, :only => [:show, :edit, :update, :destroy]

      def number
        num = {number: Contacts.count}
        authorize num  # would look for the HashPolicy not in ContactPolicy
        render json: num
      end

should i just do ?

authorize Contact

Namespaced policies

The app I'm working on has two sections: user and admin. There are multiple types of users and multiple types of admins, and different authentication solutions are used for each of them.

Although all the application models are used by both admins and users, policies are very different. Handling both users and admins and all distinct types within single policy was not so clear and full of ifs.

The way I handled this was to dynamically define policy_class on every ActiveRecord descendant in before filter. Something like this:

def set_policy_namespace
  m = self.class.name.split("::").first
  active_record_descendants.each do |ar|
    ar.class.instance_eval do
      define_method(:policy_class) do
        "::Policies::#{m}::#{self.name}Policy"
      end
    end
  end
end

def active_record_descendants
  Rails.application.eager_load! unless Rails.application.config.cache_classes
  ActiveRecord::Base.descendants
end

So, if I'm in Admin::HomeController, Project model will have policy_class redefined to return ::Policies::Admin::ProjectPolicy.

I've tried to demonstrate valid use case for this. Do you have any thoughts on how can this be made easier? I'm not sure whether or not it should be a part of gem (since it is somewhat rare).. I'm just asking for opinion.

thanks

Hook into Rails ExceptionWrapper?

I've been playing around with this today. I'm finding it being a really nice way to handle authorization exceptions in line with rails.

module ActionDispatch
  class ExceptionWrapper
    @@rescue_responses.merge!('Pundit::NotAuthorizedError' => :forbidden)
  end
end

I'm not sure this belongs in the gem, but I do feel like this should be less hacky. Maybe more of a Rails change.

DoubleRenderError using after_filters

Hi Pundit Team, I know that this gem is technically not tied to Ruby on Rails, but I have a Ruby on Rails specific issue and am looking for some advice. When I use the after_filters provided by this gem, instead of neatly handling the issue as expected with the code provided in the README, I receive a DoubleRenderError.

Failures:

  1. CompaniesController GET 'index' returns http success
    Failure/Error: get :index
    AbstractController::DoubleRenderError:
    Render and/or redirect were called multiple times in this action. Please note that you may only call render OR redirect, and at most once per action. Also note that neither redirect nor render terminate execution of the action, so if you want to exit an action after redirecting, you need to do something like "redirect_to(...) and return".

    ./app/controllers/application_controller.rb:8:in `block in class:ApplicationController'

This is application controller, line 8 is the redirect_to line below:

class ApplicationController < ActionController::Base
  include Pundit

  protect_from_forgery with: :exception

  rescue_from Pundit::NotAuthorizedError do |exception|
    redirect_to root_url, alert: exception.message, status: :forbidden #HTTP 403
  end

  def logged_in_user
    @logged_in_user ||= current_admin || current_user
  end
  helper_method :logged_in_user

  #pundit gem @OVERRIDE
  def pundit_user
    logged_in_user
  end

  def infer_class_from_controller_name
    self.controller_name.singularize.camelize.constantize
  end

end

My controller is very simple:

class BaseController < ApplicationController

  after_filter :verify_authorized, :except => [:index, :home]
  after_filter :verify_policy_scoped, :only => :index

  def index
    @resources = infer_class_from_controller_name.scoped
    #@resources = policy_scope(infer_class_from_controller_name) #does not cause the issue
    @resources = @resources.page(params[:page])
  end

  def show
    @klass = infer_class_from_controller_name
    @resource = @klass.find(params[:id])
    authorize @resource
  end

end

class CompaniesController < BaseController
  #just an empty controller that inherits all behavior from BaseController above
end

It seems that this after_filter doesn't work properly when included in an ActionController instance. Any thoughts? Me personally, I propose that the README be updated to not mention the two after_filters, and instead have the policy_scope and authorize methods raise Pundit::NotAuthorizedError directly inside of the controller methods. In the Rails controller action, if we raise the exception inside of the controller method, we would avoid the DoubleRenderError shown above.

I'll create a new pull request and link this issue so I can demonstrate what I'm referring to above with code.

Thanks for listening!

Release new version to RubyGems

The last version currently published on RubyGems is from January 2013.
-> so pretty old

Lots of improvements are already in the master branch.
Could you please do a release, if the current state of master is releaseable.
Or are there any blocking issues which would need attention before that?

Thanks.

before_action instead of after_action for :verify_authorized?

Hey! I was looking for an alternative to cancan and stumbled on pundit and I'd say it looks very nice. I saw this in the README, though:

Ensuring policies are used

Pundit adds a method called verify_authorized to your controllers. This
method will raise an exception if authorize has not yet been called. You
should run this method in an after_action to ensure that you haven't
forgotten to authorize the action. For example:

class ApplicationController < ActionController::Base
  after_action :verify_authorized, :except => :index
end

This seems to suggest that authorization checks should only be run after the action. As far as I know (I might be wrong, though), this means that the action would run entirely before the exception is raised, which in turn would mean the changes the user is trying to make would take place, even though they just wouldn't see the results in the server's response.

Wouldn't this give a false sense of security and potentially constitute a security issue?

Wouldn't it be correct to use before_action instead?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.