simon_says 0.1.6 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: eb74ffaa3fbf69fbab2c3534393df41d91f8fccd
4
- data.tar.gz: 8c96349d0aa76b9617b095cb17a4e91d05bd3829
3
+ metadata.gz: 6c3b6bd7983eb136f044c2653430143493637871
4
+ data.tar.gz: a66d00fe12a96f48e8865a61aaf61f145feb5007
5
5
  SHA512:
6
- metadata.gz: 71da79481390650b93d0045f379206ed05a1882de58afdb603a88f7996ce717e9fd46941ece13ac926d5901411e9435731760d0d3511194f90df0bf32efe6920
7
- data.tar.gz: 0c8e4ff2fcc7a0932d0a794e48fb3382c3d083d65b0cf53a326adcbaf2e2e1d23a919354b3c81682b24ce5ca229580da29460dc25f51e26b09534059dd27d6c8
6
+ metadata.gz: 284e3a2a74a36d1ae52aa78849a347f38071b4c5838dc43b60cdba794fd9bed021054941b44b44d28744511a3af57eb6764108ae087b7bf1d17e96b03f1f1e8a
7
+ data.tar.gz: dea0bc94572281d6b505ef4a3eb2ed0fb502e916483e122cf19f34444dfaf12947e374065495f2b2edd3c8a0e370b45a5454a1075c56daec896f642a02ae451e
data/README.md CHANGED
@@ -4,22 +4,12 @@
4
4
  Logo](https://raw.githubusercontent.com/SimplyBuilt/SimonSays/master/SimonSays.png)
5
5
 
6
6
  This gem is a simple, declarative, role-based access control system for
7
- Rails that works great with devise! Take a look at the
8
- [docs](http://www.rubydoc.info/github/SimplyBuilt/SimonSays/) for more
9
- details.
7
+ Rails that works great with devise!
10
8
 
11
9
  [![Travis Build Status](https://travis-ci.org/SimplyBuilt/SimonSays.svg)](https://travis-ci.org/SimplyBuilt/SimonSays)
12
10
  [![Gem Version](https://badge.fury.io/rb/simon_says.svg)](https://badge.fury.io/rb/simon_says)
13
11
  [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)
14
12
 
15
- ## About
16
-
17
- A ruby gem for simple, declarative, role-based access control system for
18
- [Rails](https://github.com/rails/rails) that works great with
19
- [Devise](https://github.com/plataformatec/devise)! Take a look at the
20
- [docs](http://www.rubydoc.info/github/SimplyBuilt/SimonSays/) for more
21
- details!
22
-
23
13
  ### Installation
24
14
 
25
15
  SimonSays can be installed via your Gemfile or using Ruby gems directly.
@@ -32,23 +22,24 @@ gem 'simon_says'
32
22
 
33
23
  SimonSays consists of two parts:
34
24
 
35
- 1. A [Roleable](#roleable) concern provides a way to define access roles
36
- on a given resource, such as User or on join through model.
37
- 2. An [Authorizer](#authorizer) concern which provides a lightweight,
38
- declarative API to controllers for finding and authorizing these
39
- resources in relation to an already authenticated resource, like a
40
- User or Admin.
25
+ 1. A [Roleable](#roleable) concern which provides a way to define access roles
26
+ on User models or on join through models.
27
+ 2. An [Authorizer](#authorizer) concern which provides a declarative API
28
+ to controllers for finding and authorizing model resources.
41
29
 
42
30
  #### Roleable
43
31
 
44
- First, we need to define some roles. Generally speaking roles will exist
45
- on either "User" models or on relationship models (such as a through
46
- model linking a User to another resource). Roles are stored as an
32
+ First, we need to define some roles on a model. Roles are stored as an
47
33
  integer and [bitmasking](https://en.wikipedia.org/wiki/Mask_(computing))
48
- is used to determine authorization logic. When using `Roleable` you need
49
- to add a `roles_mask` column to the model.
34
+ is used to determine the roles assigned for that model. SimonSays
35
+ provides a generator for creating a new migration for this required
36
+ attribute:
37
+
38
+ ```bash
39
+ rails g active_record:simon_says User
40
+ ```
50
41
 
51
- For example:
42
+ Now we can define some roles in our User model. For example:
52
43
 
53
44
  ```ruby
54
45
  class User < ActiveRecord::Base
@@ -87,12 +78,19 @@ end
87
78
  # => [:support]
88
79
  ```
89
80
 
81
+ Make sure to generate a migration using the correct attribute name if
82
+ `:as` is used. For example:
83
+
84
+ ```bash
85
+ rails g active_record:simon_says Admin access
86
+ ```
87
+
90
88
  We can also use `has_roles` to define roles on a join through model
91
89
  which is used to associate a User with a resource.
92
90
 
93
91
  ```ruby
94
92
 
95
- class Membership < ActiveRecord::Base
93
+ class Permission < ActiveRecord::Base
96
94
  include SimonSays::Roleable
97
95
 
98
96
  belongs_to :user
@@ -101,20 +99,20 @@ class Membership < ActiveRecord::Base
101
99
  has_roles :download, :edit, :delete,
102
100
  end
103
101
 
104
- # > Membership.new(roles: Membership::ROLES).roles
102
+ # > Permission.new(roles: Permission::ROLES).roles
105
103
  # => [:download, :edit, :delete]
106
104
  ```
107
105
 
108
106
  It is useful to note the dynamically generated `has_` methods as shown
109
107
  in the User model as well the `ROLES` constant which is used in the
110
- Membership example. Take a look at the [roleable source
111
- code](https://github.com/SimplyBuilt/SimonSays/blob/master/lib/simon_says/roleable.rb)
112
- to see how features are dynamically generated when using `has_roles`.
108
+ Permission example. Take a look at the `Roleable`
109
+ [source code](https://github.com/SimplyBuilt/SimonSays/blob/master/lib/simon_says/roleable.rb)
110
+ to see how features are dynamically generated with `has_roles`.
113
111
 
114
112
  #### Authorizer
115
113
 
116
114
  The `Authorizer` concern provides several methods that can be used within
117
- your controllers in declarative manner.
115
+ your controllers in a declarative manner.
118
116
 
119
117
  Please note, certain assumptions are made with `Authorizer`. Building
120
118
  upon the above User and Admin model examples, `Authorizer` would assume
@@ -138,7 +136,8 @@ to be used in controllers. All of these methods accept the `:only` and
138
136
  - `authorize_resource(resource, *roles)`: Authorize resource for given
139
137
  roles
140
138
  - `find_and_authorize(resource, *roles)`: Find a resource and then try
141
- authorize it for the given roles
139
+ authorize it for the given roles. If successful, the resource is
140
+ assigned to an instance variable
142
141
 
143
142
  When find resources, the `default_authorization_scope` is used. It can
144
143
  be customized on a per-controller basis. For example:
@@ -154,22 +153,23 @@ end
154
153
  To authorize resources against a given role, we use either `authorize`
155
154
  or `find_and_authorize`. For example, consider this
156
155
  `DocumentsController` which uses an authenticated `User` resource and a
157
- `Membership` through model:
156
+ `Permission` through model:
158
157
 
159
158
  ```ruby
160
159
  class DocumentsController < ApplicationController
161
160
  authenticate :user
162
161
 
163
- find_and_authorize :documents, :edit, through: :memberships, only: [:edit, :update]
164
- find_and_authorize :documents, :delete, through: :memberships, only: :destroy
162
+ find_and_authorize :document, :edit, through: :permissions, only: [:edit, :update]
163
+ find_and_authorize :document, :delete, through: :permissions, only: :destroy
165
164
  end
166
165
  ```
167
166
 
168
- This controller will find Document resources and assign them to the
167
+ This controller will find a Document resource and assign it to the
169
168
  `@document` instance variable. For the `:edit` and `:update` actions,
170
- it'll require membership with an `:edit` role. For the `:destroy` method, a
171
- memberships with the `:delete` role is required. It is possible for a
172
- given User to have both, one, or neither of those roles.
169
+ it'll require a permission with an `:edit` role. For the `:destroy`
170
+ method, a permission with the `:delete` role is required. Since the
171
+ `:through` option is used, a `@permission` instance variable will also
172
+ be created.
173
173
 
174
174
  The `find_resource` method may raise an `ActiveRecord::RecordNotFound`
175
175
  exception. The `authorize` method may raise a
@@ -177,7 +177,7 @@ exception. The `authorize` method may raise a
177
177
  access. As a result, the `find_and_authorize` method may raise either
178
178
  exception.
179
179
 
180
- We can also use a different authorization scope by via the `:from`
180
+ We can also use a different authorization scope with the `:from`
181
181
  option for `find_resource` and `find_and_authorize`. For example:
182
182
 
183
183
  ```ruby
@@ -0,0 +1,23 @@
1
+ require 'rails/generators/active_record'
2
+
3
+ module ActiveRecord
4
+ module Generators
5
+ class SimonSaysGenerator < ActiveRecord::Generators::Base
6
+ source_root File.expand_path("../templates", __FILE__)
7
+
8
+ def copy_simon_says_migration
9
+ migration_template "migration.rb", "db/migrate/simon_says_add_to_#{table_name}.rb"
10
+ end
11
+
12
+ private
13
+
14
+ def migration_version
15
+ "[#{Rails::VERSION::MAJOR}.#{Rails::VERSION::MINOR}]" if Rails.version >= '5.0.0'
16
+ end
17
+
18
+ def role_attribute_name
19
+ args.first || 'roles'
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ class SimonSaysAddTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migration_version %>
2
+ def change
3
+ add_column :<%= table_name %>, :<%= role_attribute_name %>_mask, :integer, default: 0, null: false
4
+ end
5
+ end
@@ -151,11 +151,6 @@ module SimonSays
151
151
  name = options[:resource]
152
152
  end
153
153
 
154
- attr = Roleable.registry[name]
155
-
156
- required ||= options[attr.to_sym]
157
- required = [required] unless Array === required
158
-
159
154
  record = instance_variable_get("@#{name}")
160
155
 
161
156
  if record.nil? # must be devise scope
@@ -163,12 +158,16 @@ module SimonSays
163
158
  send "authenticate_#{name}!"
164
159
  end
165
160
 
166
- actual = record.send(attr)
161
+ role_attr = record.class.role_attribute_name
162
+ actual = record.send(role_attr)
163
+
164
+ required ||= options[role_attr]
165
+ required = [required] unless Array === required
167
166
 
168
167
  # actual roles must have at least
169
168
  # one required role (array intersection)
170
169
  ((required & actual).size > 0).tap do |res|
171
- raise Denied.new(attr, required, actual) unless res
170
+ raise Denied.new(role_attr, required, actual) unless res
172
171
  end
173
172
  end
174
173
 
@@ -187,7 +186,6 @@ module SimonSays
187
186
 
188
187
  else
189
188
  klass = (options[:class_name] || resource).to_s
190
- # TODO support array of namespaces?
191
189
  klass = "#{options[:namespace]}/#{klass}" if options[:namespace]
192
190
 
193
191
  scope = klass.classify.constantize
@@ -2,11 +2,6 @@ module SimonSays
2
2
  module Roleable
3
3
  extend ActiveSupport::Concern
4
4
 
5
- def self.registry # :nodoc:
6
- # "global" registry we'll use when authorizing
7
- @registry ||= {}
8
- end
9
-
10
5
  module ClassMethods
11
6
  # Provides a declarative method to introduce role based
12
7
  # access controller through a give integer mask.
@@ -65,8 +60,6 @@ module SimonSays
65
60
  singular = name.singularize
66
61
  const = name.upcase
67
62
 
68
- Roleable.registry[model_name.to_s.downcase.to_sym] ||= name
69
-
70
63
  roles.map!(&:to_sym)
71
64
 
72
65
  class_eval <<-RUBY_EVAL, __FILE__, __LINE__
@@ -88,6 +81,10 @@ module SimonSays
88
81
  def has_#{name}?(*args)
89
82
  (#{name} & args).size > 0
90
83
  end
84
+
85
+ def self.role_attribute_name
86
+ :#{name}
87
+ end
91
88
  RUBY_EVAL
92
89
 
93
90
  if name != singular
@@ -1,3 +1,3 @@
1
1
  module SimonSays
2
- VERSION = '0.1.6'
2
+ VERSION = '0.2.0'
3
3
  end
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
22
22
 
23
23
  spec.add_development_dependency "bundler", "~> 1.9"
24
24
  spec.add_development_dependency "rake", "~> 10.0"
25
- spec.add_development_dependency "rails", ">= 4.0", "< 5.1"
25
+ spec.add_development_dependency "rails", ">= 4.0", "< 5.2"
26
26
  spec.add_development_dependency "responders", "~> 2.0"
27
27
  spec.add_development_dependency "mocha", "~> 1.1"
28
28
  end
@@ -9,13 +9,13 @@ class DocumentsController < ApplicationController
9
9
  find_and_authorize :document, :download, through: :memberships, only: :send_file
10
10
 
11
11
  def index
12
- @documents = Document.all
12
+ @documents = current_user.documents
13
13
 
14
14
  respond_with @documents
15
15
  end
16
16
 
17
17
  def create
18
- @document = Document.create(document_params)
18
+ @document = current_user.documents.create(document_params)
19
19
 
20
20
  respond_with @document
21
21
  end
@@ -13,35 +13,35 @@
13
13
  ActiveRecord::Schema.define(version: 20160823220959) do
14
14
 
15
15
  create_table "admin_reports", force: :cascade do |t|
16
- t.string "title"
16
+ t.string "title"
17
17
  t.datetime "created_at", null: false
18
18
  t.datetime "updated_at", null: false
19
19
  end
20
20
 
21
21
  create_table "admins", force: :cascade do |t|
22
- t.integer "access_mask"
23
- t.datetime "created_at", null: false
24
- t.datetime "updated_at", null: false
22
+ t.integer "access_mask"
23
+ t.datetime "created_at", null: false
24
+ t.datetime "updated_at", null: false
25
25
  end
26
26
 
27
27
  create_table "documents", force: :cascade do |t|
28
- t.string "title"
28
+ t.string "title"
29
29
  t.datetime "created_at", null: false
30
30
  t.datetime "updated_at", null: false
31
31
  end
32
32
 
33
33
  create_table "images", force: :cascade do |t|
34
- t.string "token"
34
+ t.string "token"
35
35
  t.datetime "created_at", null: false
36
36
  t.datetime "updated_at", null: false
37
37
  end
38
38
 
39
39
  create_table "memberships", force: :cascade do |t|
40
- t.integer "user_id"
41
- t.integer "document_id"
42
- t.integer "roles_mask", default: 0
43
- t.datetime "created_at", null: false
44
- t.datetime "updated_at", null: false
40
+ t.integer "user_id"
41
+ t.integer "document_id"
42
+ t.integer "roles_mask", default: 0
43
+ t.datetime "created_at", null: false
44
+ t.datetime "updated_at", null: false
45
45
  t.index ["document_id"], name: "index_memberships_on_document_id"
46
46
  t.index ["user_id"], name: "index_memberships_on_user_id"
47
47
  end
@@ -144,11 +144,11 @@ class RoleableTest < ActiveSupport::TestCase
144
144
  ]
145
145
  end
146
146
 
147
- test "Membership is added to registry" do
148
- assert_includes SimonSays::Roleable.registry, :membership
147
+ test "Membership defines role_attribute_name" do
148
+ assert_equal :roles, Membership.role_attribute_name
149
149
  end
150
150
 
151
- test "Admin is added to registry" do
152
- assert_includes SimonSays::Roleable.registry, :admin
151
+ test "Admin defines role_attribute_name" do
152
+ assert_equal :access, Admin.role_attribute_name
153
153
  end
154
154
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simon_says
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Coyne
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2017-09-18 00:00:00.000000000 Z
13
+ date: 2017-10-07 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport
@@ -63,7 +63,7 @@ dependencies:
63
63
  version: '4.0'
64
64
  - - "<"
65
65
  - !ruby/object:Gem::Version
66
- version: '5.1'
66
+ version: '5.2'
67
67
  type: :development
68
68
  prerelease: false
69
69
  version_requirements: !ruby/object:Gem::Requirement
@@ -73,7 +73,7 @@ dependencies:
73
73
  version: '4.0'
74
74
  - - "<"
75
75
  - !ruby/object:Gem::Version
76
- version: '5.1'
76
+ version: '5.2'
77
77
  - !ruby/object:Gem::Dependency
78
78
  name: responders
79
79
  requirement: !ruby/object:Gem::Requirement
@@ -120,6 +120,8 @@ files:
120
120
  - README.md
121
121
  - Rakefile
122
122
  - SimonSays.png
123
+ - lib/generators/active_record/simon_says_generator.rb
124
+ - lib/generators/active_record/templates/migration.rb
123
125
  - lib/simon_says.rb
124
126
  - lib/simon_says/authorizer.rb
125
127
  - lib/simon_says/roleable.rb
@@ -234,7 +236,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
234
236
  version: '0'
235
237
  requirements: []
236
238
  rubyforge_project:
237
- rubygems_version: 2.6.12
239
+ rubygems_version: 2.6.13
238
240
  signing_key:
239
241
  specification_version: 4
240
242
  summary: Light-weight, declarative authorization and access control for Rails