petergate 3.0.1 → 3.1.1
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 +4 -4
- data/.gitignore +2 -2
- data/.ruby-version +1 -1
- data/Gemfile +13 -40
- data/README.md +113 -30
- data/Rakefile +5 -2
- data/lib/generators/petergate/install_generator.rb +0 -1
- data/lib/petergate/action_controller/base.rb +30 -4
- data/lib/petergate/active_record/base.rb +12 -5
- data/lib/petergate/version.rb +1 -1
- data/lib/templates/rails/scaffold_controller/controller.rb +10 -11
- data/petergate.gemspec +27 -4
- metadata +55 -12
- data/.travis.yml +0 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: acd5072223d85700246df5acd1445b292a918cf85a3b51b4ee42ae03c3648630
|
|
4
|
+
data.tar.gz: d084364761c8234ac5db4cc4434e88337913f07dea42cf7d2d3fdc15b3b8261d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ffef6582b1bcd3d55d01c4655dff65a7d12ee47fbefeb32ba2339911db89827923a05e876396261c00849f966ecb36b3470247c057eb99dc60cf0822c8ee26f5
|
|
7
|
+
data.tar.gz: 9c4e7e84b9e07811651f6cd172f4b32b92540bd47a24a2ec986f028d64b7a3786d3a800aefe879f9d81f04700360a05f007d36148a22dea8b80b5456cc2d938e
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.2.0
|
data/Gemfile
CHANGED
|
@@ -1,43 +1,16 @@
|
|
|
1
|
-
source
|
|
2
|
-
ruby '3.2.0'
|
|
1
|
+
source "https://rubygems.org"
|
|
3
2
|
|
|
4
|
-
#
|
|
3
|
+
# Declares the runtime dependencies.
|
|
5
4
|
gemspec
|
|
6
|
-
# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
|
|
7
|
-
gem 'rails', '~> 6.0.3.4'
|
|
8
|
-
|
|
9
|
-
# Use sqlite3 as the database for Active Record
|
|
10
|
-
gem 'sqlite3'
|
|
11
|
-
# Use SCSS for stylesheets
|
|
12
|
-
gem 'sass-rails', '~> 5.0.4'
|
|
13
|
-
# Use Uglifier as compressor for JavaScript assets
|
|
14
|
-
gem 'uglifier', '>= 1.3.0'
|
|
15
|
-
# See https://github.com/sstephenson/execjs#readme for more supported runtimes
|
|
16
|
-
# gem 'therubyracer', platforms: :ruby
|
|
17
|
-
|
|
18
|
-
# Use jquery as the JavaScript library
|
|
19
|
-
gem 'jquery-rails'
|
|
20
|
-
# Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks
|
|
21
|
-
gem 'turbolinks'
|
|
22
|
-
gem "minitest-rails", "~> 6.0.1"
|
|
23
|
-
gem "minitest-reporters"
|
|
24
|
-
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
|
|
25
|
-
gem 'jbuilder', '~> 2.0'
|
|
26
|
-
# bundle exec rake doc:rails generates the API under doc/api.
|
|
27
|
-
gem 'sdoc', '~> 0.4.0', group: :doc
|
|
28
|
-
|
|
29
|
-
# Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
|
|
30
|
-
gem 'devise'
|
|
31
|
-
|
|
32
|
-
# Use ActiveModel has_secure_password
|
|
33
|
-
# gem 'bcrypt', '~> 3.1.7'
|
|
34
|
-
|
|
35
|
-
# Use unicorn as the app server
|
|
36
|
-
# gem 'unicorn'
|
|
37
|
-
|
|
38
|
-
# Use Capistrano for deployment
|
|
39
|
-
# gem 'capistrano-rails', group: :development
|
|
40
|
-
|
|
41
|
-
# Use debugger
|
|
42
|
-
# gem 'debugger', group: [:development, :test]
|
|
43
5
|
|
|
6
|
+
# The default development target. gemfiles/ holds the CI matrix across the
|
|
7
|
+
# supported Rails versions. The suite boots a minimal Rails app instead of a
|
|
8
|
+
# dummy app, so it needs the full framework plus a database to talk to.
|
|
9
|
+
gem "rails", "~> 8.1"
|
|
10
|
+
gem "sqlite3", "~> 2.0"
|
|
11
|
+
gem "rake", ">= 13.0"
|
|
12
|
+
|
|
13
|
+
# Devise is not a dependency of the gem -- petergate only needs the three
|
|
14
|
+
# authentication methods the README documents. It is here so one test can prove
|
|
15
|
+
# a real Devise app satisfies that contract.
|
|
16
|
+
gem "devise"
|
data/README.md
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
|
-
[](https://github.com/elorest/petergate)
|
|
2
2
|
|
|
3
|
-
[](https://gitter.im/isaacsloan/petergate?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
|
3
|
+
[](https://github.com/elorest/petergate/actions/workflows/ci.yml)
|
|
5
4
|
[](http://badge.fury.io/rb/petergate)
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
|
|
9
|
-
> If you like the straight forward and effective nature of [Strong Parameters](https://github.com/rails/strong_parameters) and suspect that [cancan](https://github.com/ryanb/cancan) might be overkill for your project then you'll love [Petergate's](https://github.com/
|
|
8
|
+
> If you like the straight forward and effective nature of [Strong Parameters](https://github.com/rails/strong_parameters) and suspect that [cancan](https://github.com/ryanb/cancan) might be overkill for your project then you'll love [Petergate's](https://github.com/elorest/petergate) easy to use and read action and content based authorizations.
|
|
10
9
|
>
|
|
11
10
|
> -- <cite>1 Peter 3:41</cite>
|
|
12
11
|
|
|
12
|
+
Requirements
|
|
13
|
+
------
|
|
14
|
+
Rails 7.1 through 8.1 on Ruby 3.2 through 3.4 are covered by CI. Older Rails
|
|
15
|
+
versions are permitted by the gemspec but are not verified.
|
|
16
|
+
|
|
13
17
|
Installation
|
|
14
18
|
------
|
|
15
19
|
##### Get the gem
|
|
@@ -27,16 +31,19 @@ Or install it yourself as:
|
|
|
27
31
|
|
|
28
32
|
##### Prerequisites: Setup Authentication (Devise)
|
|
29
33
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
and called User.
|
|
34
|
+
The generator writes into `app/models/user.rb`, so a model named `User` is the
|
|
35
|
+
supported setup.
|
|
33
36
|
|
|
34
|
-
If you're using [devise](https://github.com/
|
|
37
|
+
If you're using [devise](https://github.com/heartcombo/devise) you're in luck,
|
|
38
|
+
otherwise you'll have to add the following methods to your project:
|
|
35
39
|
|
|
36
40
|
current_user
|
|
37
41
|
after_sign_in_path_for(current_user)
|
|
38
42
|
authenticate_user!
|
|
39
43
|
|
|
44
|
+
You also need a `root` route: a refused visitor who isn't signed in is sent
|
|
45
|
+
there.
|
|
46
|
+
|
|
40
47
|
##### Run the generators
|
|
41
48
|
|
|
42
49
|
rails g petergate:install
|
|
@@ -60,18 +67,32 @@ petergate(roles: [:admin, :editor], multiple: false)
|
|
|
60
67
|
############################################################################################
|
|
61
68
|
```
|
|
62
69
|
|
|
70
|
+
With `multiple: false` the role is stored in the column as a plain string. With
|
|
71
|
+
`multiple: true` the roles are stored as a YAML array, so query them through the
|
|
72
|
+
generated scopes below rather than by matching the column directly.
|
|
73
|
+
|
|
63
74
|
##### Instance Methods
|
|
64
75
|
|
|
65
76
|
```ruby
|
|
66
77
|
user.role => :editor
|
|
67
78
|
user.roles => [:editor, :user]
|
|
68
79
|
user.roles=(v) #sets roles
|
|
69
|
-
user.available_roles => [:admin, :editor]
|
|
70
|
-
user.has_roles?(:admin, :
|
|
80
|
+
user.available_roles => [:admin, :editor, :user]
|
|
81
|
+
user.has_roles?(:admin, :editor) # true if the user has any of the roles passed in
|
|
82
|
+
user.has_role?(:admin) # alias of has_roles?
|
|
71
83
|
```
|
|
72
84
|
##### Class Methods
|
|
73
85
|
|
|
74
|
-
|
|
86
|
+
A scope is defined for each configured role, named `role_` plus the pluralized
|
|
87
|
+
role name:
|
|
88
|
+
|
|
89
|
+
```ruby
|
|
90
|
+
User.role_admins # => users holding :admin
|
|
91
|
+
User.role_editors # => users holding :editor
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
So `petergate(roles: [:admin, :teacher])` gives you `User.role_admins` and
|
|
95
|
+
`User.role_teachers`.
|
|
75
96
|
|
|
76
97
|
#### Controllers
|
|
77
98
|
|
|
@@ -84,26 +105,54 @@ access all: [:show, :index], user: {except: [:destroy]}, company_admin: :all
|
|
|
84
105
|
access [:all, :user] => [:show, :index]
|
|
85
106
|
```
|
|
86
107
|
|
|
108
|
+
The key is a role, or an array of roles. `all` covers everyone, including
|
|
109
|
+
visitors who aren't signed in. The value is one of:
|
|
110
|
+
|
|
111
|
+
| Value | Meaning |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `[:show, :index]` | just those actions |
|
|
114
|
+
| `:all` | every action on the controller |
|
|
115
|
+
| `{except: [:destroy]}` | every action except those |
|
|
116
|
+
|
|
117
|
+
`:root_admin` is not a rule you write -- a user holding it bypasses the rules
|
|
118
|
+
entirely.
|
|
119
|
+
|
|
120
|
+
Rules declared on a parent controller are inherited by its subclasses, so a
|
|
121
|
+
single `access` line on `ApplicationController` can cover a whole app.
|
|
122
|
+
|
|
123
|
+
`access` works the same way in an `ActionController::API` controller. There a
|
|
124
|
+
refused request answers with a bare `403`, and an unauthenticated one with
|
|
125
|
+
`401`, instead of redirecting.
|
|
126
|
+
|
|
87
127
|
Inside your views you can use logged_in?(:admin, :customer, :etc) to show or hide content.
|
|
88
128
|
|
|
89
129
|
```erb
|
|
90
130
|
<%= link_to "destroy", destroy_listing_path(listing) if logged_in?(:admin, :customer, :etc) %>
|
|
91
131
|
```
|
|
92
132
|
|
|
133
|
+
`logged_in?` tests roles. To ask only whether anyone is signed in, without
|
|
134
|
+
caring which role they hold, use `user_logged_in?`.
|
|
135
|
+
|
|
93
136
|
If you need to access available roles within your project you can by calling:
|
|
94
137
|
|
|
95
138
|
```ruby
|
|
96
|
-
User::ROLES
|
|
97
|
-
#
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
139
|
+
User::ROLES # => [:admin, :editor, :user]
|
|
140
|
+
User.first.available_roles # the same list, from an instance
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`ROLES` is a constant on the model, so it is also reachable from your own
|
|
144
|
+
instance methods. A subclass shares its parent's roles.
|
|
145
|
+
|
|
146
|
+
#### Denying access yourself
|
|
147
|
+
|
|
148
|
+
Two helpers are available in controllers and in views:
|
|
149
|
+
|
|
150
|
+
```ruby
|
|
151
|
+
forbidden! # refuse someone who is signed in
|
|
152
|
+
unauthorized! # send a visitor to authentication, via authenticate_user!
|
|
105
153
|
```
|
|
106
|
-
|
|
154
|
+
|
|
155
|
+
`forbidden!` is the one you want in your own filters:
|
|
107
156
|
|
|
108
157
|
```ruby
|
|
109
158
|
before_action :check_active_user
|
|
@@ -112,16 +161,39 @@ def check_active_user
|
|
|
112
161
|
forbidden! unless current_user.active
|
|
113
162
|
end
|
|
114
163
|
```
|
|
115
|
-
|
|
164
|
+
|
|
165
|
+
Both answer a `js`, `json` or `xml` request with a bare `403` or `401` rather
|
|
166
|
+
than a redirect, and do the same in an `ActionController::API` controller,
|
|
167
|
+
which has no format negotiation to offer.
|
|
168
|
+
|
|
169
|
+
##### The denial message
|
|
170
|
+
|
|
171
|
+
`forbidden!` takes one for a single call, and `access` sets a default for the
|
|
172
|
+
whole controller:
|
|
116
173
|
|
|
117
174
|
```ruby
|
|
175
|
+
forbidden! "Your account is suspended"
|
|
176
|
+
|
|
118
177
|
access user: [:show, :index], message: "You shall not pass"
|
|
119
178
|
```
|
|
120
179
|
|
|
180
|
+
The message is resolved in this order, first match winning:
|
|
181
|
+
|
|
182
|
+
| | Source |
|
|
183
|
+
| --- | --- |
|
|
184
|
+
| 1 | the argument passed to `forbidden!` |
|
|
185
|
+
| 2 | an `msg` request header |
|
|
186
|
+
| 3 | the `message:` option on `access` |
|
|
187
|
+
| 4 | `"Permission Denied"` |
|
|
188
|
+
|
|
189
|
+
Note the second entry: the `msg` header is read off the request, so a caller
|
|
190
|
+
can replace a message you set with `message:`. It is undocumented legacy
|
|
191
|
+
behaviour rather than something to rely on.
|
|
192
|
+
|
|
121
193
|
#### User Admin Example Form for Multiple Roles
|
|
122
194
|
|
|
123
195
|
```slim
|
|
124
|
-
=
|
|
196
|
+
= form_with model: @user do |f|
|
|
125
197
|
- if @user.errors.any?
|
|
126
198
|
#error_explanation
|
|
127
199
|
h2 = "#{pluralize(@user.errors.count, "error")} prohibited this user from being saved:"
|
|
@@ -135,10 +207,10 @@ access user: [:show, :index], message: "You shall not pass"
|
|
|
135
207
|
- if @user.new_record? || params[:passwd]
|
|
136
208
|
.field
|
|
137
209
|
= f.label :password
|
|
138
|
-
= f.
|
|
210
|
+
= f.password_field :password
|
|
139
211
|
.field
|
|
140
212
|
= f.label :password_confirmation
|
|
141
|
-
= f.
|
|
213
|
+
= f.password_field :password_confirmation
|
|
142
214
|
.field
|
|
143
215
|
= f.label :roles
|
|
144
216
|
= f.select :roles, @user.available_roles, {}, {multiple: true}
|
|
@@ -148,7 +220,7 @@ access user: [:show, :index], message: "You shall not pass"
|
|
|
148
220
|
#### User Admin Example Form for Single Role Mode
|
|
149
221
|
|
|
150
222
|
```slim
|
|
151
|
-
=
|
|
223
|
+
= form_with model: @user do |f|
|
|
152
224
|
- if @user.errors.any?
|
|
153
225
|
#error_explanation
|
|
154
226
|
h2 = "#{pluralize(@user.errors.count, "error")} prohibited this user from being saved:"
|
|
@@ -162,24 +234,35 @@ access user: [:show, :index], message: "You shall not pass"
|
|
|
162
234
|
- if @user.new_record? || params[:passwd]
|
|
163
235
|
.field
|
|
164
236
|
= f.label :password
|
|
165
|
-
= f.
|
|
237
|
+
= f.password_field :password
|
|
166
238
|
.field
|
|
167
239
|
= f.label :password_confirmation
|
|
168
|
-
= f.
|
|
240
|
+
= f.password_field :password_confirmation
|
|
169
241
|
.field
|
|
170
242
|
= f.label :role
|
|
171
243
|
= f.select :role, @user.available_roles
|
|
172
244
|
.actions = f.submit
|
|
173
245
|
```
|
|
246
|
+
Development
|
|
247
|
+
-------
|
|
248
|
+
|
|
249
|
+
bundle install
|
|
250
|
+
bundle exec rake test
|
|
251
|
+
|
|
252
|
+
The suite boots a small Rails application in memory rather than carrying a
|
|
253
|
+
dummy app. To run it against a specific Rails version:
|
|
254
|
+
|
|
255
|
+
BUNDLE_GEMFILE=gemfiles/rails_7_1.gemfile bundle exec rake test
|
|
256
|
+
|
|
174
257
|
Credits
|
|
175
258
|
-------
|
|
176
259
|
|
|
177
|
-
PeterGate is written and
|
|
260
|
+
PeterGate is written and maintained by Isaac Sloan and friends.
|
|
178
261
|
|
|
179
262
|
|
|
180
263
|
## Contributing
|
|
181
264
|
|
|
182
|
-
1. Fork it ( https://github.com/
|
|
265
|
+
1. Fork it ( https://github.com/elorest/petergate/fork )
|
|
183
266
|
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
184
267
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
185
268
|
4. Push to the branch (`git push origin my-new-feature`)
|
data/Rakefile
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
require "bundler/gem_tasks"
|
|
2
|
-
require
|
|
2
|
+
require "rake/testtask"
|
|
3
3
|
|
|
4
4
|
Rake::TestTask.new(:test) do |t|
|
|
5
|
-
t.
|
|
5
|
+
t.libs << "lib"
|
|
6
|
+
t.libs << "test"
|
|
7
|
+
t.pattern = "test/**/*_test.rb"
|
|
6
8
|
t.verbose = false
|
|
9
|
+
t.warning = false
|
|
7
10
|
end
|
|
8
11
|
|
|
9
12
|
task default: :test
|
|
@@ -5,7 +5,6 @@ module Petergate
|
|
|
5
5
|
class InstallGenerator < Rails::Generators::Base
|
|
6
6
|
include Rails::Generators::Migration
|
|
7
7
|
source_root File.expand_path("../templates", __FILE__)
|
|
8
|
-
class_option :orm
|
|
9
8
|
|
|
10
9
|
desc "Sets up rails project for Petergate Authorizations"
|
|
11
10
|
def self.next_migration_number(path)
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
# Included into ActionController::Base *and* ActionController::API: Rails runs
|
|
2
|
+
# the :action_controller load hook for both. See the hook at the bottom of this
|
|
3
|
+
# file for why that hook rather than the Base/API-specific pair.
|
|
1
4
|
module Petergate
|
|
2
5
|
module ActionController
|
|
3
6
|
module Base
|
|
@@ -63,7 +66,7 @@ module Petergate
|
|
|
63
66
|
|
|
64
67
|
def self.included(base)
|
|
65
68
|
base.extend(ClassMethods)
|
|
66
|
-
base.helper_method :logged_in?, :forbidden!, :unauthorized!
|
|
69
|
+
base.helper_method :logged_in?, :forbidden!, :unauthorized! if base.respond_to?(:helper_method)
|
|
67
70
|
end
|
|
68
71
|
|
|
69
72
|
def parse_permission_rules(rules)
|
|
@@ -107,6 +110,10 @@ module Petergate
|
|
|
107
110
|
end
|
|
108
111
|
|
|
109
112
|
def unauthorized!
|
|
113
|
+
# ActionController::API has no MimeResponds, so no respond_to; a bare
|
|
114
|
+
# status is the right answer for an API caller regardless.
|
|
115
|
+
return head(:unauthorized) if is_a?(::ActionController::API)
|
|
116
|
+
|
|
110
117
|
respond_to do |format|
|
|
111
118
|
format.any(:js, :json, :xml) do
|
|
112
119
|
head(:unauthorized)
|
|
@@ -118,13 +125,24 @@ module Petergate
|
|
|
118
125
|
end
|
|
119
126
|
|
|
120
127
|
def forbidden!(msg = nil)
|
|
128
|
+
# See unauthorized! -- API controllers cannot respond_to.
|
|
129
|
+
return head(:forbidden) if is_a?(::ActionController::API)
|
|
130
|
+
|
|
121
131
|
respond_to do |format|
|
|
122
132
|
format.any(:js, :json, :xml) do
|
|
123
133
|
head(:forbidden)
|
|
124
134
|
end
|
|
125
135
|
format.html do
|
|
126
|
-
|
|
127
|
-
|
|
136
|
+
notice = msg || request.headers['msg'] || custom_message
|
|
137
|
+
|
|
138
|
+
# The Referer is deliberately not consulted. The original line read
|
|
139
|
+
# request.headers['Referrer'] -- a misspelling of the HTTP header --
|
|
140
|
+
# so it was always nil and this always resolved to the signed-in
|
|
141
|
+
# destination. Honouring the real header now would change where
|
|
142
|
+
# every existing app sends a refused user, and would hand the
|
|
143
|
+
# redirect target to the caller.
|
|
144
|
+
destination = current_user.present? ? after_sign_in_path_for(current_user) : root_path
|
|
145
|
+
redirect_to destination, notice: notice
|
|
128
146
|
end
|
|
129
147
|
end
|
|
130
148
|
end
|
|
@@ -132,6 +150,14 @@ module Petergate
|
|
|
132
150
|
end
|
|
133
151
|
end
|
|
134
152
|
|
|
135
|
-
|
|
153
|
+
# Hook in lazily rather than reopening ActionController::Base at require time:
|
|
154
|
+
# eager reopening forces ActionPack to load during boot, and it misses API
|
|
155
|
+
# controllers entirely.
|
|
156
|
+
#
|
|
157
|
+
# :action_controller rather than the newer :action_controller_base and
|
|
158
|
+
# :action_controller_api pair. Rails runs this one for both Base and API, and
|
|
159
|
+
# it predates the other two (added in 5.2) -- so on an older Rails the pair
|
|
160
|
+
# would simply never fire and petergate would silently stop working.
|
|
161
|
+
ActiveSupport.on_load(:action_controller) do
|
|
136
162
|
include Petergate::ActionController::Base
|
|
137
163
|
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# Included into ActiveRecord::Base, through the load hook at the bottom of
|
|
2
|
+
# this file.
|
|
1
3
|
module Petergate
|
|
2
4
|
module ActiveRecord
|
|
3
5
|
module Base
|
|
@@ -19,7 +21,10 @@ module Petergate
|
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
instance_eval do
|
|
22
|
-
|
|
24
|
+
# Own constant only, so each model that calls petergate gets its own
|
|
25
|
+
# roles rather than deferring to whichever model loaded first.
|
|
26
|
+
# Configuring the same model twice keeps the first set.
|
|
27
|
+
const_set('ROLES', (roles + [:user]).uniq.map(&:to_sym)) unless const_defined?(:ROLES, false)
|
|
23
28
|
|
|
24
29
|
if multiple
|
|
25
30
|
roles.each do |role|
|
|
@@ -39,7 +44,7 @@ module Petergate
|
|
|
39
44
|
|
|
40
45
|
if multiple
|
|
41
46
|
def roles=(v)
|
|
42
|
-
self[:roles] = (Array(v).map(&:to_sym).select{|r| r.size > 0 && available_roles.include?(r)} + [:user]).uniq
|
|
47
|
+
self[:roles] = (Array(v).compact.map(&:to_sym).select{|r| r.size > 0 && available_roles.include?(r)} + [:user]).uniq
|
|
43
48
|
end
|
|
44
49
|
else
|
|
45
50
|
def roles=(v)
|
|
@@ -48,8 +53,8 @@ module Petergate
|
|
|
48
53
|
v
|
|
49
54
|
when "Array"
|
|
50
55
|
v.first
|
|
51
|
-
end
|
|
52
|
-
self[:roles] = available_roles.include?(r) ? r : :user
|
|
56
|
+
end&.to_sym
|
|
57
|
+
self[:roles] = available_roles.include?(r) ? r : :user
|
|
53
58
|
end
|
|
54
59
|
end
|
|
55
60
|
|
|
@@ -82,6 +87,8 @@ module Petergate
|
|
|
82
87
|
end
|
|
83
88
|
end
|
|
84
89
|
|
|
85
|
-
|
|
90
|
+
# Hook in lazily so ActiveRecord::Base is not forced to load during boot,
|
|
91
|
+
# before the app has finished applying its own `config.active_record` settings.
|
|
92
|
+
ActiveSupport.on_load(:active_record) do
|
|
86
93
|
include Petergate::ActiveRecord::Base
|
|
87
94
|
end
|
data/lib/petergate/version.rb
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
<% end -%>
|
|
1
|
+
<%# 422 is written numerically on purpose. Rack 2.2 knows only
|
|
2
|
+
:unprocessable_entity and Rack 3.2 only :unprocessable_content, and this
|
|
3
|
+
template has to serve apps on either. -%>
|
|
5
4
|
<% module_namespacing do -%>
|
|
6
5
|
class <%= controller_class_name %>Controller < ApplicationController
|
|
7
|
-
before_action :set_<%= singular_table_name %>, only: [
|
|
6
|
+
before_action :set_<%= singular_table_name %>, only: %i[ show edit update destroy ]
|
|
8
7
|
access all: [:index, :show, :new, :edit, :create, :update, :destroy], user: :all
|
|
9
8
|
|
|
10
9
|
# GET <%= route_url %>
|
|
@@ -32,23 +31,23 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
32
31
|
if @<%= orm_instance.save %>
|
|
33
32
|
redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully created.'" %>
|
|
34
33
|
else
|
|
35
|
-
render :new
|
|
34
|
+
render :new, status: 422
|
|
36
35
|
end
|
|
37
36
|
end
|
|
38
37
|
|
|
39
38
|
# PATCH/PUT <%= route_url %>/1
|
|
40
39
|
def update
|
|
41
40
|
if @<%= orm_instance.update("#{singular_table_name}_params") %>
|
|
42
|
-
redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'"
|
|
41
|
+
redirect_to @<%= singular_table_name %>, notice: <%= "'#{human_name} was successfully updated.'" %>, status: :see_other
|
|
43
42
|
else
|
|
44
|
-
render :edit
|
|
43
|
+
render :edit, status: 422
|
|
45
44
|
end
|
|
46
45
|
end
|
|
47
46
|
|
|
48
47
|
# DELETE <%= route_url %>/1
|
|
49
48
|
def destroy
|
|
50
49
|
@<%= orm_instance.destroy %>
|
|
51
|
-
redirect_to <%= index_helper %>
|
|
50
|
+
redirect_to <%= index_helper %>_path, notice: <%= "'#{human_name} was successfully destroyed.'" %>, status: :see_other
|
|
52
51
|
end
|
|
53
52
|
|
|
54
53
|
private
|
|
@@ -57,10 +56,10 @@ class <%= controller_class_name %>Controller < ApplicationController
|
|
|
57
56
|
@<%= singular_table_name %> = <%= orm_class.find(class_name, "params[:id]") %>
|
|
58
57
|
end
|
|
59
58
|
|
|
60
|
-
# Only allow a
|
|
59
|
+
# Only allow a list of trusted parameters through.
|
|
61
60
|
def <%= "#{singular_table_name}_params" %>
|
|
62
61
|
<%- if attributes_names.empty? -%>
|
|
63
|
-
params
|
|
62
|
+
params.fetch(:<%= singular_table_name %>, {})
|
|
64
63
|
<%- else -%>
|
|
65
64
|
params.require(:<%= singular_table_name %>).permit(<%= attributes_names.map { |name| ":#{name}" }.join(', ') %>)
|
|
66
65
|
<%- end -%>
|
data/petergate.gemspec
CHANGED
|
@@ -10,15 +10,38 @@ Gem::Specification.new do |spec|
|
|
|
10
10
|
spec.email = ["isaac@isaacsloan.com"]
|
|
11
11
|
spec.summary = %q{Authorization system allowing verbose easy read controller syntax.}
|
|
12
12
|
spec.description = %q{If you like the straight forward and effective nature of Strong Parameters and suspect that CanCan might be overkill for your project then you'll love Petergate's easy to use and read action and content based authorizations.}
|
|
13
|
-
spec.homepage = "https://github.com/
|
|
13
|
+
spec.homepage = "https://github.com/elorest/petergate"
|
|
14
14
|
spec.license = "MIT"
|
|
15
|
+
spec.metadata = {
|
|
16
|
+
"source_code_uri" => "https://github.com/elorest/petergate",
|
|
17
|
+
"bug_tracker_uri" => "https://github.com/elorest/petergate/issues",
|
|
18
|
+
}
|
|
15
19
|
|
|
16
|
-
|
|
20
|
+
# assets/ holds the README's images, which the README loads from GitHub. They
|
|
21
|
+
# are 350K of PNG that no runtime code touches, so they stay out of the gem --
|
|
22
|
+
# they only shipped at all because moving them out of dummy/, which was
|
|
23
|
+
# excluded here, put them on the default path.
|
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |p| p.start_with?("test/", "gemfiles/", ".github/", "assets/") }
|
|
17
25
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
26
|
spec.require_paths = ["lib"]
|
|
19
27
|
spec.post_install_message = "NOTICE: As of version 1.5.0, the :admin role has been changed to :root_admin."
|
|
20
28
|
|
|
21
29
|
spec.add_development_dependency "bundler", "> 1.7"
|
|
22
|
-
spec.add_development_dependency "rake", "
|
|
23
|
-
|
|
30
|
+
spec.add_development_dependency "rake", ">= 12.3"
|
|
31
|
+
|
|
32
|
+
# petergate reopens ActionController (actionpack), calls String#pluralize
|
|
33
|
+
# (activesupport), and subclasses Rails::Railtie (railties), so all three are
|
|
34
|
+
# real runtime dependencies -- not just activerecord.
|
|
35
|
+
#
|
|
36
|
+
# 6.1 is the real floor, not a conservative one. `serialize :roles, coder:
|
|
37
|
+
# YAML` needs a serialize that accepts keywords: 6.1 and 7.0 swallow the
|
|
38
|
+
# unknown one and fall through to YAMLColumn.new(:roles, Object), and 7.1
|
|
39
|
+
# added coder: for real. On 6.0 and earlier the signature is
|
|
40
|
+
# serialize(attr_name, class_name_or_coder = Object) with no **options, so
|
|
41
|
+
# Ruby binds the hash to the positional argument and the model raises
|
|
42
|
+
# NoMethodError on load. CI covers 7.1 through 8.1.
|
|
43
|
+
spec.add_dependency "activerecord", ">= 6.1"
|
|
44
|
+
spec.add_dependency "actionpack", ">= 6.1"
|
|
45
|
+
spec.add_dependency "activesupport", ">= 6.1"
|
|
46
|
+
spec.add_dependency "railties", ">= 6.1"
|
|
24
47
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: petergate
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.1.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Isaac Sloan
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: bundler
|
|
@@ -27,30 +27,72 @@ dependencies:
|
|
|
27
27
|
name: rake
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
29
29
|
requirements:
|
|
30
|
-
- - "
|
|
30
|
+
- - ">="
|
|
31
31
|
- !ruby/object:Gem::Version
|
|
32
32
|
version: '12.3'
|
|
33
33
|
type: :development
|
|
34
34
|
prerelease: false
|
|
35
35
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
36
|
requirements:
|
|
37
|
-
- - "
|
|
37
|
+
- - ">="
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
39
|
version: '12.3'
|
|
40
40
|
- !ruby/object:Gem::Dependency
|
|
41
41
|
name: activerecord
|
|
42
42
|
requirement: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
|
-
- - "
|
|
44
|
+
- - ">="
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version:
|
|
46
|
+
version: '6.1'
|
|
47
47
|
type: :runtime
|
|
48
48
|
prerelease: false
|
|
49
49
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
50
|
requirements:
|
|
51
|
-
- - "
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '6.1'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: actionpack
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '6.1'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '6.1'
|
|
68
|
+
- !ruby/object:Gem::Dependency
|
|
69
|
+
name: activesupport
|
|
70
|
+
requirement: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '6.1'
|
|
75
|
+
type: :runtime
|
|
76
|
+
prerelease: false
|
|
77
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
+
requirements:
|
|
79
|
+
- - ">="
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '6.1'
|
|
82
|
+
- !ruby/object:Gem::Dependency
|
|
83
|
+
name: railties
|
|
84
|
+
requirement: !ruby/object:Gem::Requirement
|
|
85
|
+
requirements:
|
|
86
|
+
- - ">="
|
|
87
|
+
- !ruby/object:Gem::Version
|
|
88
|
+
version: '6.1'
|
|
89
|
+
type: :runtime
|
|
90
|
+
prerelease: false
|
|
91
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
52
94
|
- !ruby/object:Gem::Version
|
|
53
|
-
version:
|
|
95
|
+
version: '6.1'
|
|
54
96
|
description: If you like the straight forward and effective nature of Strong Parameters
|
|
55
97
|
and suspect that CanCan might be overkill for your project then you'll love Petergate's
|
|
56
98
|
easy to use and read action and content based authorizations.
|
|
@@ -62,7 +104,6 @@ extra_rdoc_files: []
|
|
|
62
104
|
files:
|
|
63
105
|
- ".gitignore"
|
|
64
106
|
- ".ruby-version"
|
|
65
|
-
- ".travis.yml"
|
|
66
107
|
- Gemfile
|
|
67
108
|
- LICENSE.txt
|
|
68
109
|
- README.md
|
|
@@ -76,10 +117,12 @@ files:
|
|
|
76
117
|
- lib/petergate/version.rb
|
|
77
118
|
- lib/templates/rails/scaffold_controller/controller.rb
|
|
78
119
|
- petergate.gemspec
|
|
79
|
-
homepage: https://github.com/
|
|
120
|
+
homepage: https://github.com/elorest/petergate
|
|
80
121
|
licenses:
|
|
81
122
|
- MIT
|
|
82
|
-
metadata:
|
|
123
|
+
metadata:
|
|
124
|
+
source_code_uri: https://github.com/elorest/petergate
|
|
125
|
+
bug_tracker_uri: https://github.com/elorest/petergate/issues
|
|
83
126
|
post_install_message: 'NOTICE: As of version 1.5.0, the :admin role has been changed
|
|
84
127
|
to :root_admin.'
|
|
85
128
|
rdoc_options: []
|
|
@@ -96,7 +139,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
96
139
|
- !ruby/object:Gem::Version
|
|
97
140
|
version: '0'
|
|
98
141
|
requirements: []
|
|
99
|
-
rubygems_version: 3.6.
|
|
142
|
+
rubygems_version: 3.6.9
|
|
100
143
|
specification_version: 4
|
|
101
144
|
summary: Authorization system allowing verbose easy read controller syntax.
|
|
102
145
|
test_files: []
|