bullet_train-super_load_and_authorize_resource 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 1a068f14f14c8f382a9d7b30d30dcf7ac89656d30f2b2e8279110e139a449f34
4
+ data.tar.gz: e80081fe8ea016f9418b072529a540b6282ff6c240b806871457f2f9189d23d7
5
+ SHA512:
6
+ metadata.gz: '09989eceabb20cdc3ca223acade617e01628ad8ff5d31b29f07ddbb4bc6f50b1f25d2a982ed1d21601f7d8cdbe475e143956f9d10045bcdbdf06effe1fde7bb2'
7
+ data.tar.gz: d5f772ee16dabfcbbb6c8908480462ae7e3a251af528767ee1bab4c91782aa132281902d3724edb20f1a9e07170396bac66e741d6f85d14ceea3a14a5ccdc6e9
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2022 Andrew Culver
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # BulletTrain::SuperLoadAndAuthorizeResource
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "bullet_train-super_load_and_authorize_resource"
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install bullet_train-super_load_and_authorize_resource
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1,189 @@
1
+ module LoadsAndAuthorizesResource
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ def regex_to_remove_controller_namespace
6
+ raise "This is a template method that needs to be implemented by controllers including LoadsAndAuthorizesResource."
7
+ end
8
+
9
+ def load_team
10
+ # Sometimes `@team` has already been populated by earlier `before_action` steps.
11
+ @team ||= @child_object&.team || @parent_object&.team
12
+
13
+ # Update current attributes.
14
+ Current.team = @team
15
+
16
+ # If the currently loaded team is saved to the database, make that the user's new current team.
17
+ if @team.try(:persisted?)
18
+ if can? :show, @team
19
+ current_user.update_column(:current_team_id, @team.id)
20
+ end
21
+ end
22
+ end
23
+
24
+ def self.model_namespace_from_controller_namespace
25
+ controller_class_name = regex_to_remove_controller_namespace ? name.gsub(regex_to_remove_controller_namespace, "") : name
26
+ namespace = controller_class_name.split("::")
27
+ # Remove "::ThingsController"
28
+ namespace.pop
29
+ namespace
30
+ end
31
+
32
+ # this is one of the few pieces of 'magical' functionality that bullet train implements
33
+ # for you in your controllers beyond that is provided by the underlying gems that we've
34
+ # tied together. we've taken the liberty of doing this because it's heavily based on
35
+ # cancancan's `load_and_authorize_resource` method, which is awesome, but it also
36
+ # implements a lot of the options required to make that method work very well for our
37
+ # controllers in the account namespace, including our shallow nested routes.
38
+ #
39
+ # there are also some complications that were introduced into this method by our support
40
+ # for namespaced models and controllers. (we introduced this complexity in support of
41
+ # namespacing our `Oauth::` models and controllers.)
42
+ #
43
+ # to help you understand the code below, usually `through` is `team`
44
+ # and `model` is something like `project`.
45
+ def self.account_load_and_authorize_resource(model, options, old_options = {})
46
+ # options are now required, because you have to have at least a 'through' setting.
47
+
48
+ # we used to support calling this method with a signature like this:
49
+ #
50
+ # `account_load_and_authorize_resource [:oauth, :twitter_account], :team`
51
+ #
52
+ # however this abstraction was too short-sighted so we've updated this method to accept the exact same method
53
+ # signature as cancancan's original `load_and_authorize_resource` method.
54
+ if model.is_a?(Array)
55
+ raise "Bullet Train has depreciated this method of calling `account_load_and_authorize_resource`. Read the comments on this line of source for more details."
56
+ end
57
+
58
+ # this is providing backward compatibility for folks who are calling this method like this:
59
+ # account_load_and_authorize_resource :thing, through: :team, through_association: :scaffolding_things
60
+ # i'm going to deprecate this at some point.
61
+ if options.is_a?(Hash)
62
+ through = options[:through]
63
+ options.delete(:through)
64
+ else
65
+ through = options
66
+ options = old_options
67
+ end
68
+
69
+ # fetch the namespace of the controller. this should generally match the namespace of the model, except for the
70
+ # `account` part.
71
+ namespace = model_namespace_from_controller_namespace
72
+
73
+ tried = []
74
+ begin
75
+ # check whether the parent exists in the model namespace.
76
+ model_class_name = (namespace + [model.to_s.classify]).join("::")
77
+ model_class_name.constantize
78
+ rescue NameError
79
+ tried << model_class_name
80
+ if namespace.any?
81
+ namespace.pop
82
+ retry
83
+ else
84
+ raise "Oh no, it looks like your call to 'account_load_and_authorize_resource' is broken. We tried #{tried.join(" and ")}, but didn't find a valid class name."
85
+ end
86
+ end
87
+
88
+ # treat through as an array even if the user only specified one parent type.
89
+ through_as_symbols = through.is_a?(Array) ? through : [through]
90
+
91
+ through = []
92
+ through_class_names = []
93
+
94
+ through_as_symbols.each do |through_as_symbol|
95
+ # reflect on the belongs_to association of the child model to figure out the class names of the parents.
96
+ unless (association = model_class_name.constantize.reflect_on_association(through_as_symbol))
97
+ raise "Oh no, it looks like your call to 'account_load_and_authorize_resource' is broken. Tried to reflect on the `#{through_as_symbol}` association of #{model_class_name}, but didn't find one."
98
+ end
99
+
100
+ through_class_name = association.klass.name
101
+
102
+ begin
103
+ through << through_class_name.constantize
104
+ through_class_names << through_class_name
105
+ rescue NameError
106
+ raise "Oh no, it looks like your call to 'account_load_and_authorize_resource' is broken. We tried to load `#{through_class_name}}` (the class name defined for the `#{through_as_symbol}` association), but couldn't find it."
107
+ end
108
+ end
109
+
110
+ if through_as_symbols.count > 1 && !options[:polymorphic]
111
+ raise "When a resource can be loaded through multiple parents, please specify the 'polymorphic' option to tell us what that controller calls the parent, e.g. `polymorphic: :imageable`."
112
+ end
113
+
114
+ # this provides the support we need for shallow nested resources, which
115
+ # helps keep our routes tidy even after many levels of nesting. most people
116
+ # i talk to don't actually know about this feature in rails, but it's
117
+ # actually the recommended approach in the rails routing documentation.
118
+ #
119
+ # also, similar to `load_and_authorize_resource`, people can pass in additional
120
+ # actions for which the resource should be loaded, but because we're making
121
+ # separate calls to `load_and_authorize_resource` for member and collection
122
+ # actions, we ask controllers to specify these actions separately, e.g.:
123
+ # `account_load_and_authorize_resource :invitation, :team, member_actions: [:accept, :promote]`
124
+ collection_actions = options[:collection_actions] || []
125
+ member_actions = options[:member_actions] || []
126
+
127
+ # this option is native to cancancan and allows you to skip account_load_and_authorize_resource
128
+ # for a specific action that would otherwise run it (e.g. see invitations#show.)
129
+ except_actions = options[:except] || []
130
+
131
+ collection_actions = ([:index, :new, :create, :reorder] + collection_actions) - except_actions
132
+ member_actions = ([:show, :edit, :update, :destroy] + member_actions) - except_actions
133
+
134
+ options.delete(:collection_actions)
135
+ options.delete(:member_actions)
136
+
137
+ # NOTE: because we're using prepend for all of these, these are written in backwards order
138
+ # of how they'll be executed during a request!
139
+
140
+ # 4. finally, load the team and parent resource if we can.
141
+ prepend_before_action :load_team
142
+
143
+ # x. this and the thing below it are only here to make a sortable concern possible.
144
+ prepend_before_action only: member_actions do
145
+ instance_variable_name = options[:polymorphic] || through_as_symbols[0]
146
+ eval "@child_object = @#{model}"
147
+ eval "@parent_object = @#{instance_variable_name}"
148
+ end
149
+
150
+ prepend_before_action only: collection_actions do
151
+ instance_variable_name = options[:polymorphic] || through_as_symbols[0]
152
+ eval "@parent_object = @#{instance_variable_name}"
153
+ if options[:through_association].present?
154
+ eval "@child_collection = :#{options[:through_association]}"
155
+ else
156
+ eval "@child_collection = :#{model.to_s.pluralize}"
157
+ end
158
+ end
159
+
160
+ prepend_before_action only: member_actions do
161
+ instance_variable_name = options[:polymorphic] || through_as_symbols[0]
162
+ possible_sources_of_parent = through_as_symbols.map { |tas| "@#{model}.#{tas}" }.join(" || ")
163
+ eval_string = "@#{instance_variable_name} ||= " + possible_sources_of_parent
164
+ eval eval_string
165
+ end
166
+
167
+ if options[:polymorphic]
168
+ prepend_before_action only: collection_actions do
169
+ possible_sources_of_parent = through_as_symbols.map { |tas| "@#{tas}" }.join(" || ")
170
+ eval "@#{options[:polymorphic]} ||= #{possible_sources_of_parent}"
171
+ end
172
+ end
173
+
174
+ # 3. on action resource, we have a specific id for the child resource, so load it directly.
175
+ load_and_authorize_resource model, options.merge(class: model_class_name, only: member_actions, prepend: true, shallow: true)
176
+
177
+ # 2. only load the child resource through the parent resource for collection actions.
178
+ load_and_authorize_resource model, options.merge(class: model_class_name, through: through_as_symbols, only: collection_actions, prepend: true, shallow: true)
179
+
180
+ # 1. load the parent resource for collection actions only. (we're using shallow routes.)
181
+ # since a controller can have multiple potential parents, we have to run this as a loop on every possible
182
+ # parent. (the vast majority of controllers only have one parent.)
183
+
184
+ through_class_names.each_with_index do |through_class_name, index|
185
+ load_and_authorize_resource through_as_symbols[index], options.merge(class: through_class_name, only: collection_actions, prepend: true, shallow: true)
186
+ end
187
+ end
188
+ end
189
+ end
data/config/routes.rb ADDED
@@ -0,0 +1,2 @@
1
+ Rails.application.routes.draw do
2
+ end
@@ -0,0 +1,6 @@
1
+ module BulletTrain
2
+ module SuperLoadAndAuthorizeResource
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module BulletTrain
2
+ module SuperLoadAndAuthorizeResource
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
@@ -0,0 +1,8 @@
1
+ require "bullet_train/super_load_and_authorize_resource/version"
2
+ require "bullet_train/super_load_and_authorize_resource/engine"
3
+
4
+ module BulletTrain
5
+ module SuperLoadAndAuthorizeResource
6
+ # Your code goes here...
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :bullet_train_super_load_and_authorize_resource do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bullet_train-super_load_and_authorize_resource
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Andrew Culver
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-01-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 7.0.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 7.0.0
27
+ description: Bullet Train Super Load And Authorize Resource
28
+ email:
29
+ - andrew.culver@gmail.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - MIT-LICENSE
35
+ - README.md
36
+ - Rakefile
37
+ - app/assets/config/bullet_train_super_load_and_authorize_resource_manifest.js
38
+ - app/controllers/concerns/loads_and_authorizes_resource.rb
39
+ - config/routes.rb
40
+ - lib/bullet_train/super_load_and_authorize_resource.rb
41
+ - lib/bullet_train/super_load_and_authorize_resource/engine.rb
42
+ - lib/bullet_train/super_load_and_authorize_resource/version.rb
43
+ - lib/tasks/bullet_train/super_load_and_authorize_resource_tasks.rake
44
+ homepage: https://github.com/bullet-train-co/bullet_train-super_load_and_authorize_resource
45
+ licenses:
46
+ - MIT
47
+ metadata:
48
+ homepage_uri: https://github.com/bullet-train-co/bullet_train-super_load_and_authorize_resource
49
+ source_code_uri: https://github.com/bullet-train-co/bullet_train-super_load_and_authorize_resource
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.2.22
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: Bullet Train Super Load And Authorize Resource
69
+ test_files: []