skinny_controllers 0.2 → 0.3
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/README.md +12 -9
- data/lib/skinny_controllers/diet.rb +8 -50
- data/lib/skinny_controllers/lookup/controller.rb +38 -0
- data/lib/skinny_controllers/lookup/model.rb +33 -0
- data/lib/skinny_controllers/lookup/operation.rb +65 -0
- data/lib/skinny_controllers/lookup/policy.rb +25 -0
- data/lib/skinny_controllers/operation/base.rb +36 -24
- data/lib/skinny_controllers/operation/model_helpers.rb +5 -16
- data/lib/skinny_controllers/version.rb +1 -1
- data/lib/skinny_controllers.rb +8 -9
- metadata +7 -4
- data/lib/skinny_controllers/operation/policy_helpers.rb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f549f005c93de6eb099efb11b80a429c99077cf0
|
4
|
+
data.tar.gz: 44dd3003008e227b826fff4c51b3c1e9d28cf9d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 975ae25a383bee2c3b88d79b126c95be07c379cf69382ce24666ef0963cd89a6e312fa8cd530944f784c0ec63599b2afcdc294678cfe9f13f58bd4c649ee5c6d
|
7
|
+
data.tar.gz: c0a2877d7e19e90deaa5c5e43f54222ffc256fd2a7b1487ad79fd149011504288ffea052e8510bd9dd164bff20dd319f9e940727277a1d791a01ee683af92e15
|
data/README.md
CHANGED
@@ -42,7 +42,7 @@ The above does a multitude of assumptions to make sure that you can type the lea
|
|
42
42
|
3. Your model responds to `find`, and `where`
|
43
43
|
4. Your model responds to `is_accessible_to?`. This can be changed at `SkinnyControllers.accessible_to_method`
|
44
44
|
|
45
|
-
### Your model name
|
45
|
+
### Your model name might be different from your resource name
|
46
46
|
Lets say you have a JSON API resource that you'd like to render that has some additional/subset of data.
|
47
47
|
Maybe the model is an `Event`, and the resource an `EventSummary` (which could do some aggregation of `Event` data).
|
48
48
|
|
@@ -128,11 +128,14 @@ SkinnyControllers.controller_namespace = 'API'
|
|
128
128
|
```
|
129
129
|
|
130
130
|
The following options are available:
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
131
|
+
|
132
|
+
|Option|Default|Note|
|
133
|
+
|------|-------|----|
|
134
|
+
|`operations_namespace` | '' | Optional namespace to put all the operations in. |
|
135
|
+
|`operations_suffix`|`'Operations'` | Default suffix for the operations namespaces. |
|
136
|
+
|`policy_suffix`|`'Policy'` | Default suffix for policies classes. |
|
137
|
+
|`controller_namespace`|`''`| Global Namespace for all controllers (e.g.: `'API'`) |
|
138
|
+
|`allow_by_default`| `true` | Default permission |
|
139
|
+
|`accessible_to_method`|`is_accessible_to?`| method to call an the object that the user might be able to access |
|
140
|
+
|`accessible_to_scope`| `accessible_to`| scope / class method on an object that the user might be able to access |
|
141
|
+
|`action_map`| see [skinny_controllers.rb](./lib/skinny_controllers.rb#L61)| |
|
@@ -2,6 +2,10 @@ module SkinnyControllers
|
|
2
2
|
module Diet
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
|
+
included do
|
6
|
+
cattr_accessor :model_class
|
7
|
+
end
|
8
|
+
|
5
9
|
# TODO: what if we want multiple operations per action?
|
6
10
|
#
|
7
11
|
# @return an instance of the operation with default parameters
|
@@ -12,73 +16,27 @@ module SkinnyControllers
|
|
12
16
|
# Assumes the operation name from the controller name
|
13
17
|
#
|
14
18
|
# @example SomeObjectsController => Operation::SomeObject::Action
|
15
|
-
#
|
19
|
+
# @return [Class] the operation class for the model and verb
|
16
20
|
def operation_class
|
17
|
-
|
18
|
-
klass_name = operation_class_from_model(model_name)
|
19
|
-
klass = klass_name.safe_constantize
|
20
|
-
klass || default_operation_class_for(model_name)
|
21
|
-
end
|
22
|
-
|
23
|
-
# dynamically creates a module for the model if it
|
24
|
-
# isn't already defined
|
25
|
-
def default_operation_class_for(model_name)
|
26
|
-
default_operation = Operation::Default
|
27
|
-
namespace = default_operation_namespace_for(model_name)
|
28
|
-
|
29
|
-
default = "#{namespace.name}::Default".safe_constantize
|
30
|
-
default || namespace.const_set('Default'.freeze, default_operation.dup)
|
31
|
-
end
|
32
|
-
|
33
|
-
def default_operation_namespace_for(model_name)
|
34
|
-
desired_namespace = operation_namespace_from_model(model_name)
|
35
|
-
|
36
|
-
parent_namespace = SkinnyControllers.operations_namespace
|
37
|
-
namespace = "#{parent_namespace}::#{desired_namespace}".safe_constantize
|
38
|
-
namespace || Object.const_set(desired_namespace, Module.new)
|
21
|
+
Lookup::Operation.from_controller(self.class.name, verb_for_action, model_class)
|
39
22
|
end
|
40
23
|
|
41
24
|
# abstraction for `operation.run`
|
42
25
|
# useful when there is no logic needed for deciding what to
|
43
26
|
# do with an operation or if there is no logic to decide which operation
|
44
27
|
# to use
|
28
|
+
#
|
29
|
+
# @return [ActiveRecord::Base] the model
|
45
30
|
def model
|
46
31
|
@model ||= operation.run
|
47
32
|
end
|
48
33
|
|
49
34
|
private
|
50
35
|
|
51
|
-
def operation_namespace_from_model(model_name)
|
52
|
-
"#{model_name}#{SkinnyControllers::operations_suffix}"
|
53
|
-
end
|
54
|
-
|
55
36
|
# action name is inherited from ActionController::Base
|
56
37
|
# http://www.rubydoc.info/docs/rails/2.3.8/ActionController%2FBase%3Aaction_name
|
57
38
|
def verb_for_action
|
58
39
|
SkinnyControllers.action_map[action_name] || SkinnyControllers.action_map['default']
|
59
40
|
end
|
60
|
-
|
61
|
-
def model_name_from_controller
|
62
|
-
object_name = resource_name_from_controller.singularize
|
63
|
-
# remove the namespace if one exists
|
64
|
-
object_name.slice! controller_name_prefix
|
65
|
-
object_name
|
66
|
-
end
|
67
|
-
|
68
|
-
def resource_name_from_controller
|
69
|
-
controller_name = self.class.name
|
70
|
-
controller_name.gsub('Controller', '')
|
71
|
-
end
|
72
|
-
|
73
|
-
def operation_class_from_model(model_name)
|
74
|
-
prefix = SkinnyControllers.operations_namespace
|
75
|
-
namespace = operation_namespace_from_model(model_name)
|
76
|
-
"#{prefix}::#{namespace}::#{verb_for_action}"
|
77
|
-
end
|
78
|
-
|
79
|
-
def controller_name_prefix
|
80
|
-
namespace = SkinnyControllers.controller_namespace || ''
|
81
|
-
"#{namespace}::" if namespace
|
82
|
-
end
|
83
41
|
end
|
84
42
|
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module SkinnyControllers
|
2
|
+
module Lookup
|
3
|
+
module Controller
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# @example ObjectsController => Objects
|
7
|
+
# @return [String] the resource name
|
8
|
+
def resource_name(controller_name)
|
9
|
+
controller_name.gsub('Controller', '')
|
10
|
+
end
|
11
|
+
|
12
|
+
# @example <ObjectsContreller> => Object
|
13
|
+
# @return [String] name of the class of the model
|
14
|
+
def model_name(controller)
|
15
|
+
resource_name = Controller.resource_name(controller)
|
16
|
+
# Convert Resources to Resource
|
17
|
+
object_name = resource_name.singularize
|
18
|
+
# remove the namespace if one exists
|
19
|
+
object_name.slice! namespace
|
20
|
+
object_name
|
21
|
+
end
|
22
|
+
|
23
|
+
# TODO: add option to configure this per controller
|
24
|
+
#
|
25
|
+
# @example
|
26
|
+
# If the controller_namespace is specified as 'API', and
|
27
|
+
# the controller name is API::ObjectsController,
|
28
|
+
# API:: will be ignored from the name. However if the
|
29
|
+
# controller_namespace is left blank, API will be assumed to
|
30
|
+
# be a part of the model's namespace.
|
31
|
+
# @return [String] the optional namespace of all controllers
|
32
|
+
def namespace
|
33
|
+
namespace = SkinnyControllers.controller_namespace || ''
|
34
|
+
"#{namespace}::" if namespace
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module SkinnyControllers
|
2
|
+
module Lookup
|
3
|
+
module Model
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# @example 'ObjectOperations::Verb' => Object
|
7
|
+
#
|
8
|
+
# @return [Class] class based on the operation
|
9
|
+
def class_from_operation(operation_name)
|
10
|
+
# "Namespace::Model" => "Model"
|
11
|
+
model_name = Model.name_from_operation(operation_name)
|
12
|
+
# object_type_of_interest.demodulize
|
13
|
+
|
14
|
+
# "Model" => Model
|
15
|
+
model_name.constantize
|
16
|
+
end
|
17
|
+
|
18
|
+
# @example 'Namespace::ModelOperation::Verb' => 'Model'
|
19
|
+
# @return [String] the model name corresponding to the operation
|
20
|
+
def name_from_operation(operation_name)
|
21
|
+
# operation_name is something of the form:
|
22
|
+
# Namespace::ModelOperations::Verb
|
23
|
+
|
24
|
+
# Namespace::ModelOperations::Verb => Namespace::ModelOperations
|
25
|
+
namespace = operation_name.deconstantize
|
26
|
+
# Namespace::ModelOperations => ModelOperations
|
27
|
+
nested_namespace = namespace.demodulize
|
28
|
+
# ModelOperations => Model
|
29
|
+
nested_namespace.gsub(SkinnyControllers.operations_suffix, '')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module SkinnyControllers
|
2
|
+
module Lookup
|
3
|
+
module Operation
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# @example ObjectOperations::Verb
|
7
|
+
#
|
8
|
+
# @param [String] model_name name of the model
|
9
|
+
# @param [String] verb the verb/action for the operation
|
10
|
+
# @return [Class] the operation based on the model name and the verb
|
11
|
+
def operation_of(model_name, verb)
|
12
|
+
klass_name = Lookup::Operation.name_from_model(model_name, verb)
|
13
|
+
klass_name.safe_constantize
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [String] controller name of the controller class
|
17
|
+
# @param [String] verb
|
18
|
+
# @param [String] model_name optional
|
19
|
+
# @return [Class] the class or default
|
20
|
+
def from_controller(controller, verb, model_name = nil)
|
21
|
+
model_name ||= Lookup::Controller.model_name(controller)
|
22
|
+
klass = operation_of(model_name, verb)
|
23
|
+
klass || default_operation_class_for(model_name)
|
24
|
+
end
|
25
|
+
|
26
|
+
# dynamically creates a module for the model if it
|
27
|
+
# isn't already defined
|
28
|
+
# @return [Class] default operation class
|
29
|
+
def default_operation_class_for(model_name)
|
30
|
+
default_operation = SkinnyControllers::Operation::Default
|
31
|
+
namespace = Lookup::Operation.default_operation_namespace_for(model_name)
|
32
|
+
|
33
|
+
default = "#{namespace.name}::Default".safe_constantize
|
34
|
+
default || namespace.const_set('Default'.freeze, default_operation.dup)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [Class] namespace for the default operation class
|
38
|
+
def default_operation_namespace_for(model_name)
|
39
|
+
desired_namespace = namespace_from_model(model_name)
|
40
|
+
|
41
|
+
parent_namespace = SkinnyControllers.operations_namespace
|
42
|
+
namespace = "#{parent_namespace}::#{desired_namespace}".safe_constantize
|
43
|
+
namespace || Object.const_set(desired_namespace, Module.new)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @example 'Object' => 'ObjectOperations'
|
47
|
+
# @return [String] the operation namespace based on the model name
|
48
|
+
def namespace_from_model(model_name)
|
49
|
+
"#{model_name}#{SkinnyControllers.operations_suffix}"
|
50
|
+
end
|
51
|
+
|
52
|
+
# @example 'Model', 'Verb' => [optional namespace]::ModelOperations::Verb
|
53
|
+
#
|
54
|
+
# @param [String] model_name name of the model
|
55
|
+
# @param [String] the verb/action for the operation
|
56
|
+
# @return [String] the operation based on the model name
|
57
|
+
def name_from_model(model_name, verb)
|
58
|
+
# this namespace is '' by default
|
59
|
+
prefix = SkinnyControllers.operations_namespace
|
60
|
+
namespace = Lookup::Operation.namespace_from_model(model_name)
|
61
|
+
"#{prefix}::#{namespace}::#{verb}"
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SkinnyControllers
|
2
|
+
module Lookup
|
3
|
+
module Policy
|
4
|
+
module_function
|
5
|
+
|
6
|
+
# @param [String] name the name of the model
|
7
|
+
# @return [Class] the policy class
|
8
|
+
def class_from_model(name)
|
9
|
+
(
|
10
|
+
"#{namespace}::#{name}" +
|
11
|
+
SkinnyControllers.policy_suffix
|
12
|
+
).constantize
|
13
|
+
end
|
14
|
+
|
15
|
+
# @param [String] class_name name of the operation class
|
16
|
+
def method_name_for_operation(class_name)
|
17
|
+
class_name.demodulize.downcase + POLICY_METHOD_SUFFIX
|
18
|
+
end
|
19
|
+
|
20
|
+
def namespace
|
21
|
+
SkinnyControllers.policies_namespace
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -3,8 +3,8 @@ module SkinnyControllers
|
|
3
3
|
#
|
4
4
|
# An example Operation may looy like
|
5
5
|
#
|
6
|
-
# module
|
7
|
-
# class
|
6
|
+
# module EventOperations
|
7
|
+
# class Read < SkinnyControllers::Policy::Base
|
8
8
|
# def run
|
9
9
|
# model if allowed?
|
10
10
|
# end
|
@@ -13,13 +13,12 @@ module SkinnyControllers
|
|
13
13
|
#
|
14
14
|
# TODO: make the above the 'default' and not require to be defined
|
15
15
|
class Base
|
16
|
-
include PolicyHelpers
|
17
16
|
include ModelHelpers
|
18
17
|
|
19
18
|
attr_accessor :params, :current_user, :authorized_via_parent
|
20
19
|
|
21
20
|
def self.run(current_user, params)
|
22
|
-
object =
|
21
|
+
object = new(current_user, params)
|
23
22
|
object.run
|
24
23
|
end
|
25
24
|
|
@@ -41,34 +40,47 @@ module SkinnyControllers
|
|
41
40
|
end
|
42
41
|
|
43
42
|
def object_class
|
44
|
-
|
45
|
-
# "Namespace::Model" => "Model"
|
46
|
-
model_name = object_type_of_interest.demodulize
|
47
|
-
# "Model" => Model
|
48
|
-
@object_class = model_name.constantize
|
49
|
-
end
|
50
|
-
|
51
|
-
@object_class
|
43
|
+
@object_class ||= Lookup::Model.class_from_operation(self.class.name)
|
52
44
|
end
|
53
45
|
|
54
46
|
def object_type_of_interest
|
55
|
-
|
56
|
-
# Namespace::ModelOperations::Verb
|
57
|
-
klass_name = self.class.name
|
58
|
-
# Namespace::ModelOperations::Verb => Namespace::ModelOperations
|
59
|
-
namespace = klass_name.deconstantize
|
60
|
-
# Namespace::ModelOperations => ModelOperations
|
61
|
-
nested_namespace = namespace.demodulize
|
62
|
-
# ModelOperations => Model
|
63
|
-
@object_type_name = nested_namespace.gsub(SkinnyControllers.operations_suffix, '')
|
64
|
-
end
|
65
|
-
|
66
|
-
@object_type_name
|
47
|
+
@object_type_name ||= Lookup::Model.name_from_operation(self.class.name)
|
67
48
|
end
|
68
49
|
|
69
50
|
def association_name_from_object
|
70
51
|
object_type_of_interest.tableize
|
71
52
|
end
|
53
|
+
|
54
|
+
# Takes the class name of self and converts it to a Policy class name
|
55
|
+
#
|
56
|
+
# @example In Operation::Event::Read, Policy::EventPolicy is returned
|
57
|
+
def policy_class
|
58
|
+
@policy_class ||= Lookup::Policy.class_from_model(object_type_of_interest)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Converts the class name to the method name to call on the policy
|
62
|
+
#
|
63
|
+
# @example Operation::Event::Read would become read?
|
64
|
+
def policy_method_name
|
65
|
+
@policy_method_name ||= Lookup::Policy.method_name_for_operation(self.class.name)
|
66
|
+
end
|
67
|
+
|
68
|
+
# @return a new policy object and caches it
|
69
|
+
def policy_for(object)
|
70
|
+
@policy ||= policy_class.new(
|
71
|
+
current_user,
|
72
|
+
object,
|
73
|
+
authorized_via_parent: authorized_via_parent)
|
74
|
+
end
|
75
|
+
|
76
|
+
def allowed?
|
77
|
+
allowed_for?(model)
|
78
|
+
end
|
79
|
+
|
80
|
+
# checks the policy
|
81
|
+
def allowed_for?(object)
|
82
|
+
policy_for(object).send(policy_method_name)
|
83
|
+
end
|
72
84
|
end
|
73
85
|
end
|
74
86
|
end
|
@@ -4,8 +4,6 @@ module SkinnyControllers
|
|
4
4
|
def model
|
5
5
|
# TODO: not sure if multiple ids is a good idea here
|
6
6
|
# if we don't have a(ny) id(s), get all of them
|
7
|
-
|
8
|
-
|
9
7
|
@model ||=
|
10
8
|
if id_from_params
|
11
9
|
model_from_id
|
@@ -27,8 +25,8 @@ module SkinnyControllers
|
|
27
25
|
def scoped_model(scoped_params)
|
28
26
|
unless @scoped_model
|
29
27
|
klass_name = scoped_params[:type]
|
30
|
-
|
31
|
-
operation =
|
28
|
+
operation_class = Lookup::Operation.operation_of(klass_name, DefaultVerbs::Read)
|
29
|
+
operation = operation_class.new(current_user, id: scoped_params[:id])
|
32
30
|
@scoped_model = operation.run
|
33
31
|
self.authorized_via_parent = !!@scoped_model
|
34
32
|
end
|
@@ -36,22 +34,13 @@ module SkinnyControllers
|
|
36
34
|
@scoped_model
|
37
35
|
end
|
38
36
|
|
39
|
-
def operation_for(klass_name, verb)
|
40
|
-
operations_class_namespace +
|
41
|
-
klass_name +
|
42
|
-
SkinnyControllers.operations_suffix +
|
43
|
-
"::#{verb}"
|
44
|
-
end
|
45
|
-
|
46
|
-
def operations_class_namespace
|
47
|
-
namespace = SkinnyControllers.policies_namespace
|
48
|
-
"#{namespace}::" if namespace
|
49
|
-
end
|
50
|
-
|
51
37
|
def model_from_params
|
52
38
|
ar_proxy = object_class.where(sanitized_params)
|
53
39
|
|
54
40
|
if ar_proxy.respond_to? SkinnyControllers.accessible_to_scope
|
41
|
+
# It's better to filter in sql, than in the app, so if there is
|
42
|
+
# a way to do the filtering in active query, do that. This will help
|
43
|
+
# mitigate n+1 query scenarios
|
55
44
|
return ar_proxy.accessible_to(current_user)
|
56
45
|
end
|
57
46
|
|
data/lib/skinny_controllers.rb
CHANGED
@@ -7,21 +7,20 @@ require 'active_support/core_ext/string/inflections'
|
|
7
7
|
|
8
8
|
# files for this gem
|
9
9
|
require 'skinny_controllers/default_verbs'
|
10
|
+
require 'skinny_controllers/lookup/controller'
|
11
|
+
require 'skinny_controllers/lookup/model'
|
12
|
+
require 'skinny_controllers/lookup/operation'
|
13
|
+
require 'skinny_controllers/lookup/policy'
|
10
14
|
require 'skinny_controllers/policy/base'
|
11
|
-
require 'skinny_controllers/operation/policy_helpers'
|
12
15
|
require 'skinny_controllers/operation/model_helpers'
|
13
16
|
require 'skinny_controllers/operation/base'
|
14
17
|
require 'skinny_controllers/operation/default'
|
15
18
|
require 'skinny_controllers/diet'
|
16
19
|
require 'skinny_controllers/version'
|
17
20
|
|
18
|
-
# load the policies and operations to the top level name space.
|
19
|
-
if defined? Rails
|
20
|
-
$LOAD_PATH.unshift Rails.root + '/app/operations'
|
21
|
-
$LOAD_PATH.unshift Rails.root + '/app/policies'
|
22
|
-
end
|
23
|
-
|
24
21
|
module SkinnyControllers
|
22
|
+
POLICY_METHOD_SUFFIX = '?'.freeze
|
23
|
+
|
25
24
|
# Tells the Diet what namespace of the controller
|
26
25
|
# isn't going to be part of the model name
|
27
26
|
#
|
@@ -32,11 +31,11 @@ module SkinnyControllers
|
|
32
31
|
cattr_accessor :controller_namespace
|
33
32
|
|
34
33
|
cattr_accessor :operations_suffix do
|
35
|
-
'Operations'
|
34
|
+
'Operations'.freeze
|
36
35
|
end
|
37
36
|
|
38
37
|
cattr_accessor :policy_suffix do
|
39
|
-
'Policy'
|
38
|
+
'Policy'.freeze
|
40
39
|
end
|
41
40
|
|
42
41
|
cattr_accessor :operations_namespace do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: skinny_controllers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.3'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- L. Preston Sego III
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-11-
|
11
|
+
date: 2015-11-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -189,10 +189,13 @@ files:
|
|
189
189
|
- lib/skinny_controllers.rb
|
190
190
|
- lib/skinny_controllers/default_verbs.rb
|
191
191
|
- lib/skinny_controllers/diet.rb
|
192
|
+
- lib/skinny_controllers/lookup/controller.rb
|
193
|
+
- lib/skinny_controllers/lookup/model.rb
|
194
|
+
- lib/skinny_controllers/lookup/operation.rb
|
195
|
+
- lib/skinny_controllers/lookup/policy.rb
|
192
196
|
- lib/skinny_controllers/operation/base.rb
|
193
197
|
- lib/skinny_controllers/operation/default.rb
|
194
198
|
- lib/skinny_controllers/operation/model_helpers.rb
|
195
|
-
- lib/skinny_controllers/operation/policy_helpers.rb
|
196
199
|
- lib/skinny_controllers/policy/base.rb
|
197
200
|
- lib/skinny_controllers/version.rb
|
198
201
|
homepage: https://github.com/NullVoxPopuli/skinny-controllers
|
@@ -218,5 +221,5 @@ rubyforge_project:
|
|
218
221
|
rubygems_version: 2.4.8
|
219
222
|
signing_key:
|
220
223
|
specification_version: 4
|
221
|
-
summary: SkinnyControllers-0.
|
224
|
+
summary: SkinnyControllers-0.3
|
222
225
|
test_files: []
|
@@ -1,49 +0,0 @@
|
|
1
|
-
module SkinnyControllers
|
2
|
-
module Operation
|
3
|
-
module PolicyHelpers
|
4
|
-
POLICY_METHOD_SUFFIX = '?'.freeze
|
5
|
-
|
6
|
-
# Takes the class name of self and converts it to a Policy class name
|
7
|
-
#
|
8
|
-
# @example In Operation::Event::Read, Policy::EventPolicy is returned
|
9
|
-
def policy_class
|
10
|
-
@policy_class ||= (
|
11
|
-
policy_class_namespace +
|
12
|
-
object_type_of_interest +
|
13
|
-
SkinnyControllers.policy_suffix
|
14
|
-
).constantize
|
15
|
-
end
|
16
|
-
|
17
|
-
# Converts the class name to the method name to call on the policy
|
18
|
-
#
|
19
|
-
# @example Operation::Event::Read would become read?
|
20
|
-
def policy_method_name
|
21
|
-
@policy_method_name ||= self.class.name.demodulize.downcase + POLICY_METHOD_SUFFIX
|
22
|
-
end
|
23
|
-
|
24
|
-
# @return a new policy object and caches it
|
25
|
-
def policy_for(object)
|
26
|
-
@policy ||= policy_class.new(
|
27
|
-
current_user,
|
28
|
-
object,
|
29
|
-
authorized_via_parent: authorized_via_parent)
|
30
|
-
end
|
31
|
-
|
32
|
-
def allowed?
|
33
|
-
allowed_for?(model)
|
34
|
-
end
|
35
|
-
|
36
|
-
# checks the policy
|
37
|
-
def allowed_for?(object)
|
38
|
-
policy_for(object).send(policy_method_name)
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def policy_class_namespace
|
44
|
-
namespace = SkinnyControllers.policies_namespace
|
45
|
-
"#{namespace}::" if namespace
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|