Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove cancancan customizations #3148

Closed

Conversation

coorasse
Copy link
Contributor

Description
While testing solidus against cancancan 3.0 I noticed that the usage was "not correct (Euphemismus)".
This PR aims to remove the customizations introduced to cancancan, which are not necessary.
The current customizations are not compatible with version 3.0.0 of cancancan since Solidus makes use of merge of Abilities. The 3.0.0 has a breaking change which changes how aliased_actions are merged.

I removed all custom aliases and replaced display with read. Also, I corrected the rule which would have caused issues during the migration.

This is probably a breaking change, because it will cause problems for the plugins.
Plugins should now use standard cancancan actions and replace display with read.

Checklist:

  • I have followed Pull Request guidelines
  • I have added a detailed description into each commit message
  • I have updated Guides and README accordingly to this change (if needed)
  • I have added tests to cover this change (if needed)

core/spec/models/spree/ability_spec.rb Outdated Show resolved Hide resolved
core/spec/models/spree/ability_spec.rb Outdated Show resolved Hide resolved
@@ -133,13 +133,13 @@ def find_product(id)

def product_scope
if can?(:admin, Spree::Product)
scope = Spree::Product.with_deleted.accessible_by(current_ability, :read).includes(*product_includes)
scope = Spree::Product.with_deleted.accessible_by(current_ability).includes(*product_includes)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is not necessary anymore. The default is :index which is by default aliased by :read.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @coorasse! But if :read alias was :show shouldn't it be changed like this scope = Spree::Product.with_deleted.accessible_by(current_ability, :show).includes(*product_includes) to keep same logic? Isn't your change changing scope from show to index now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it changes from :show to :index but all the rules are defined for :read instead of :display which was including also :read. it's quite complicated, I know, I don't know why all these aliases were generated before. accessible_by(ability, :show) would not make sense because you want a list of objects. :show is for single instances.

Copy link

@jkojro jkojro Mar 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(current_ability, :read) made scope of products that user is authorized for action :show I gues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:read was aliased by :display and rules were (almost) always defined on :display. You can see that most of the changes are about that: https://github.com/solidusio/solidus/pull/3148/files#diff-82b30f937458e7c1052c326354dc18cbL8

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that :index is the right thing here, as :show would need to check every single instance of a Product if its able to be shown to the user, what is definitely not what we want here.

@@ -49,8 +49,9 @@ def empty
render plain: nil, status: 204
end

# TODO: this action is never accessible. shall we simply remove it?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this method was never accessible. why don't we remove it?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coorasse Could you explain why is it unaccessible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it was defined with :index and since :read was an alias of :show, no rule was defined for :index. in fact, I replaced it with a random action called :impossible_action and no test failed. There is only one test and it checks that this endpoint should not be accessible 🤷‍♂️ . That's why I asked myself: "why don't we remove it?"

Copy link

@jkojro jkojro Mar 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coorasse As I've tested, :manage gives acces to all rules, also theese not defined, so a user with can :manage, Order will go through authorize! :impossible_action, Order too. And am I missing somethin or :index was defined in display: alias_action :index, :read, to: :display

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh right! manage authorizes you! I forgot that 🤦‍♂️ . To do it properly here we should leave authorize! :index, Order but then this test will fail. So I'd say we could use authorize! :admin, Order and keep the current behaviour.

def alias_actions
clear_aliased_actions

# override cancan default aliasing (we don't want to differentiate between read and index)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is supported already. you can use read.

clear_aliased_actions

# override cancan default aliasing (we don't want to differentiate between read and index)
alias_action :delete, to: :destroy
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

delete was never used

alias_action :delete, to: :destroy
alias_action :edit, to: :update
alias_action :new, to: :create
alias_action :new_action, to: :create
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

new_action was never used

can :create, Order
can [:read, :update], Order do |order, token|
can [:show, :edit, :update], Order do |order, token|
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

block conditions should be defined only for actions on object instances, not classes, therefore this rule applies only on :show, :edit, :update. This was actually working by mistake since version 2.0 of cacancan

@@ -254,7 +256,7 @@ def initialize(_user)
context 'requested by same user' do
let(:resource) { user }
it_should_behave_like 'access granted'
it_should_behave_like 'no index allowed'
it_should_behave_like 'index allowed'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why should it not be allowed?

@kennyadsl
Copy link
Member

@coorasse wow, thank you, I love this change! Do you think there's a way to deprecate the old usage any way before removing it?

@coorasse coorasse force-pushed the remove_cancancan_customizations branch from 269e210 to 00c266c Compare March 18, 2019 08:26
@coorasse
Copy link
Contributor Author

I cannot really think of a deprecation warning: we could override can? and accessible_by methods of cancancan and raise a warning when can? is called with delete, new_action, read or display and when accessible_by is called with :read or :display.

The calls to accessible_by(ability, :read) should be replaced by accessible_by(ability) but this would not work before this update! ⚠️

Also can? :read, resource should be changed to the specific action can? :show or can? :edit, etc, but again: it would not work before this change.

The calls to can? :delete, resource could already be replaced by can? :destroy, resource.

Also the calls to can? :new_action, resource could already be replaced by can? :create, resource.

The main problem was this alias:

alias_action :show, to: :read
alias_action :index, :read, to: :display

which caused read to be the same of show and display to be both read and index...
I am not even sure what this means 😄. If you notice, in fact, the changes I had to do in the code itself were not actually many. It is more a renaming issue. I can make a new comment and show in detail how/why the problem is raised only in version 3.0.0.

I let you guys decide about how to move here: I have not enough knowledge about the project.
I pointed the finger 😄 and I can provide all help you need but I think this might break quite some stuff.

@coorasse
Copy link
Contributor Author

In cancancan 3.0.0 when two abilities are merged, also the aliased_actions are merged.
Solidus defines the following aliases in base ability:

{
:destroy=>[:delete], 
:update=>[:edit], 
:create=>[:new, :new_action], 
:read=>[:show], 
:display=>[:index, :read]
}

base ability is the merged with other abilities where the default aliases are defined. The following:

{
  :read => [:index, :show],
  :create => [:new],
  :update => [:edit]
}

with the following aliases as a result:

{
:destroy=>[:delete], 
:update=>[:edit], 
:create=>[:new], 
:read=>[:index, :show], 
:display=>[:index, :read]
}

The call that Solidus performs on Spree::Order.accessible_by(ability, :read) in version 3.0.0 fails because the following rule:

can [:read, :update], Order do |order, token|
  order.user == user || (order.guest_token.present? && token == order.guest_token)
end

is now identified as possible interesting rule and cancancan raises an issue because this is a block rule (do...end) defined on a collection action read

@coorasse coorasse force-pushed the remove_cancancan_customizations branch from 00c266c to 5b3f8bd Compare March 23, 2019 08:20
This was referenced Apr 12, 2019
@@ -50,7 +50,7 @@ def empty
end

def index
authorize! :index, Order
authorize! :admin, Order
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this change?

@aldesantis aldesantis added this to the 2.11 milestone May 22, 2020
@kennyadsl kennyadsl removed this from the 2.11 milestone Aug 28, 2020
@kennyadsl
Copy link
Member

Closing in favor of #3701.

@kennyadsl kennyadsl closed this Aug 28, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants