abilities 0.1.2 → 4.0.0.0

Sign up to get free protection for your applications and to get access to all the features.
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