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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 03b0b048bf5f3fa47709ea1ee62839a0a4fb793eaa5cd054435a4765f39d5529
4
- data.tar.gz: 6252d26aa0f3009ceb36b7f77070920a58b4f8f16dc7d345c4ed5b8a151efe73
3
+ metadata.gz: acd5072223d85700246df5acd1445b292a918cf85a3b51b4ee42ae03c3648630
4
+ data.tar.gz: d084364761c8234ac5db4cc4434e88337913f07dea42cf7d2d3fdc15b3b8261d
5
5
  SHA512:
6
- metadata.gz: 530ffc1078e0999fef2fd48d0041c8754fd4f7b6e95ed2d55ea187dc4affd1d7257071f28e3997d4b42457b090fe4f94f04ae8049bf5bfe6ec322e9cedfd3447
7
- data.tar.gz: cf64dfce82b8358c162555a5c5bdde118520b4308d09f382c21b9a72a17b805e4a01b665644a6edb9006f17d886dd1a45ed772847b007f1f8dbb6a9cdca2f5af
6
+ metadata.gz: ffef6582b1bcd3d55d01c4655dff65a7d12ee47fbefeb32ba2339911db89827923a05e876396261c00849f966ecb36b3470247c057eb99dc60cf0822c8ee26f5
7
+ data.tar.gz: 9c4e7e84b9e07811651f6cd172f4b32b92540bd47a24a2ec986f028d64b7a3786d3a800aefe879f9d81f04700360a05f007d36148a22dea8b80b5456cc2d938e
data/.gitignore CHANGED
@@ -6,8 +6,6 @@ Gemfile.lock
6
6
  /doc/
7
7
  /pkg/
8
8
  /spec/reports/
9
- dummy/log/*
10
- dummy/tmp/*
11
9
  *.sqlite3
12
10
  *.bundle
13
11
  *.so
@@ -16,3 +14,5 @@ dummy/tmp/*
16
14
  mkmf.log
17
15
  *.gem
18
16
  .DS_Store
17
+ /tmp/
18
+ gemfiles/*.lock
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 3.4.2
1
+ 3.2.0
data/Gemfile CHANGED
@@ -1,43 +1,16 @@
1
- source 'https://rubygems.org'
2
- ruby '3.2.0'
1
+ source "https://rubygems.org"
3
2
 
4
- # Specify your gem's dependencies in petergate.gemspec
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
- [![Petergate](https://github.com/elorest/petergate/blob/master/dummy/public/petergate.png)](https://github.com/elorest/petergate)
1
+ [![Petergate](https://raw.githubusercontent.com/elorest/petergate/master/assets/petergate.png)](https://github.com/elorest/petergate)
2
2
 
3
- [![Build Status](https://travis-ci.org/elorest/petergate.svg)](https://travis-ci.org/dburnsii/petergate)
4
- [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/isaacsloan/petergate?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
3
+ [![CI](https://github.com/elorest/petergate/actions/workflows/ci.yml/badge.svg)](https://github.com/elorest/petergate/actions/workflows/ci.yml)
5
4
  [![Gem Version](https://badge.fury.io/rb/petergate.svg)](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/isaacsloan/petergate) easy to use and read action and content based authorizations."
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
- Make sure your user model is defined in
31
- app/models/user.rb
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/plataformatec/devise) you're in luck, otherwise you'll have to add following methods to your project:
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, :editors) # returns true if user is any of roles passed in as params.
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
- `User.#{role}_editors => #list of editors. Method is created for all roles. Roles [admin, :teacher] will have corresponding methods role_admins, role_teachers, etc.`
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
- # or from an instance
98
- User.first.available_roles
99
- # ROLES is a CONSTANT and will still work from within the User model instance methods
100
- # like in this default setter:
101
-
102
- def roles=(v)
103
- self[:roles] = v.map(&:to_sym).to_a.select{|r| r.size > 0 && ROLES.include?(r)}
104
- end
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
- If you need to deny access you can use the forbidden! method:
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
- If you want to change the `permission denied` message you can add to the access line:
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
- = form_for @user do |f|
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.text_field :password
210
+ = f.password_field :password
139
211
  .field
140
212
  = f.label :password_confirmation
141
- = f.text_field :password_confirmation
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
- = form_for @user do |f|
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.text_field :password
237
+ = f.password_field :password
166
238
  .field
167
239
  = f.label :password_confirmation
168
- = f.text_field :password_confirmation
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 maintaned by Isaac Sloan and friends.
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/isaacsloan/petergate/fork )
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 'rake/testtask'
2
+ require "rake/testtask"
3
3
 
4
4
  Rake::TestTask.new(:test) do |t|
5
- t.pattern = 'dummy/test/**/*_test.rb'
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
- destination = current_user.present? ? request.headers['Referrer'] || after_sign_in_path_for(current_user) : root_path
127
- redirect_to destination, notice: (msg || request.headers['msg'] || custom_message)
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
- class ActionController::Base
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
- const_set('ROLES', (roles + [:user]).uniq.map(&:to_sym)) unless defined?(User::ROLES)
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.to_sym
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
- class ActiveRecord::Base
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
@@ -1,3 +1,3 @@
1
1
  module Petergate
2
- VERSION = "3.0.1"
2
+ VERSION = "3.1.1"
3
3
  end
@@ -1,10 +1,9 @@
1
- <% if namespaced? -%>
2
- require_dependency "<%= namespaced_file_path %>/application_controller"
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: [:show, :edit, :update, :destroy]
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 %>_url, notice: <%= "'#{human_name} was successfully destroyed.'" %>
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 trusted parameter "white list" through.
59
+ # Only allow a list of trusted parameters through.
61
60
  def <%= "#{singular_table_name}_params" %>
62
61
  <%- if attributes_names.empty? -%>
63
- params[:<%= singular_table_name %>]
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/isaacsloan/petergate"
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
- spec.files = `git ls-files -z`.split("\x0").delete_if{|p| p.include?("dummy/")}
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", "~> 12.3"
23
- spec.add_dependency 'activerecord', "> 4.0.0"
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.0.1
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: 2025-06-20 00:00:00.000000000 Z
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: 4.0.0
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: 4.0.0
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/isaacsloan/petergate
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.2
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: []
data/.travis.yml DELETED
@@ -1,5 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - "2.5.1"
4
- before_script: "bundle install && cd dummy && rake db:create && rake db:migrate"
5
- script: "bundle exec rake test"