cancannible 0.0.2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- YWE0OWZkMjhlMWQ3ODMzNTVmZWNiMTk2ZWM5YmU2YjMyY2I1NTAwMA==
5
- data.tar.gz: !binary |-
6
- YjQ0NDZhNzQ5MzdhMDJiMDQ4NzRjMjI1MDE5ZGY1N2ViZjU2NThlMA==
2
+ SHA256:
3
+ metadata.gz: 8ba63fd7b6b80a32a3bc93fbbe43845439c1eaffa9661e35510dbeff487af673
4
+ data.tar.gz: fdf8f225705b0e0fa9ea469674d62ce22b5340f48cb23fb94a2b8501112417cf
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- Zjc2OGYzMGI1ODA5ZmY4ZmQ3ZGRhNTU5MDM2MmRiOWJmNDNmNzI4MzZjYTY0
10
- ZDNiNDM3ODVmZTExYzM5NDQ1ZmQyNDZmZjc0NDFiYWIxZTM2YjcwMTdiMGU0
11
- YTliZGI0YjFhNDdjY2RmZWNhZjNhY2YyNDU5YTQ3MDQ3NDRhNjY=
12
- data.tar.gz: !binary |-
13
- MjFhMzBmNzQ5YTcyMzBmOTViMTYwMjEwNDI2YjllNjUxZjEzYjkxNmZjOTVi
14
- YmVkOWZjMWUyODBiMDQ3MmY4YWExMDJiNmUzZTkzZTBlY2MwZWFjMzFmOWM0
15
- MjNiMTBmMGFjNGI3OTllNTkxMjM3NTBmZDViOWYwNmVlZGMwZWE=
6
+ metadata.gz: f9068c6dce19852c747512ddafa0a29461586128d67408bc5c53f07e029e8273d0cb343acb4400dcfd180afd6596202837fac699838f62d6e252a56dd35f99df
7
+ data.tar.gz: e5ec5d5accb0e40139dbeee9b6bc211d3652688c7ffb17c1788c86cea455c626914b233d4eb52de2786993989df8018d38ddfb07bef5bedb2f04484d43f62054
@@ -0,0 +1,34 @@
1
+ # This workflow uses actions that are not certified by GitHub.
2
+ # They are provided by a third-party and are governed by
3
+ # separate terms of service, privacy policy, and support
4
+ # documentation.
5
+ # This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
6
+ # For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
7
+
8
+ name: Ruby
9
+
10
+ on:
11
+ push:
12
+ branches: [ '*' ]
13
+ pull_request:
14
+ branches: [ main ]
15
+
16
+ jobs:
17
+ test:
18
+
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ matrix:
22
+ ruby-version: ['2.7', '3.0']
23
+
24
+ steps:
25
+ - uses: actions/checkout@v2
26
+ - name: Set up Ruby
27
+ uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
28
+ with:
29
+ ruby-version: ${{ matrix.ruby-version }}
30
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
31
+ - name: Install dependencies
32
+ run: bundle install
33
+ - name: Run tests
34
+ run: bundle exec rake
data/Gemfile CHANGED
@@ -1,8 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- # currently testing on the 3.2 branch of rails
4
- # gem "activemodel", '~> 3.2'
5
- # gem "activerecord", '~> 3.2'
6
-
7
3
  # Specify your gem's dependencies in cancannible.gemspec
8
4
  gemspec
data/Guardfile CHANGED
@@ -1,18 +1,8 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
- # Note: The cmd option is now required due to the increasing number of ways
5
- # rspec may be run, below are examples of the most common uses.
6
- # * bundler: 'bundle exec rspec'
7
- # * bundler binstubs: 'bin/rspec'
8
- # * spring: 'bin/rsspec' (This will use spring if running and you have
9
- # installed the spring binstubs per the docs)
10
- # * zeus: 'zeus rspec' (requires the server to be started separetly)
11
- # * 'just' rspec: 'rspec'
12
- guard :rspec, cmd: 'bundle exec rspec' do
4
+ guard :rspec, cmd: 'bundle exec rspec', all_on_start: false, all_after_pass: false do
13
5
  watch(%r{^spec/.+_spec\.rb$})
14
- watch(%r{^lib/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
6
+ watch(%r{^lib/cancannible/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
15
7
  watch('spec/spec_helper.rb') { "spec" }
16
-
17
8
  end
18
-
data/README.md CHANGED
@@ -1,22 +1,28 @@
1
1
  # Cancannible
2
- [![Build Status](https://travis-ci.org/evendis/cancannible.svg?branch=master)](https://travis-ci.org/evendis/cancannible)
3
2
 
4
- Cancannible is a gem that extends CanCan with a range of capabilities:
3
+ Cancannible is a gem that extends [CanCanCan](https://github.com/CanCanCommunity/cancancan) with a range of capabilities:
4
+
5
5
  * database-persisted permissions
6
6
  * export CanCan methods to the model layer (so that permissions can be applied in model methods, and easily set in a test case)
7
7
  * permissions inheritance (so that, for example, a User can inherit permissions from Roles and/or Groups)
8
8
  * caching of abilities (so that they don't need to be recalculated on each web request)
9
9
  * general-purpose access refinements (so that, for example, CanCan will automatically enforce multi-tenant or other security restrictions)
10
+ * battle-tested with Rails 3.2.x and 4.2.x
11
+
12
+ Two demo applications are available (with source) that show cancannible in action:
13
+
14
+ * [cancannibledemo.evendis.com](http://cancannibledemo.evendis.com) uses Rails 3.2.x
15
+ * [cancannibledemo4.evendis.com](http://cancannibledemo4.evendis.com) uses Rails 4.2.x
10
16
 
11
17
  ## Limitations
12
- Cancannible's origin was in a web application that's been in production for over 3 years.
18
+
19
+ Cancannible's origin was in a web application that's been in production for over 4 years.
13
20
  This gem is an initial refactoring as a separate component. It continues to be used in production, but
14
21
  there are some limitations and constraints that will ideally be removed or changed over time:
15
22
 
16
23
  * It only supports ActiveRecord for permissions storage (specifically, it has been tested with PostgreSQL and SQLite)
17
24
  * It currently assumes permissions are stored in a Permission model with a specific structure
18
- * It works with the [CanCan](https://github.com/ryanb/cancan) gem. It has not yet been tested with the new [CanCanCan](https://github.com/CanCanCommunity/cancancan) gem.
19
- * It assumes and is only tested with Rails 3.2. Not yet with Rails 4.
25
+ * It works with the [CanCanCan](https://github.com/CanCanCommunity/cancancan) gem.
20
26
  * It assumes your CanCan rules are setup with the default `Ability` class
21
27
 
22
28
 
@@ -120,6 +126,23 @@ For example, this is a simple scheme using Redis:
120
126
  end
121
127
 
122
128
 
129
+ ## Testing the gem
130
+
131
+ The RSpec test suite runs as the default rake task:
132
+
133
+ rake
134
+ # same as:
135
+ rake spec
136
+
137
+ For convenience, guard is included in the development gem environment, so you can start automatic testing-on-change:
138
+
139
+ bundle exec guard
140
+
141
+ [Appraisal](https://github.com/thoughtbot/appraisal) is also included to run tests across Rails 3 and 4 environments:
142
+
143
+ appraisal rake spec
144
+
145
+
123
146
  ## Contributing
124
147
 
125
148
  1. Fork it ( https://github.com/evendis/cancannible/fork )
data/cancannible.gemspec CHANGED
@@ -18,14 +18,17 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_runtime_dependency "activesupport", "~> 3.2"
22
- spec.add_runtime_dependency "activemodel", "~> 3.2"
23
- spec.add_runtime_dependency "cancan", "~> 1.6"
21
+ spec.add_runtime_dependency "activesupport", "~> 6.1"
22
+ spec.add_runtime_dependency "activemodel", "~> 6.1"
23
+ spec.add_runtime_dependency "cancancan"
24
24
 
25
- spec.add_development_dependency "activerecord", "~> 3.2"
26
- spec.add_development_dependency "sqlite3", "~> 1.3"
27
- spec.add_development_dependency "bundler", "~> 1.6"
28
- spec.add_development_dependency "rake", "~> 10.0"
29
- spec.add_development_dependency "rspec", "~> 3.0"
30
- spec.add_development_dependency "guard-rspec", "~> 4.0"
25
+ spec.add_development_dependency "activerecord", "~> 6.1"
26
+ spec.add_development_dependency "sqlite3", ">= 1.3.2"
27
+
28
+ spec.add_development_dependency "bundler"
29
+ spec.add_development_dependency "rake"
30
+ spec.add_development_dependency "rdoc"
31
+ spec.add_development_dependency "rspec"
32
+ spec.add_development_dependency "guard-rspec"
33
+ spec.add_development_dependency "rb-fsevent"
31
34
  end
@@ -1,5 +1,4 @@
1
1
  module Cancannible
2
-
3
2
  mattr_accessor :refinements
4
3
  mattr_accessor :get_cached_abilities
5
4
  mattr_accessor :store_cached_abilities
@@ -24,5 +23,4 @@ module Cancannible
24
23
  self.refinements[stage] ||= []
25
24
  self.refinements[stage] << refinement
26
25
  end
27
-
28
- end
26
+ end
@@ -23,34 +23,25 @@ module Cancannible::Grantee
23
23
  resource_id = resource.try(:id)
24
24
  end
25
25
 
26
- permission = find_by_asserted_and_ability_and_resource_id_and_resource_type(
27
- asserted, ability, resource_id, resource_type)
28
- unless permission
29
- permission = find_or_initialize_by_asserted_and_ability_and_resource_id_and_resource_type(
30
- !asserted, ability, resource_id, resource_type)
31
- permission.asserted = asserted
32
- permission.save!
33
- end
26
+ # This looks ugly, but it avoid version-specific issues with find_by*/find_or_initialize_by* methods
27
+ permission = where(asserted: asserted, ability: ability, resource_id: resource_id, resource_type: resource_type).first
28
+ permission ||= where(asserted: !asserted, ability: ability, resource_id: resource_id, resource_type: resource_type).first
29
+ permission ||= new(asserted: asserted, ability: ability, resource_id: resource_id, resource_type: resource_type)
30
+ permission.asserted = asserted
31
+ permission.save!
32
+
33
+ proxy_association.owner.instance_variable_set :@abilities, nil # invalidate the owner's ability collection
34
34
 
35
- # if Rails.version =~ /3\.0/ # the rails 3.0 way
36
- # proxy_owner.instance_variable_set :@permissions, nil # invalidate the owner's permissions collection
37
- # proxy_owner.instance_variable_set :@abilities, nil # invalidate the owner's ability collection
38
- # else
39
- proxy_association.owner.instance_variable_set :@abilities, nil # invalidate the owner's ability collection
40
- # end
41
35
  permission
42
36
  end
43
37
  end
44
-
45
38
  end
46
39
 
47
40
  module ClassMethods
48
-
49
41
  # Command: configures the set of associations (array of symbols) from which permissions should be inherited
50
42
  def inherit_permissions_from(*relations)
51
43
  self.inheritable_permissions = relations
52
44
  end
53
-
54
45
  end
55
46
 
56
47
  # Returns the Ability set for the owner.
@@ -59,7 +50,13 @@ module Cancannible::Grantee
59
50
  @abilities = if refresh
60
51
  nil
61
52
  elsif Cancannible.get_cached_abilities.respond_to?(:call)
62
- Cancannible.get_cached_abilities.call(self)
53
+ result = Cancannible.get_cached_abilities.call(self)
54
+ if result
55
+ # performs a crude compatibility check
56
+ rules_size = result.send(:rules).size rescue nil
57
+ rules_index_size = (result.instance_variable_get(:@rules_index) || []).size
58
+ result if !rules_size.nil? && rules_index_size == rules_size
59
+ end
63
60
  end
64
61
  return @abilities if @abilities
65
62
 
@@ -70,7 +67,7 @@ module Cancannible::Grantee
70
67
  ability_class.new(self)
71
68
  end
72
69
 
73
- Cancannible.store_cached_abilities.call(self,@abilities) if Cancannible.store_cached_abilities.respond_to?(:call)
70
+ Cancannible.store_cached_abilities.call(self, @abilities) if Cancannible.store_cached_abilities.respond_to?(:call)
74
71
  @abilities
75
72
  end
76
73
 
@@ -104,16 +101,18 @@ module Cancannible::Grantee
104
101
  def cannot(ability, resource)
105
102
  permissions << [ability, resource, false]
106
103
  end
107
-
108
104
  end
109
105
 
110
-
111
106
  module Cancannible
112
107
  # This module is automatically included into all controllers.
113
108
  # It overrides some CanCan ControllerAdditions
114
109
  module ControllerAdditions
110
+ # Returns abilities cached in the current_user model.
111
+ # If that fails, returns a default Ability instance
115
112
  def current_ability
116
- current_user.try(:abilities)
113
+ current_user.try(:abilities) || if ability_class = ('::Ability'.constantize rescue nil)
114
+ ability_class.new(current_user)
115
+ end
117
116
  end
118
117
  end
119
118
  end
@@ -2,14 +2,11 @@ module Cancannible::PreloadAdapter
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
-
6
5
  # Tap Ability.new to first preload permissions via Cancannible
7
6
  alias_method :cancan_initialize, :initialize
8
7
  def initialize(user)
9
- Cancannible::Preloader.preload_abilities!(user,self)
8
+ Cancannible::Preloader.preload_abilities!(user, self)
10
9
  cancan_initialize(user)
11
10
  end
12
-
13
11
  end
14
-
15
- end
12
+ end
@@ -1,19 +1,19 @@
1
1
  class Cancannible::Preloader
2
-
3
- def self.preload_abilities!(grantee,cancan_ability_object)
4
- new(grantee,cancan_ability_object).preload!
2
+ def self.preload_abilities!(grantee, cancan_ability_object)
3
+ new(grantee, cancan_ability_object).preload!
5
4
  end
6
5
 
7
6
  attr_accessor :grantee
8
7
  attr_accessor :cancan_ability_object
9
8
 
10
- def initialize(grantee,cancan_ability_object)
9
+ def initialize(grantee, cancan_ability_object)
11
10
  self.grantee = grantee
12
11
  self.cancan_ability_object = cancan_ability_object
13
12
  end
14
13
 
15
14
  def preload!
16
15
  return unless grantee.respond_to?(:inherited_permissions)
16
+
17
17
  # load inherited permissions to CanCan Abilities
18
18
  preload_abilities_from_permissions(grantee.inherited_permissions)
19
19
  # load user-based permissions from database to CanCan Abilities
@@ -39,17 +39,15 @@ class Cancannible::Preloader
39
39
  end
40
40
 
41
41
  if permission.resource_id.nil?
42
-
43
42
  if action == :cannot
44
43
  # apply generic unrestricted permission to the class
45
- cancan_ability_object.send( action, ability, resource_type )
44
+ cancan_ability_object.send(action, ability, resource_type)
46
45
  else
47
-
48
46
  refinements = resolve_resource_refinements(ability,model_resource)
49
47
 
50
48
  if refinements.empty?
51
49
  # apply generic unrestricted permission to the class
52
- cancan_ability_object.send( action, ability, resource_type )
50
+ cancan_ability_object.send(action, ability, resource_type)
53
51
  else
54
52
  secondary_refinements = resolve_resource_refinements(ability,model_resource,2).presence || [{}]
55
53
  refinements.each do |refinement|
@@ -58,25 +56,22 @@ class Cancannible::Preloader
58
56
  end
59
57
  end
60
58
  end
61
-
62
59
  end
63
-
64
60
  elsif resource_type.find_by_id(permission.resource_id)
65
61
  cancan_ability_object.send( action, ability, resource_type, id: permission.resource_id)
66
62
  end
67
-
68
63
  end
69
64
  end
70
65
 
71
66
  def resolve_resource_type(given_resource_type)
72
67
  model_resource = nil
73
68
  resource_type = given_resource_type
74
- resource_type = resource_type==resource_type.downcase ? resource_type.to_sym : resource_type.constantize rescue nil
69
+ resource_type = resource_type == resource_type.downcase ? resource_type.to_sym : resource_type.constantize rescue nil
75
70
  model_resource = resource_type.respond_to?(:new) ? resource_type.new : resource_type rescue nil
76
71
  [resource_type,model_resource]
77
72
  end
78
73
 
79
- def resolve_resource_refinements(ability,model_resource,stage=1)
74
+ def resolve_resource_refinements(ability, model_resource, stage=1)
80
75
  Array(Cancannible.refinements[stage-1]).each_with_object([]) do |refinement,memo|
81
76
  refinement_attributes = refinement.dup
82
77
 
@@ -111,5 +106,4 @@ class Cancannible::Preloader
111
106
  memo.push(restriction) if restriction.present?
112
107
  end
113
108
  end
114
-
115
- end
109
+ end
@@ -1,3 +1,3 @@
1
1
  module Cancannible
2
- VERSION = "0.0.2"
2
+ VERSION = '2.0.0'
3
3
  end
data/lib/cancannible.rb CHANGED
@@ -2,8 +2,8 @@ require 'active_support'
2
2
  require 'active_support/core_ext'
3
3
  require 'cancan'
4
4
 
5
- require "cancannible/version"
6
- require "cancannible/config"
7
- require "cancannible/preload_adapter"
8
- require "cancannible/preloader"
9
- require "cancannible/grantee"
5
+ require 'cancannible/version'
6
+ require 'cancannible/config'
7
+ require 'cancannible/preload_adapter'
8
+ require 'cancannible/preloader'
9
+ require 'cancannible/grantee'
@@ -34,6 +34,5 @@ module Cancannible
34
34
  end
35
35
  end
36
36
  end
37
-
38
37
  end
39
38
  end
@@ -1,5 +1,4 @@
1
1
  Cancannible.setup do |config|
2
-
3
2
  # ABILITY CACHING
4
3
  # ===============
5
4
  # Cancannible supports optional ability caching. This can provide a significant performance
@@ -24,6 +23,7 @@ Cancannible.setup do |config|
24
23
 
25
24
 
26
25
  # ACCESS REFINMENTS
26
+ # =================
27
27
  # Cancannible allows general-purpose access refinements to be declared here. This will be enforced
28
28
  # in addition to any rules defined in you Ability.rb file.
29
29
 
@@ -99,5 +99,4 @@ Cancannible.setup do |config|
99
99
  #
100
100
  # By default, access refinements are "stage 1" i.e. applied directly to the permissions being loaded.
101
101
  # By specifying stage 2, this refinement is applied on top of all stage 1 refinements (if possible / applicable)
102
-
103
102
  end
@@ -1,4 +1,4 @@
1
- class CreateCancanniblePermissions < ActiveRecord::Migration
1
+ class CreateCancanniblePermissions < ActiveRecord::Migration[6.1]
2
2
  def change
3
3
  create_table :permissions, force: true do |table|
4
4
  table.integer :permissible_id
@@ -1,8 +1,12 @@
1
1
  # The Permission class stores permissions managed by CanCan and Cancannible
2
2
  class Permission < ActiveRecord::Base
3
3
  belongs_to :permissible, polymorphic: true
4
- belongs_to :resource, polymorphic: true
4
+ belongs_to :resource, polymorphic: true, optional: true
5
5
 
6
- validates_uniqueness_of :ability, scope: [:resource_id, :resource_type, :permissible_id, :permissible_type]
6
+ validates :ability, uniqueness: { scope: [:resource_id, :resource_type, :permissible_id, :permissible_type] }
7
7
 
8
- end
8
+ # Note: for Rails 3 you may need to declare attr_accessible as follows, depending on your whitelist_attributes setting.
9
+ # A future version of cancannible should make this unnecessary.
10
+ #
11
+ # attr_accessible :asserted, :ability, :resource_id, :resource_type
12
+ end
data/spec/spec_helper.rb CHANGED
@@ -6,11 +6,11 @@ require 'sqlite3'
6
6
 
7
7
  # Requires supporting files with custom matchers and macros, etc,
8
8
  # in ./support/ and its subdirectories.
9
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each {|f| require f}
10
10
 
11
11
  RSpec.configure do |config|
12
12
  config.before do
13
13
  Cancannible.reset!
14
14
  run_migrations
15
15
  end
16
- end
16
+ end
@@ -1,5 +1,4 @@
1
1
  module MigrationsHelper
2
-
3
2
  def run_migrations
4
3
  ActiveRecord::Base.establish_connection({
5
4
  adapter: 'sqlite3',
@@ -8,7 +7,6 @@ module MigrationsHelper
8
7
 
9
8
  ActiveRecord::Migration.suppress_messages do
10
9
  ActiveRecord::Schema.define(:version => 0) do
11
-
12
10
  create_table "members", :force => true do |t|
13
11
  t.string "name"
14
12
  t.string "email"
@@ -49,13 +47,11 @@ module MigrationsHelper
49
47
  t.string "name"
50
48
  t.integer "category_id"
51
49
  end
52
-
53
50
  end
54
51
  end
55
52
  end
56
-
57
53
  end
58
54
 
59
55
  RSpec.configure do |conf|
60
56
  conf.include MigrationsHelper
61
- end
57
+ end
@@ -1,13 +1,10 @@
1
1
  # These model definitions are just used for the test scenarios
2
2
 
3
- # The Permission class stores permissions maanged by CanCan and Cancannible
4
3
  class Permission < ActiveRecord::Base
5
4
  belongs_to :permissible, polymorphic: true
6
- belongs_to :resource, polymorphic: true
5
+ belongs_to :resource, polymorphic: true, optional: true
7
6
 
8
- validates_uniqueness_of :ability,
9
- :scope => [:resource_id, :resource_type,
10
- :permissible_id, :permissible_type]
7
+ validates :ability, uniqueness: { scope: [:resource_id, :resource_type, :permissible_id, :permissible_type] }
11
8
  end
12
9
 
13
10
  class Member < ActiveRecord::Base
@@ -29,7 +26,7 @@ class RolesUsers < ActiveRecord::Base
29
26
  end
30
27
 
31
28
  class Role < ActiveRecord::Base
32
- has_many :roles_users, :class_name => 'RolesUsers'
29
+ has_many :roles_users, class_name: 'RolesUsers'
33
30
  has_many :users, through: :roles_users
34
31
 
35
32
  include Cancannible::Grantee
@@ -3,29 +3,46 @@ require 'spec_helper'
3
3
  describe Cancannible do
4
4
  let(:grantee_class) { Member }
5
5
  let(:grantee) { grantee_class.create! }
6
+ let(:cached_object) do
7
+ abilities = Ability.new(grantee)
8
+ abilities.can :read, :all
9
+ abilities
10
+ end
6
11
 
7
12
  describe "#abilities" do
8
13
  subject { grantee.abilities }
9
14
 
10
15
  context "when get_cached_abilities provided" do
11
16
  before do
12
- Cancannible.get_cached_abilities = proc{|grantee| "get_cached_abilities for #{grantee.id}" }
17
+ Cancannible.get_cached_abilities = proc { |grantee| cached_object }
18
+ end
19
+
20
+ it "returns the cached object" do
21
+ expect(cached_object.instance_variable_defined?(:@rules_index)).to eql(true)
22
+ expect(subject).to eql(cached_object)
13
23
  end
14
- it "should returned the cached object" do
15
- should eql("get_cached_abilities for #{grantee.id}")
24
+ context 'when incompatible cached_object' do
25
+ let(:cached_object) { 'bogative' }
26
+ it 'returns a new object' do
27
+ expect(subject).to be_an(Ability)
28
+ expect(subject).to_not eql(cached_object)
29
+ end
16
30
  end
17
31
  context "unless reload requested" do
18
32
  subject { grantee.abilities(true) }
19
- it { should be_an(Ability) }
33
+ it 'returns a new object' do
34
+ expect(subject).to be_an(Ability)
35
+ expect(subject).to_not eql(cached_object)
36
+ end
20
37
  end
21
38
  end
22
39
 
23
40
  context "when store_cached_abilities provided" do
24
41
  before do
25
42
  @stored = nil
26
- Cancannible.store_cached_abilities = proc{ |grantee,ability| @stored = { grantee_id: grantee.id, ability: ability } }
43
+ Cancannible.store_cached_abilities = proc { |grantee, ability| @stored = { grantee_id: grantee.id, ability: ability } }
27
44
  end
28
- it "should store the cached object" do
45
+ it "stores the cached object" do
29
46
  expect { subject }.to change { @stored }.from(nil)
30
47
  expect(@stored[:grantee_id]).to eql(grantee.id)
31
48
  expect(@stored[:ability]).to be_an(Ability)
@@ -36,32 +53,29 @@ describe Cancannible do
36
53
  before do
37
54
  @stored = nil
38
55
  @store = 0
39
- Cancannible.get_cached_abilities = proc{|grantee| @stored }
40
- Cancannible.store_cached_abilities = proc{ |grantee,ability| @store += 1 ; @stored = { grantee_id: grantee.id, ability: ability } }
56
+ Cancannible.get_cached_abilities = proc { |grantee| @stored[:ability] if @stored }
57
+ Cancannible.store_cached_abilities = proc { |grantee, ability| @store += 1 ; @stored = { grantee_id: grantee.id, ability: ability } }
41
58
  end
42
- it "should store the cached object on the first call" do
59
+ it "stores the cached object on the first call" do
43
60
  expect { subject }.to change { @stored }.from(nil)
44
61
  expect(@store).to eql(1)
45
62
  expect(@stored[:grantee_id]).to eql(grantee.id)
46
63
  expect(@stored[:ability]).to be_an(Ability)
47
64
  end
48
- it "should return the cached object on the second call" do
65
+ it "returns the cached object on the second call" do
49
66
  expect { subject }.to change { @stored }.from(nil)
50
67
  expect(@store).to eql(1)
51
68
  expect { grantee.abilities }.to_not change { @store }
52
- expect(grantee.abilities[:grantee_id]).to eql(grantee.id)
53
- expect(grantee.abilities[:ability]).to be_an(Ability)
69
+ expect(grantee.abilities).to be_an(Ability)
70
+ expect(@stored[:grantee_id]).to eql(grantee.id)
54
71
  end
55
72
  it "should re-cache object on the second call if refresh requested" do
56
73
  expect { subject }.to change { @stored }.from(nil)
57
74
  expect(@store).to eql(1)
58
75
  expect { grantee.abilities(true) }.to change { @store }.from(1).to(2)
59
- expect(grantee.abilities[:grantee_id]).to eql(grantee.id)
60
- expect(grantee.abilities[:ability]).to be_an(Ability)
76
+ expect(grantee.abilities).to be_an(Ability)
77
+ expect(@stored[:grantee_id]).to eql(grantee.id)
61
78
  end
62
79
  end
63
-
64
-
65
80
  end
66
-
67
- end
81
+ end
@@ -14,4 +14,4 @@ describe Cancannible do
14
14
  subject
15
15
  end
16
16
  end
17
- end
17
+ end
@@ -1,6 +1,5 @@
1
1
  require 'spec_helper'
2
2
 
3
-
4
3
  describe Cancannible do
5
4
  let(:grantee_class) { User }
6
5
  let(:ability) { :blow }
@@ -9,7 +8,6 @@ describe Cancannible do
9
8
  subject(:grantee) { grantee_class.create!(username: username) }
10
9
 
11
10
  describe "#can?" do
12
-
13
11
  context "with custom attribute association restriction" do
14
12
  let(:resource_class) { Widget }
15
13
  before do
@@ -245,7 +243,5 @@ describe Cancannible do
245
243
  it { should be_falsey }
246
244
  end
247
245
  end
248
-
249
246
  end
250
-
251
247
  end
@@ -4,7 +4,6 @@ describe Cancannible::Grantee do
4
4
  let(:grantee_class) { Member }
5
5
 
6
6
  context "without permissions inheritance" do
7
-
8
7
  describe "##inheritable_permissions" do
9
8
  subject { grantee_class.inheritable_permissions }
10
9
  it { should be_empty }
@@ -43,9 +42,13 @@ describe Cancannible::Grantee do
43
42
  context "when permission is not asserted" do
44
43
  it { should be_truthy }
45
44
  end
46
- context "when permission is not asserted but can is" do
45
+ context "when :can already asserted" do
47
46
  before { grantee.can(:read, resource) }
48
47
  it { should be_falsey }
48
+ context "and then reset as :cannot" do
49
+ before { grantee.cannot(:read, resource) }
50
+ it { should be_truthy }
51
+ end
49
52
  end
50
53
  context "when permission is asserted" do
51
54
  before { grantee.cannot(:read, resource) }
@@ -54,31 +57,6 @@ describe Cancannible::Grantee do
54
57
  end
55
58
  end
56
59
 
57
- context "with a nil resource" do
58
- let!(:resource) { nil }
59
- describe "#can? -> nil" do
60
- subject { grantee.can?(:read, nil) }
61
- context "when permission is not set" do
62
- it { should be_falsey }
63
- end
64
- context "when permission is set" do
65
- before { grantee.can(:read, resource) }
66
- it { should be_truthy }
67
- end
68
- end
69
- describe "#can? -> ''" do
70
- subject { grantee.can?(:read, '') }
71
- context "when permission is not set" do
72
- it { should be_falsey }
73
- end
74
- context "when permission is set" do
75
- before { grantee.can(:read, resource) }
76
- it { should be_falsey }
77
- end
78
- end
79
- end
80
-
81
-
82
60
  context "with a resource class" do
83
61
  let!(:resource) { Widget }
84
62
 
@@ -117,15 +95,14 @@ describe Cancannible::Grantee do
117
95
  context "with a non-existent model" do
118
96
  describe "instance" do
119
97
  let!(:obsolete_permission) {grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'Bogative', resource_id: 33) }
120
- it "should not error on load" do
121
- expect { grantee.abilities }.to_not raise_error
98
+ it "raises CanCan::Error" do
99
+ expect { grantee.abilities }.to raise_error(CanCan::Error)
122
100
  end
123
101
  end
124
102
  describe "class" do
125
103
  let!(:obsolete_permission) {grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'Bogative') }
126
- it "should not error on load" do
127
- grantee.abilities
128
- expect { grantee.abilities }.to_not raise_error
104
+ it "raises CanCan::Error" do
105
+ expect { grantee.abilities }.to raise_error(CanCan::Error)
129
106
  end
130
107
  end
131
108
  end
@@ -134,19 +111,17 @@ describe Cancannible::Grantee do
134
111
  class SuperBogative < ActiveRecord::Base
135
112
  end
136
113
  context "instance" do
137
- let!(:obsolete_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative', resource_id: 33) }
138
- it "should not error on load" do
114
+ let!(:invalid_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative', resource_id: 33) }
115
+ it "does not error on load" do
139
116
  expect { grantee.abilities }.to_not raise_error
140
117
  end
141
118
  end
142
119
  context "class" do
143
- let!(:obsolete_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative') }
144
- it "should not error on load" do
120
+ let!(:invalid_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative') }
121
+ it "does not error on load" do
145
122
  expect { grantee.abilities }.to_not raise_error
146
123
  end
147
124
  end
148
125
  end
149
-
150
126
  end
151
-
152
127
  end
@@ -1,11 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
-
4
3
  describe Cancannible do
5
4
  let(:grantee_class) { User }
6
5
 
7
6
  context "with mulitple sources of permissions inheritance" do
8
-
9
7
  describe "##inheritable_permissions" do
10
8
  subject { grantee_class.inheritable_permissions }
11
9
  it { should eql([:roles, :group]) }
@@ -15,12 +13,12 @@ describe Cancannible do
15
13
  let!(:role_b) { Role.create! }
16
14
  let!(:group_a) { Group.create! }
17
15
  let!(:group_b) { Group.create! }
18
- subject(:grantee) {
16
+ subject(:grantee) do
19
17
  u = grantee_class.new(group: group_a)
20
18
  u.roles << role_a
21
19
  u.save!
22
20
  u
23
- }
21
+ end
24
22
 
25
23
  context "with a symbolic resource" do
26
24
  let!(:resource) { :something }
@@ -43,10 +41,8 @@ describe Cancannible do
43
41
  it { should be_truthy }
44
42
  end
45
43
  end
46
-
47
44
  end
48
45
 
49
-
50
46
  context "with a resource class" do
51
47
  let!(:resource) { Widget }
52
48
 
@@ -68,7 +64,6 @@ describe Cancannible do
68
64
  it { should be_truthy }
69
65
  end
70
66
  end
71
-
72
67
  end
73
68
 
74
69
  context "with a resource instance" do
@@ -136,10 +131,6 @@ describe Cancannible do
136
131
  it { should be_truthy }
137
132
  end
138
133
  end
139
-
140
-
141
134
  end
142
-
143
135
  end
144
-
145
136
  end
metadata CHANGED
@@ -1,141 +1,169 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cancannible
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Gallagher
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-07-31 00:00:00.000000000 Z
11
+ date: 2022-03-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ~>
17
+ - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '3.2'
19
+ version: '6.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ~>
24
+ - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '3.2'
26
+ version: '6.1'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: activemodel
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.2'
33
+ version: '6.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.2'
40
+ version: '6.1'
41
41
  - !ruby/object:Gem::Dependency
42
- name: cancan
42
+ name: cancancan
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
- version: '1.6'
47
+ version: '0'
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
- version: '1.6'
54
+ version: '0'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: activerecord
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - ~>
59
+ - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '3.2'
61
+ version: '6.1'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - ~>
66
+ - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '3.2'
68
+ version: '6.1'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - ~>
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
- version: '1.3'
75
+ version: 1.3.2
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - ~>
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
- version: '1.3'
82
+ version: 1.3.2
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: bundler
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
- - - ~>
87
+ - - ">="
88
88
  - !ruby/object:Gem::Version
89
- version: '1.6'
89
+ version: '0'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
- - - ~>
94
+ - - ">="
95
95
  - !ruby/object:Gem::Version
96
- version: '1.6'
96
+ version: '0'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: rake
99
99
  requirement: !ruby/object:Gem::Requirement
100
100
  requirements:
101
- - - ~>
101
+ - - ">="
102
102
  - !ruby/object:Gem::Version
103
- version: '10.0'
103
+ version: '0'
104
104
  type: :development
105
105
  prerelease: false
106
106
  version_requirements: !ruby/object:Gem::Requirement
107
107
  requirements:
108
- - - ~>
108
+ - - ">="
109
109
  - !ruby/object:Gem::Version
110
- version: '10.0'
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rdoc
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
111
125
  - !ruby/object:Gem::Dependency
112
126
  name: rspec
113
127
  requirement: !ruby/object:Gem::Requirement
114
128
  requirements:
115
- - - ~>
129
+ - - ">="
116
130
  - !ruby/object:Gem::Version
117
- version: '3.0'
131
+ version: '0'
118
132
  type: :development
119
133
  prerelease: false
120
134
  version_requirements: !ruby/object:Gem::Requirement
121
135
  requirements:
122
- - - ~>
136
+ - - ">="
123
137
  - !ruby/object:Gem::Version
124
- version: '3.0'
138
+ version: '0'
125
139
  - !ruby/object:Gem::Dependency
126
140
  name: guard-rspec
127
141
  requirement: !ruby/object:Gem::Requirement
128
142
  requirements:
129
- - - ~>
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rb-fsevent
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
130
158
  - !ruby/object:Gem::Version
131
- version: '4.0'
159
+ version: '0'
132
160
  type: :development
133
161
  prerelease: false
134
162
  version_requirements: !ruby/object:Gem::Requirement
135
163
  requirements:
136
- - - ~>
164
+ - - ">="
137
165
  - !ruby/object:Gem::Version
138
- version: '4.0'
166
+ version: '0'
139
167
  description: Extends CanCan with dynamic, inheritable permissions stored in a database,
140
168
  with caching and multi-tenant refinements
141
169
  email:
@@ -144,9 +172,8 @@ executables: []
144
172
  extensions: []
145
173
  extra_rdoc_files: []
146
174
  files:
147
- - .gitignore
148
- - .rspec
149
- - .travis.yml
175
+ - ".github/workflows/ruby.yml"
176
+ - ".gitignore"
150
177
  - Gemfile
151
178
  - Guardfile
152
179
  - LICENSE.txt
@@ -176,24 +203,23 @@ homepage: https://github.com/evendis/cancannible
176
203
  licenses:
177
204
  - MIT
178
205
  metadata: {}
179
- post_install_message:
206
+ post_install_message:
180
207
  rdoc_options: []
181
208
  require_paths:
182
209
  - lib
183
210
  required_ruby_version: !ruby/object:Gem::Requirement
184
211
  requirements:
185
- - - ! '>='
212
+ - - ">="
186
213
  - !ruby/object:Gem::Version
187
214
  version: '0'
188
215
  required_rubygems_version: !ruby/object:Gem::Requirement
189
216
  requirements:
190
- - - ! '>='
217
+ - - ">="
191
218
  - !ruby/object:Gem::Version
192
219
  version: '0'
193
220
  requirements: []
194
- rubyforge_project:
195
- rubygems_version: 2.2.2
196
- signing_key:
221
+ rubygems_version: 3.2.20
222
+ signing_key:
197
223
  specification_version: 4
198
224
  summary: Dynamic, configurable permissions for CanCan
199
225
  test_files:
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color
data/.travis.yml DELETED
@@ -1,4 +0,0 @@
1
- # These are specific configuration settings required for travis-ci
2
- language: ruby
3
- rvm:
4
- - 1.9.3