Support for Draper #624

Open
sirn opened this Issue May 17, 2012 · 8 comments

5 participants

@sirn

CanCan 2.0 currently doesn't correctly works with Draper, since Draper wraps over the model object, its class name become that of Draper's class name. So CanCan will fail to authorize any object wrapped by Draper's decorators:

can :create, :contents            # not work, draper class name is ContentDecorator
can :create, :content_decorators  # works, but not very obvious

This used to works fine in CanCan 1.x. I'm not sure if I should file this bug to Draper or here, or both, but it would be nice if there's any way to make CanCan generates subject name from something else than class name.

My current workaround is to access model object from Draper decorator in can?, but I think it's repetitive.

can? :create, @content        # not work, @content is ContentDecorator
can? :create, @content.model  # works, but repetitive
@rmcastil
Collaborator

@sirn Any way you can provide a use case for this?

@sirn

Hmm, I'm not sure where to start about test case since from CanCan's side it's working properly by resolving subject name from class name (the subject.class.to_s.underscore.pluralize.to_sym if I look at the right place) so this is more like a feature request for specifying a custom subject name than a bug report...

@sirn

Sorry, I misread. (Oops)

I use Draper for data filtering and for presentation (e.g. I can just call content.created_at via Draper instead of content.created_at.strftime(...)). They're passed to controller like normal model objects.

def show
  @content = ContentDecorator.decorate(Content.find(params[:id])
end
<% if can? :create, @content %>
  <li><a href="..">Create content</a></li>
<% end %>
@rmcastil
Collaborator

Aren't you really looking for a way to specify a wrapper for the object you're trying to authorize?

class ContentsController < ApplicationController
  load_and_authorize_resource wrapper: :content_decorator
  ....
end
@sirn

No, I'm not. There's no problem calling the wrapper, I just want a way to specify custom subject, so I could skip calling .model for every can? calls to decorator object. For example, I wish I could do this:

class ContentDecorator < Draper::Base
  authorize_as :contents
  ...
end

...and have CanCan 2.0 resolve a subject name for ContentDecorator as :contents instead of :content_decorators.

@softpro

I haven't checked it yet, but could the usage of model_name (something like subject.model_name.collection.to_sym instead of subject.class.to_s.underscore.pluralize.to_sym) help?

@myitcv

I've just stumbled across exactly the same issue. It feels to me like the decoration of an object needs to happen immediately prior to the render call (or equivalent) - hence I'm not sure CanCan is the right place to solve this problem...

Indeed how about this. Assuming you have a User model:

class UsersController < ApplicationController
  load_and_authorize_resource

  def render(options = nil, extra_options = {}, &block)
    @users.map! { |u| u.decorate } unless @users.nil?
    @user = @user.decorate unless @user.nil?
    super(options, extra_options, &block)
  end

  # .....

In my views I then get the decorated objects whilst my controller code remains untouched.

But a more elegant solution not requiring the render override would be better

Thoughts?

@xhoy

Dear submitter, Since cancan/raynB hasn't been active for more than 6 months and no body else then ryam himself has commit permissions the cancan project is on a stand still.
Since cancan has several issues including missing support for rails 4 cancan is moving forward to cancancan. More details on: #994

If your feel that your pull request or bug is still applicable (and hasn't been merged in to cancan) it would be really appreciated if you would resubmit it to cancancan (https://github.com/cancancommunity/cancancan)

We hope to see you on the other side!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment