cancannible 1.0.0 → 2.1.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
- ZjFkNmJkNGYzODQ2NDRkZDJlODM0M2UyYjY2OTNlODJjMWIzNjU1Yw==
5
- data.tar.gz: !binary |-
6
- YzhmMDIxNGY3Y2NkOThiMDEzYzI2ODU5NTA1ZDMyMDA3NWQ1YzdjYQ==
2
+ SHA256:
3
+ metadata.gz: ecb16c35b4fdf331771322c61a13d78d34e6e75eb97b26b06e8745ec0bf86ff4
4
+ data.tar.gz: 88d347b2f3dccf1e8fa6c38413676d38d89e7ad654ef425e70da5de5dce79592
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- MTc3ZGNlOTU1NzliNGFlNjBjOTk0ZGVmZDMyNzg4ODBlYTkxNGM4Njg3Mjdi
10
- NDlkYjc0ZDg3NDRkZDIzMjkzMjRhOGQxZTQ4N2JiZDI1MjAxMWE4NzQ3ZmY5
11
- NGFjZTYxYWM4Yzg0NGNlMWM3NGMzZTgxNjIxZWE5OThjNTAyMGE=
12
- data.tar.gz: !binary |-
13
- YzQzYzU4ZDEzZmRjZWZmNTZkYmVkNzExNzQxN2UyODNmNjc4ZWUzNTE2ZTZm
14
- MzhmNDE2NjQwN2YyMzcwMDg5OTg5MGY1OGNiZjQyNDRmM2EyNjJmOGYxZGUw
15
- ZjY1MjI2NmNhNTBkM2UyNjg4MTA1MGI3ZWIwNWFmYWE5MTY2NGM=
6
+ metadata.gz: 5e418c7689141e1967e44d011da10579dd6d1439bab2043ec5d71088a7f7f916be8496aa8dcf04c9c65bc70367980e32206e8c7029da2ccfb3fc52d7bc338b20
7
+ data.tar.gz: 481bdcff9e0e8501070e4c0ca1e0d4400e65708608bdcfaa6a7fd551d5783849eba6808bda6fe3e97c3df18c12b6c04764363bc1cb25e623e06803b67aeb0301
@@ -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/.gitignore CHANGED
@@ -22,3 +22,4 @@ tmp
22
22
  mkmf.log
23
23
  .rvm*
24
24
  .ruby*
25
+ .byebug_history
data/Gemfile CHANGED
@@ -1,6 +1,4 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem "appraisal"
4
-
5
3
  # Specify your gem's dependencies in cancannible.gemspec
6
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,23 +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
11
- * tested with Rails 4 (but limited experience in the field?)
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
12
16
 
13
17
  ## Limitations
18
+
14
19
  Cancannible's origin was in a web application that's been in production for over 4 years.
15
20
  This gem is an initial refactoring as a separate component. It continues to be used in production, but
16
21
  there are some limitations and constraints that will ideally be removed or changed over time:
17
22
 
18
23
  * It only supports ActiveRecord for permissions storage (specifically, it has been tested with PostgreSQL and SQLite)
19
24
  * It currently assumes permissions are stored in a Permission model with a specific structure
20
- * 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.
25
+ * It works with the [CanCanCan](https://github.com/CanCanCommunity/cancancan) gem.
21
26
  * It assumes your CanCan rules are setup with the default `Ability` class
22
27
 
23
28
 
data/Rakefile CHANGED
@@ -7,5 +7,5 @@ task :default => :spec
7
7
 
8
8
  desc "Open an irb session preloaded with this library"
9
9
  task :console do
10
- sh "irb -rubygems -I lib -r cancannible.rb"
11
- end
10
+ sh "irb -I lib -r cancannible.rb"
11
+ end
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.1"
22
- spec.add_runtime_dependency "activemodel", ">= 3.2.1"
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.1"
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
@@ -35,16 +35,13 @@ module Cancannible::Grantee
35
35
  permission
36
36
  end
37
37
  end
38
-
39
38
  end
40
39
 
41
40
  module ClassMethods
42
-
43
41
  # Command: configures the set of associations (array of symbols) from which permissions should be inherited
44
42
  def inherit_permissions_from(*relations)
45
43
  self.inheritable_permissions = relations
46
44
  end
47
-
48
45
  end
49
46
 
50
47
  # Returns the Ability set for the owner.
@@ -53,7 +50,10 @@ module Cancannible::Grantee
53
50
  @abilities = if refresh
54
51
  nil
55
52
  elsif Cancannible.get_cached_abilities.respond_to?(:call)
56
- Cancannible.get_cached_abilities.call(self)
53
+ result = Cancannible.get_cached_abilities.call(self)
54
+ # performs a crude compatibility check: cancan rules won't have a @rules_index
55
+ # (neither will an empty ability object, but we ignore this case)
56
+ result unless result && !result.instance_variable_defined?(:@rules_index)
57
57
  end
58
58
  return @abilities if @abilities
59
59
 
@@ -64,7 +64,7 @@ module Cancannible::Grantee
64
64
  ability_class.new(self)
65
65
  end
66
66
 
67
- Cancannible.store_cached_abilities.call(self,@abilities) if Cancannible.store_cached_abilities.respond_to?(:call)
67
+ Cancannible.store_cached_abilities.call(self, @abilities) if Cancannible.store_cached_abilities.respond_to?(:call)
68
68
  @abilities
69
69
  end
70
70
 
@@ -98,16 +98,18 @@ module Cancannible::Grantee
98
98
  def cannot(ability, resource)
99
99
  permissions << [ability, resource, false]
100
100
  end
101
-
102
101
  end
103
102
 
104
-
105
103
  module Cancannible
106
104
  # This module is automatically included into all controllers.
107
105
  # It overrides some CanCan ControllerAdditions
108
106
  module ControllerAdditions
107
+ # Returns abilities cached in the current_user model.
108
+ # If that fails, returns a default Ability instance
109
109
  def current_ability
110
- current_user.try(:abilities)
110
+ current_user.try(:abilities) || if ability_class = ('::Ability'.constantize rescue nil)
111
+ ability_class.new(current_user)
112
+ end
111
113
  end
112
114
  end
113
115
  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 = "1.0.0"
2
+ VERSION = '2.1.0'
3
3
  end
data/lib/cancannible.rb CHANGED
@@ -1,9 +1,9 @@
1
1
  require 'active_support'
2
2
  require 'active_support/core_ext'
3
- require 'cancan'
3
+ require 'cancancan'
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
@@ -100,5 +99,4 @@ Cancannible.setup do |config|
100
99
  #
101
100
  # By default, access refinements are "stage 1" i.e. applied directly to the permissions being loaded.
102
101
  # By specifying stage 2, this refinement is applied on top of all stage 1 refinements (if possible / applicable)
103
-
104
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
@@ -13,4 +13,4 @@ RSpec.configure do |config|
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
@@ -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: cached_object } }
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,27 @@ 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 && cached_object }
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
- expect(@stored[:grantee_id]).to eql(grantee.id)
46
- expect(@stored[:ability]).to be_an(Ability)
62
+ expect(grantee.abilities.instance_variable_get(:@rules).size).to eql(1)
63
+ expect(grantee.abilities.instance_variable_get(:@rules_index).size).to eql(1)
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)
54
70
  end
55
71
  it "should re-cache object on the second call if refresh requested" do
56
72
  expect { subject }.to change { @stored }.from(nil)
57
73
  expect(@store).to eql(1)
58
74
  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)
75
+ expect(grantee.abilities).to be_an(Ability)
61
76
  end
62
77
  end
63
-
64
-
65
78
  end
66
-
67
- end
79
+ 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 }
@@ -58,31 +57,6 @@ describe Cancannible::Grantee do
58
57
  end
59
58
  end
60
59
 
61
- context "with a nil resource" do
62
- let!(:resource) { nil }
63
- describe "#can? -> nil" do
64
- subject { grantee.can?(:read, nil) }
65
- context "when permission is not set" do
66
- it { should be_falsey }
67
- end
68
- context "when permission is set" do
69
- before { grantee.can(:read, resource) }
70
- it { should be_truthy }
71
- end
72
- end
73
- describe "#can? -> ''" do
74
- subject { grantee.can?(:read, '') }
75
- context "when permission is not set" do
76
- it { should be_falsey }
77
- end
78
- context "when permission is set" do
79
- before { grantee.can(:read, resource) }
80
- it { should be_falsey }
81
- end
82
- end
83
- end
84
-
85
-
86
60
  context "with a resource class" do
87
61
  let!(:resource) { Widget }
88
62
 
@@ -121,15 +95,14 @@ describe Cancannible::Grantee do
121
95
  context "with a non-existent model" do
122
96
  describe "instance" do
123
97
  let!(:obsolete_permission) {grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'Bogative', resource_id: 33) }
124
- it "should not error on load" do
125
- expect { grantee.abilities }.to_not raise_error
98
+ it "raises CanCan::Error" do
99
+ expect { grantee.abilities }.to raise_error(CanCan::Error)
126
100
  end
127
101
  end
128
102
  describe "class" do
129
103
  let!(:obsolete_permission) {grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'Bogative') }
130
- it "should not error on load" do
131
- grantee.abilities
132
- expect { grantee.abilities }.to_not raise_error
104
+ it "raises CanCan::Error" do
105
+ expect { grantee.abilities }.to raise_error(CanCan::Error)
133
106
  end
134
107
  end
135
108
  end
@@ -138,19 +111,17 @@ describe Cancannible::Grantee do
138
111
  class SuperBogative < ActiveRecord::Base
139
112
  end
140
113
  context "instance" do
141
- let!(:obsolete_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative', resource_id: 33) }
142
- 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
143
116
  expect { grantee.abilities }.to_not raise_error
144
117
  end
145
118
  end
146
119
  context "class" do
147
- let!(:obsolete_permission) { grantee.permissions.create!(asserted: true, ability: 'manage', resource_type: 'SuperBogative') }
148
- 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
149
122
  expect { grantee.abilities }.to_not raise_error
150
123
  end
151
124
  end
152
125
  end
153
-
154
126
  end
155
-
156
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: 1.0.0
4
+ version: 2.1.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: 2015-01-06 00:00:00.000000000 Z
11
+ date: 2022-06-09 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.1
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.1
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.1
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.1
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.1
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.1
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,20 +172,14 @@ executables: []
144
172
  extensions: []
145
173
  extra_rdoc_files: []
146
174
  files:
147
- - .gitignore
148
- - .rspec
149
- - .travis.yml
150
- - Appraisals
175
+ - ".github/workflows/ruby.yml"
176
+ - ".gitignore"
151
177
  - Gemfile
152
178
  - Guardfile
153
179
  - LICENSE.txt
154
180
  - README.md
155
181
  - Rakefile
156
182
  - cancannible.gemspec
157
- - gemfiles/rails_3.gemfile
158
- - gemfiles/rails_3.gemfile.lock
159
- - gemfiles/rails_4.gemfile
160
- - gemfiles/rails_4.gemfile.lock
161
183
  - lib/cancannible.rb
162
184
  - lib/cancannible/config.rb
163
185
  - lib/cancannible/grantee.rb
@@ -181,24 +203,23 @@ homepage: https://github.com/evendis/cancannible
181
203
  licenses:
182
204
  - MIT
183
205
  metadata: {}
184
- post_install_message:
206
+ post_install_message:
185
207
  rdoc_options: []
186
208
  require_paths:
187
209
  - lib
188
210
  required_ruby_version: !ruby/object:Gem::Requirement
189
211
  requirements:
190
- - - ! '>='
212
+ - - ">="
191
213
  - !ruby/object:Gem::Version
192
214
  version: '0'
193
215
  required_rubygems_version: !ruby/object:Gem::Requirement
194
216
  requirements:
195
- - - ! '>='
217
+ - - ">="
196
218
  - !ruby/object:Gem::Version
197
219
  version: '0'
198
220
  requirements: []
199
- rubyforge_project:
200
- rubygems_version: 2.4.5
201
- signing_key:
221
+ rubygems_version: 3.2.20
222
+ signing_key:
202
223
  specification_version: 4
203
224
  summary: Dynamic, configurable permissions for CanCan
204
225
  test_files:
data/.rspec DELETED
@@ -1,2 +0,0 @@
1
- --format documentation
2
- --color
data/.travis.yml DELETED
@@ -1,14 +0,0 @@
1
- # These are specific configuration settings required for travis-ci
2
- language: ruby
3
- rvm:
4
- - 1.9.3
5
- - 2.1.5
6
- gemfile:
7
- - gemfiles/rails_3.gemfile
8
- - gemfiles/rails_4.gemfile
9
- matrix:
10
- exclude:
11
- - rvm: 1.9.3
12
- gemfile: gemfiles/rails_4.gemfile
13
- - rvm: 2.1.5
14
- gemfile: gemfiles/rails_3.gemfile
data/Appraisals DELETED
@@ -1,11 +0,0 @@
1
- appraise "rails-3" do
2
- gem "activesupport", '~> 3.2'
3
- gem "activemodel", '~> 3.2'
4
- gem "activerecord", '~> 3.2'
5
- end
6
-
7
- appraise "rails-4" do
8
- gem "activesupport", '> 4'
9
- gem "activemodel", '> 4'
10
- gem "activerecord", '> 4'
11
- end
@@ -1,10 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "activesupport", "~> 3.2"
7
- gem "activemodel", "~> 3.2"
8
- gem "activerecord", "~> 3.2"
9
-
10
- gemspec :path => "../"
@@ -1,98 +0,0 @@
1
- PATH
2
- remote: ../
3
- specs:
4
- cancannible (1.0.0)
5
- activemodel (>= 3.2.1)
6
- activesupport (>= 3.2.1)
7
- cancan (~> 1.6)
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- activemodel (3.2.19)
13
- activesupport (= 3.2.19)
14
- builder (~> 3.0.0)
15
- activerecord (3.2.19)
16
- activemodel (= 3.2.19)
17
- activesupport (= 3.2.19)
18
- arel (~> 3.0.2)
19
- tzinfo (~> 0.3.29)
20
- activesupport (3.2.19)
21
- i18n (~> 0.6, >= 0.6.4)
22
- multi_json (~> 1.0)
23
- appraisal (1.0.2)
24
- bundler
25
- rake
26
- thor (>= 0.14.0)
27
- arel (3.0.3)
28
- builder (3.0.4)
29
- cancan (1.6.10)
30
- celluloid (0.16.0)
31
- timers (~> 4.0.0)
32
- coderay (1.1.0)
33
- diff-lcs (1.2.5)
34
- ffi (1.9.6)
35
- formatador (0.2.5)
36
- guard (2.10.5)
37
- formatador (>= 0.2.4)
38
- listen (~> 2.7)
39
- lumberjack (~> 1.0)
40
- nenv (~> 0.1)
41
- pry (>= 0.9.12)
42
- thor (>= 0.18.1)
43
- guard-compat (1.2.0)
44
- guard-rspec (4.5.0)
45
- guard (~> 2.1)
46
- guard-compat (~> 1.1)
47
- rspec (>= 2.99.0, < 4.0)
48
- hitimes (1.2.2)
49
- i18n (0.7.0)
50
- listen (2.8.4)
51
- celluloid (>= 0.15.2)
52
- rb-fsevent (>= 0.9.3)
53
- rb-inotify (>= 0.9)
54
- lumberjack (1.0.9)
55
- method_source (0.8.2)
56
- multi_json (1.10.1)
57
- nenv (0.1.1)
58
- pry (0.10.1)
59
- coderay (~> 1.1.0)
60
- method_source (~> 0.8.1)
61
- slop (~> 3.4)
62
- rake (10.4.2)
63
- rb-fsevent (0.9.4)
64
- rb-inotify (0.9.5)
65
- ffi (>= 0.5.0)
66
- rspec (3.1.0)
67
- rspec-core (~> 3.1.0)
68
- rspec-expectations (~> 3.1.0)
69
- rspec-mocks (~> 3.1.0)
70
- rspec-core (3.1.7)
71
- rspec-support (~> 3.1.0)
72
- rspec-expectations (3.1.2)
73
- diff-lcs (>= 1.2.0, < 2.0)
74
- rspec-support (~> 3.1.0)
75
- rspec-mocks (3.1.3)
76
- rspec-support (~> 3.1.0)
77
- rspec-support (3.1.2)
78
- slop (3.6.0)
79
- sqlite3 (1.3.10)
80
- thor (0.19.1)
81
- timers (4.0.1)
82
- hitimes
83
- tzinfo (0.3.40)
84
-
85
- PLATFORMS
86
- ruby
87
-
88
- DEPENDENCIES
89
- activemodel (~> 3.2)
90
- activerecord (~> 3.2)
91
- activesupport (~> 3.2)
92
- appraisal
93
- bundler (~> 1.6)
94
- cancannible!
95
- guard-rspec (~> 4.0)
96
- rake (~> 10.0)
97
- rspec (~> 3.0)
98
- sqlite3 (~> 1.3)
@@ -1,10 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "appraisal"
6
- gem "activesupport", "> 4"
7
- gem "activemodel", "> 4"
8
- gem "activerecord", "> 4"
9
-
10
- gemspec :path => "../"
@@ -1,103 +0,0 @@
1
- PATH
2
- remote: ../
3
- specs:
4
- cancannible (1.0.0)
5
- activemodel (>= 3.2.1)
6
- activesupport (>= 3.2.1)
7
- cancan (~> 1.6)
8
-
9
- GEM
10
- remote: https://rubygems.org/
11
- specs:
12
- activemodel (4.2.0)
13
- activesupport (= 4.2.0)
14
- builder (~> 3.1)
15
- activerecord (4.2.0)
16
- activemodel (= 4.2.0)
17
- activesupport (= 4.2.0)
18
- arel (~> 6.0)
19
- activesupport (4.2.0)
20
- i18n (~> 0.7)
21
- json (~> 1.7, >= 1.7.7)
22
- minitest (~> 5.1)
23
- thread_safe (~> 0.3, >= 0.3.4)
24
- tzinfo (~> 1.1)
25
- appraisal (1.0.2)
26
- bundler
27
- rake
28
- thor (>= 0.14.0)
29
- arel (6.0.0)
30
- builder (3.2.2)
31
- cancan (1.6.10)
32
- celluloid (0.16.0)
33
- timers (~> 4.0.0)
34
- coderay (1.1.0)
35
- diff-lcs (1.2.5)
36
- ffi (1.9.6)
37
- formatador (0.2.5)
38
- guard (2.10.5)
39
- formatador (>= 0.2.4)
40
- listen (~> 2.7)
41
- lumberjack (~> 1.0)
42
- nenv (~> 0.1)
43
- pry (>= 0.9.12)
44
- thor (>= 0.18.1)
45
- guard-compat (1.2.0)
46
- guard-rspec (4.5.0)
47
- guard (~> 2.1)
48
- guard-compat (~> 1.1)
49
- rspec (>= 2.99.0, < 4.0)
50
- hitimes (1.2.2)
51
- i18n (0.7.0)
52
- json (1.8.1)
53
- listen (2.8.4)
54
- celluloid (>= 0.15.2)
55
- rb-fsevent (>= 0.9.3)
56
- rb-inotify (>= 0.9)
57
- lumberjack (1.0.9)
58
- method_source (0.8.2)
59
- minitest (5.5.0)
60
- nenv (0.1.1)
61
- pry (0.10.1)
62
- coderay (~> 1.1.0)
63
- method_source (~> 0.8.1)
64
- slop (~> 3.4)
65
- rake (10.4.2)
66
- rb-fsevent (0.9.4)
67
- rb-inotify (0.9.5)
68
- ffi (>= 0.5.0)
69
- rspec (3.1.0)
70
- rspec-core (~> 3.1.0)
71
- rspec-expectations (~> 3.1.0)
72
- rspec-mocks (~> 3.1.0)
73
- rspec-core (3.1.7)
74
- rspec-support (~> 3.1.0)
75
- rspec-expectations (3.1.2)
76
- diff-lcs (>= 1.2.0, < 2.0)
77
- rspec-support (~> 3.1.0)
78
- rspec-mocks (3.1.3)
79
- rspec-support (~> 3.1.0)
80
- rspec-support (3.1.2)
81
- slop (3.6.0)
82
- sqlite3 (1.3.10)
83
- thor (0.19.1)
84
- thread_safe (0.3.4)
85
- timers (4.0.1)
86
- hitimes
87
- tzinfo (1.2.2)
88
- thread_safe (~> 0.1)
89
-
90
- PLATFORMS
91
- ruby
92
-
93
- DEPENDENCIES
94
- activemodel (> 4)
95
- activerecord (> 4)
96
- activesupport (> 4)
97
- appraisal
98
- bundler (~> 1.6)
99
- cancannible!
100
- guard-rspec (~> 4.0)
101
- rake (~> 10.0)
102
- rspec (~> 3.0)
103
- sqlite3 (~> 1.3)