abilities 0.1.2 → 4.0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +1 -1
  3. data/README.md +31 -44
  4. data/Rakefile +1 -14
  5. data/lib/abilities.rb +9 -18
  6. data/lib/abilities/definitions.rb +38 -29
  7. data/lib/abilities/extensions/action_controller/base.rb +28 -0
  8. data/lib/abilities/proxy.rb +6 -7
  9. data/lib/abilities/railtie.rb +4 -3
  10. data/lib/abilities/version.rb +1 -1
  11. data/lib/generators/abilities/install/install_generator.rb +15 -0
  12. data/lib/generators/abilities/{templates/abilities.rb → install/templates/configuration.rb} +0 -0
  13. data/test/dummy/Rakefile +0 -1
  14. data/test/dummy/app/assets/javascripts/application.js +2 -2
  15. data/test/dummy/app/assets/stylesheets/application.css +1 -1
  16. data/test/dummy/app/controllers/products_controller.rb +10 -0
  17. data/test/dummy/app/models/product.rb +2 -0
  18. data/test/dummy/app/models/user.rb +0 -1
  19. data/test/dummy/app/views/layouts/application.html.erb +9 -11
  20. data/test/dummy/app/views/products/show.html.erb +6 -0
  21. data/test/dummy/bin/bundle +1 -0
  22. data/test/dummy/bin/rails +2 -1
  23. data/test/dummy/bin/rake +1 -0
  24. data/test/dummy/bin/setup +30 -0
  25. data/test/dummy/config.ru +1 -1
  26. data/test/dummy/config/abilities.rb +6 -7
  27. data/test/dummy/config/application.rb +3 -0
  28. data/test/dummy/config/database.yml +4 -22
  29. data/test/dummy/config/database.yml.travis +3 -0
  30. data/test/dummy/config/environments/development.rb +6 -2
  31. data/test/dummy/config/environments/production.rb +16 -24
  32. data/test/dummy/config/environments/test.rb +7 -12
  33. data/test/dummy/config/initializers/assets.rb +11 -0
  34. data/test/dummy/config/initializers/mime_types.rb +1 -1
  35. data/test/dummy/config/routes.rb +1 -54
  36. data/test/dummy/config/secrets.yml +3 -3
  37. data/test/dummy/db/migrate/20140629203344_create_users.rb +1 -3
  38. data/test/dummy/db/migrate/20140629203412_create_products.rb +7 -0
  39. data/test/dummy/db/schema.rb +9 -9
  40. data/test/dummy/log/development.log +78 -0
  41. data/test/dummy/log/test.log +1465 -246
  42. data/test/dummy/public/404.html +57 -63
  43. data/test/dummy/public/422.html +57 -63
  44. data/test/dummy/public/500.html +56 -62
  45. data/test/dummy/tmp/cache/assets/sprockets/v3.0/2b/2bzOr5XdBQAg_ZBDeXY157jGXLRL6qjEoFZBTPyLFwM.cache +0 -0
  46. data/test/dummy/tmp/cache/assets/sprockets/v3.0/48/48oV_bpl6OaHjWm9j-I1uNUp5m7SbkTgYjW6NaNnTfU.cache +0 -0
  47. data/test/dummy/tmp/cache/assets/sprockets/v3.0/5L/5Lly_CA8DZvPhQV2jDQx-Y6P_y3Ygra9t5jfSlGhHDA.cache +2 -0
  48. data/test/dummy/tmp/cache/assets/sprockets/v3.0/OI/OI6uxGcnsKavdWTtwDAasU3wPx8QXhzBgV0X2n1KjMQ.cache +2 -0
  49. data/test/dummy/tmp/cache/assets/sprockets/v3.0/SG/SGNGr7AZfBE1q7ev2-YM1G-o0XAZ0pKqbsS3NvHtRcA.cache +1 -0
  50. data/test/dummy/tmp/cache/assets/sprockets/v3.0/fG/fG_uaNK13wisQiji91xNsGecGxX9QhMCF2eSX_aR0G0.cache +1 -0
  51. data/test/dummy/tmp/cache/assets/sprockets/v3.0/gb/gbunrAFVOHPwl2npUgKv_C3f_qiJnZDd9zG5-h3jrpo.cache +1 -0
  52. data/test/dummy/tmp/cache/assets/sprockets/v3.0/hZ/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +2 -0
  53. data/test/dummy/tmp/cache/assets/sprockets/v3.0/j0/j06P5zp022n2VUoAPi5fqCp_UbS7OaCD8XtVtEbHy58.cache +0 -0
  54. data/test/dummy/tmp/cache/assets/sprockets/v3.0/mv/mvqN6PphkrOOC8zbUEhpC_9E_4ybdO25MRy_gG6dq3Y.cache +1 -0
  55. data/test/dummy/tmp/cache/assets/sprockets/v3.0/nm/nmcUZlKAIwyJ_35Nm9P8pukLeRX5aApP6NFj5MpNPgc.cache +1 -0
  56. data/test/dummy/tmp/cache/assets/sprockets/v3.0/pE/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +2 -0
  57. data/test/dummy/tmp/cache/assets/sprockets/v3.0/sB/sB6xWxBmgzVC0Co9__ANYrE58lr4WPwiwFa9mswooWM.cache +0 -0
  58. data/test/dummy/tmp/cache/assets/sprockets/v3.0/va/vaNrIny9hchHD9eIJxAicyYLC7qeV4PTh4Nh40_Y6Vg.cache +1 -0
  59. data/test/dummy/tmp/cache/assets/sprockets/v3.0/x6/x6W7JXRDHOmqATQMRSTLu17o8EcA-ietA1qm_PMPjbo.cache +0 -0
  60. data/test/dummy/tmp/cache/assets/sprockets/v3.0/xd/xdBKQyhEAlDIstGvXw945PWJoEWi23rKuY7elOcWqHc.cache +1 -0
  61. data/test/generator_test.rb +4 -4
  62. data/test/policy_test.rb +62 -0
  63. data/test/test_helper.rb +5 -16
  64. data/test/view_test.rb +6 -17
  65. metadata +63 -32
  66. data/lib/abilities/action_controller/base.rb +0 -20
  67. data/lib/abilities/action_view/base.rb +0 -14
  68. data/lib/abilities/concern.rb +0 -12
  69. data/lib/abilities/configuration.rb +0 -13
  70. data/lib/generators/abilities/install_generator.rb +0 -13
  71. data/test/changes_test.rb +0 -12
  72. data/test/checking_test.rb +0 -64
  73. data/test/controller_test.rb +0 -38
  74. data/test/dummy/README.rdoc +0 -28
  75. data/test/dummy/app/models/post.rb +0 -3
  76. data/test/dummy/config/initializers/abilities.rb +0 -7
  77. data/test/dummy/config/initializers/secret_token.rb +0 -1
  78. data/test/dummy/db/migrate/20140629203412_create_posts.rb +0 -10
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73ae248bbe708f9a398a788c4db88773f66bbf08
4
- data.tar.gz: c59fcc7224d4493496754293d535d2e35e28a5b4
3
+ metadata.gz: d2bc9ac0cfbd40fc108a5cd619f54e7844096292
4
+ data.tar.gz: 1e8aa0c9839cad844c4b540e663124e070cbfe63
5
5
  SHA512:
6
- metadata.gz: ad7edc77a9356754a83df963fa96ff53fb677e89a3cbab259b68465973bbf581b594cf40c52fcd0edf663be587471816e3628943ec2940f94a50b7221f941687
7
- data.tar.gz: 55d7a75da416b82320cb3fb36c5d8499ed478485d03baf4c5aab7ed74e06d0e34c37d66e42d1f4a083fdca262346a03712a2b2ea26f1409c85f92310da14f47a
6
+ metadata.gz: 1b83c49c8ce1332ca10d8b9dcee7d1415572ed39cc849a2801b5970176fc3b8f5095d822d4fa8560f53b8133f568bd403e98b763df67456c075e3a79910a5e32
7
+ data.tar.gz: 32d1b4733cf942cf5247110c5790b9c093eb7212febdf11ca1d0ec8f17f44b7ec32710f4e9907dabe3ce1753f9706c1b4c171ad3f6fb7d88fc54c2b4935fc3e5
@@ -1,4 +1,4 @@
1
- Copyright 2015 Mathías Montossi
1
+ Copyright 2016 Mathías Montossi
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -5,7 +5,14 @@
5
5
 
6
6
  # Abilities
7
7
 
8
- Minimalistic authorization inspired in cancan for rails.
8
+ Authorization dsl to manage permissions in rails.
9
+
10
+ ## Why
11
+
12
+ I did this gem to:
13
+
14
+ - Use a dsl instead of a plain class to simplify the syntax.
15
+ - Limit authorizations to only controllers and their views.
9
16
 
10
17
  ## Install
11
18
 
@@ -21,65 +28,45 @@ $ bundle
21
28
 
22
29
  ## Configuration
23
30
 
24
- Generate the abilities configuration file:
31
+ Generate the definitions file:
25
32
  ```
26
33
  bundle exec rails g abilities:install
27
34
  ```
28
35
 
29
- Define the user fetcher for your controllers and views:
36
+ Ensure there is a current_user method in your controllers:
30
37
  ```ruby
31
- Abilities.configure do |config|
32
- config.fetcher do
33
- current_user
38
+ class ApplicationController < ActionController::Base
39
+ def current_user
40
+ @current_user ||= User.find(session[:user_id])
34
41
  end
35
42
  end
36
43
  ```
37
44
 
38
- Add the abilities concern to the model if you want to call can? and cannot? in the user instance:
39
- ```ruby
40
- class User < ActiveRecord::Base
41
- include Abilities::Concern
42
- end
43
- ```
44
-
45
45
  ## Usage
46
46
 
47
- ### Defining
47
+ ### Definitions
48
48
 
49
- All the abilities are defined in config/abilities.rb by can and cannot methods:
49
+ Use can and cannot methods to define the policies:
50
50
  ```ruby
51
51
  Abilities.define do
52
- can :create, Post
53
- cannot :destroy, User unless admin?
54
- can :edit, Post do |subject|
55
- subject.user == self
52
+ can :view, :any
53
+ can :manage, User do |user|
54
+ user == self
56
55
  end
57
- can :manage, User
58
- can :touch, :all
56
+ can :detroy, Product if admin?
59
57
  end
60
58
  ```
61
59
 
62
- If you want to load the abilities from the database you may do something like this:
63
- ```ruby
64
- Abilities.define do
65
- permissions.each do |permission|
66
- can premissions.action, permissions.subject
67
- end
68
- end
69
- ```
60
+ NOTE: Methods besides can and cannot are sent to the current_user.
70
61
 
71
- NOTE: Any method besides can and cannot references the user instance.
72
-
73
- ### Checking
74
-
75
- #### Controllers
62
+ ### Controllers
76
63
 
77
64
  With the authorize! method Abilities::AccessDenied is raised if authorization fails:
78
65
  ```ruby
79
- class PostsController < ApplicationController
66
+ class UsersController < ApplicationController
80
67
  def edit
81
- @post = Post.find(params[:id])
82
- authorize! :edit, @post
68
+ @user = User.find(params[:id])
69
+ authorize! :edit, @user
83
70
  end
84
71
  end
85
72
  ```
@@ -88,9 +75,9 @@ If you don't want an exception to be raised use can? and cannot? helpers:
88
75
  ```ruby
89
76
  class UsersController < ApplicationController
90
77
  def edit
91
- @post = Post.find(params[:id])
92
- if can? :edit, @post
93
- @post.update post_params
78
+ @user = User.find(params[:id])
79
+ if can?(:edit, @user)
80
+ @user.update post_params
94
81
  else
95
82
  # handle access denied
96
83
  end
@@ -98,12 +85,12 @@ class UsersController < ApplicationController
98
85
  end
99
86
  ```
100
87
 
101
- #### Views
88
+ ### Views
102
89
 
103
- The helpers can? and cannot? are available here too:
90
+ The helpers can? and cannot? are available in the controller views too:
104
91
  ```erb
105
- <% if can? :create, Post %>
106
- <%= link_to new_post_path %>
92
+ <% if can?(:detroy, @product) %>
93
+ <%= link_to product_path(@product), method: 'delete' %>
107
94
  <% end %>
108
95
  ```
109
96
 
data/Rakefile CHANGED
@@ -4,19 +4,6 @@ rescue LoadError
4
4
  puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
5
  end
6
6
 
7
- require 'rdoc/task'
8
-
9
- RDoc::Task.new(:rdoc) do |rdoc|
10
- rdoc.rdoc_dir = 'rdoc'
11
- rdoc.title = 'Abilities'
12
- rdoc.options << '--line-numbers'
13
- rdoc.rdoc_files.include('README.rdoc')
14
- rdoc.rdoc_files.include('lib/**/*.rb')
15
- end
16
-
17
-
18
-
19
-
20
7
  Bundler::GemHelper.install_tasks
21
8
 
22
9
  require 'rake/testtask'
@@ -26,7 +13,7 @@ Rake::TestTask.new(:test) do |t|
26
13
  t.libs << 'test'
27
14
  t.pattern = 'test/**/*_test.rb'
28
15
  t.verbose = false
16
+ t.warning = false
29
17
  end
30
18
 
31
-
32
19
  task default: :test
@@ -1,33 +1,24 @@
1
- require 'abilities/action_controller/base'
2
- require 'abilities/action_view/base'
3
- require 'abilities/proxy'
4
- require 'abilities/configuration'
1
+ require 'abilities/extensions/action_controller/base'
5
2
  require 'abilities/definitions'
6
3
  require 'abilities/exceptions'
7
- require 'abilities/concern'
4
+ require 'abilities/proxy'
8
5
  require 'abilities/railtie'
6
+ require 'abilities/version'
9
7
 
10
8
  module Abilities
11
9
  class << self
12
10
 
13
- def configure
14
- yield configuration
15
- end
16
-
17
- def configuration
18
- @configuration ||= Configuration.new
19
- end
11
+ attr_reader :block
20
12
 
21
13
  def define(&block)
22
14
  @block = block
23
15
  end
24
16
 
25
- def can?(actor, action, subject)
26
- Definitions.new(actor, &@block).can?(action, subject)
27
- end
28
-
29
- def cannot?(*args)
30
- !can?(*args)
17
+ %i(can? cannot?).each do |name|
18
+ define_method name do |user, action, resource|
19
+ definitions = Definitions.new(user, &block)
20
+ definitions.send name, action, resource
21
+ end
31
22
  end
32
23
 
33
24
  end
@@ -1,31 +1,23 @@
1
1
  module Abilities
2
2
  class Definitions
3
3
 
4
- def initialize(actor, &block)
5
- @actor = actor
6
- Proxy.new(actor, self, &block)
7
- end
4
+ attr_reader :user
8
5
 
9
- def add(actions, subjects, behavior, &block)
10
- actions = [actions] unless actions.is_a? Array
11
- subjects = [subjects] unless subjects.is_a? Array
12
- subjects.each do |subject|
13
- actions.each do |action|
14
- (all[find_subject_id(subject)] ||= {})[action.to_s] = block_given? ? block : behavior
15
- end
16
- end
6
+ def initialize(user, &block)
7
+ @user = user
8
+ Proxy.new self, &block
17
9
  end
18
10
 
19
- def can?(action, subject)
20
- subject_id = find_subject_id(subject)
21
- if subject_id != 'all' and can?(action, 'all')
11
+ def can?(action, resource)
12
+ id = resource_id(resource)
13
+ if id != :any && can?(action, :any)
22
14
  true
23
- elsif actions = all[subject_id]
24
- if behavior = (actions[action.to_s] || actions['manage'])
25
- if behavior.is_a? Proc
26
- @actor.instance_exec subject, &behavior
15
+ elsif actions = registry[id]
16
+ if policy = (actions[action] || actions[:manage])
17
+ if policy.is_a?(Proc)
18
+ user.instance_exec resource, &policy
27
19
  else
28
- behavior
20
+ policy
29
21
  end
30
22
  else
31
23
  false
@@ -39,19 +31,36 @@ module Abilities
39
31
  !can?(*args)
40
32
  end
41
33
 
42
- protected
34
+ def add(actions, resources, policy)
35
+ unless actions.is_a?(Array)
36
+ actions = [actions]
37
+ end
38
+ unless resources.is_a?(Array)
39
+ resources = [resources]
40
+ end
41
+ resources.each do |resource|
42
+ actions.each do |action|
43
+ id = resource_id(resource)
44
+ registry[id] ||= {}
45
+ registry[id][action] = policy
46
+ end
47
+ end
48
+ end
49
+
50
+ private
43
51
 
44
- def all
45
- @all ||= {}
52
+ def registry
53
+ @registry ||= {}
46
54
  end
47
55
 
48
- def find_subject_id(subject)
49
- if subject.to_s == 'all'
50
- subject.to_s
51
- elsif subject.is_a? Class
52
- subject.name
56
+ def resource_id(resource)
57
+ case resource
58
+ when :any
59
+ resource
60
+ when Class
61
+ resource.name.underscore.to_sym
53
62
  else
54
- subject.class.name
63
+ resource.class.name.underscore.to_sym
55
64
  end
56
65
  end
57
66
 
@@ -0,0 +1,28 @@
1
+ module Abilities
2
+ module Extensions
3
+ module ActionController
4
+ module Base
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ helper_method :can?, :cannot?
9
+ end
10
+
11
+ %w(can? cannot?).each do |name|
12
+ define_method name do |action, resource|
13
+ Abilities.send name, current_user, action, resource
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def authorize!(action, subject)
20
+ if cannot?(action, subject)
21
+ raise Abilities::AccessDenied
22
+ end
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,22 +1,21 @@
1
1
  module Abilities
2
2
  class Proxy
3
3
 
4
- def initialize(actor, definitions, &block)
5
- @actor = actor
4
+ def initialize(definitions, &block)
6
5
  @definitions = definitions
7
6
  instance_eval &block
8
7
  end
9
8
 
10
- def can(actions, subjects, &block)
11
- @definitions.add actions, subjects, true, &block
9
+ def can(actions, resources, &block)
10
+ @definitions.add actions, resources, (block_given? ? block : true)
12
11
  end
13
12
 
14
- def cannot(actions, subjects, &block)
15
- @definitions.add actions, subjects, false, &block
13
+ def cannot(actions, resources, &block)
14
+ @definitions.add actions, resources, (block_given? ? block : false)
16
15
  end
17
16
 
18
17
  def method_missing(name, *args, &block)
19
- @actor.send name, *args, &block
18
+ @definitions.user.send name, *args, &block
20
19
  end
21
20
 
22
21
  end
@@ -1,9 +1,10 @@
1
1
  module Abilities
2
2
  class Railtie < Rails::Railtie
3
3
 
4
- initializer 'abilites' do
5
- ::ActionView::Base.send :include, Abilities::ActionView::Base
6
- ::ActionController::Base.send :include, Abilities::ActionController::Base
4
+ initializer 'abilites.extensions' do
5
+ ::ActionController::Base.include(
6
+ Abilities::Extensions::ActionController::Base
7
+ )
7
8
  end
8
9
 
9
10
  config.after_initialize do
@@ -1,5 +1,5 @@
1
1
  module Abilities
2
2
 
3
- VERSION = '0.1.2'
3
+ VERSION = '4.0.0.0'
4
4
 
5
5
  end
@@ -0,0 +1,15 @@
1
+ require 'rails/generators'
2
+
3
+ module Abilities
4
+ module Generators
5
+ class InstallGenerator < ::Rails::Generators::Base
6
+
7
+ source_root File.expand_path('../templates', __FILE__)
8
+
9
+ def create_configuration_file
10
+ copy_file 'configuration.rb', 'config/abilities.rb'
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -2,5 +2,4 @@
2
2
  # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3
3
 
4
4
  require File.expand_path('../config/application', __FILE__)
5
-
6
5
  Rails.application.load_tasks
@@ -2,12 +2,12 @@
2
2
  // listed below.
3
3
  //
4
4
  // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
- // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
6
  //
7
7
  // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
8
  // compiled file.
9
9
  //
10
- // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
10
+ // Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
11
11
  // about supported directives.
12
12
  //
13
13
  //= require_tree .
@@ -3,7 +3,7 @@
3
3
  * listed below.
4
4
  *
5
5
  * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
- * or vendor/assets/stylesheets of plugins, if any, can be referenced here using a relative path.
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
7
  *
8
8
  * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
9
  * compiled file so the styles you add here take precedence over styles defined in any styles
@@ -0,0 +1,10 @@
1
+ class ProductsController < ApplicationController
2
+
3
+ attr_accessor :current_user
4
+
5
+ def show
6
+ @current_user = User.new
7
+ @product = Product.new
8
+ end
9
+
10
+ end