has_strong_policy 0.0.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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Fudgefile +3 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +64 -0
- data/Guardfile +9 -0
- data/LICENSE.txt +22 -0
- data/README.md +125 -0
- data/Rakefile +5 -0
- data/TODO +14 -0
- data/has_strong_policy.gemspec +20 -0
- data/lib/has_strong_policy.rb +8 -0
- data/lib/has_strong_policy/controller_helper.rb +33 -0
- data/lib/has_strong_policy/policy.rb +30 -0
- data/lib/has_strong_policy/policy_definition.rb +34 -0
- data/lib/has_strong_policy/policy_set.rb +54 -0
- data/lib/has_strong_policy/version.rb +3 -0
- data/spec/lib/has_strong_policy/controller_helper_spec.rb +59 -0
- data/spec/lib/has_strong_policy/policy_definition_spec.rb +52 -0
- data/spec/lib/has_strong_policy/policy_set_spec.rb +57 -0
- data/spec/lib/has_strong_policy/policy_spec.rb +119 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/strong_param_interface_spec.rb +31 -0
- data/spec/support/mock_strong_params.rb +36 -0
- metadata +98 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Fudgefile
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
has_strong_policy (0.0.1)
|
|
5
|
+
activesupport
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: https://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
activesupport (3.2.12)
|
|
11
|
+
i18n (~> 0.6)
|
|
12
|
+
multi_json (~> 1.0)
|
|
13
|
+
coderay (1.0.8)
|
|
14
|
+
diff-lcs (1.1.3)
|
|
15
|
+
fudge (0.0.5)
|
|
16
|
+
activesupport
|
|
17
|
+
rainbow
|
|
18
|
+
thor
|
|
19
|
+
guard (1.6.1)
|
|
20
|
+
listen (>= 0.6.0)
|
|
21
|
+
lumberjack (>= 1.0.2)
|
|
22
|
+
pry (>= 0.9.10)
|
|
23
|
+
thor (>= 0.14.6)
|
|
24
|
+
guard-rspec (2.3.3)
|
|
25
|
+
guard (>= 1.1)
|
|
26
|
+
rspec (~> 2.11)
|
|
27
|
+
i18n (0.6.4)
|
|
28
|
+
listen (0.7.0)
|
|
29
|
+
lumberjack (1.0.2)
|
|
30
|
+
method_source (0.8.1)
|
|
31
|
+
multi_json (1.6.1)
|
|
32
|
+
pry (0.9.10)
|
|
33
|
+
coderay (~> 1.0.5)
|
|
34
|
+
method_source (~> 0.8)
|
|
35
|
+
slop (~> 3.3.1)
|
|
36
|
+
rainbow (1.1.4)
|
|
37
|
+
rake (10.0.3)
|
|
38
|
+
rb-fsevent (0.9.3)
|
|
39
|
+
rspec (2.12.0)
|
|
40
|
+
rspec-core (~> 2.12.0)
|
|
41
|
+
rspec-expectations (~> 2.12.0)
|
|
42
|
+
rspec-mocks (~> 2.12.0)
|
|
43
|
+
rspec-core (2.12.2)
|
|
44
|
+
rspec-expectations (2.12.1)
|
|
45
|
+
diff-lcs (~> 1.1.3)
|
|
46
|
+
rspec-mocks (2.12.1)
|
|
47
|
+
simplecov (0.7.1)
|
|
48
|
+
multi_json (~> 1.0)
|
|
49
|
+
simplecov-html (~> 0.7.1)
|
|
50
|
+
simplecov-html (0.7.1)
|
|
51
|
+
slop (3.3.3)
|
|
52
|
+
thor (0.16.0)
|
|
53
|
+
|
|
54
|
+
PLATFORMS
|
|
55
|
+
ruby
|
|
56
|
+
|
|
57
|
+
DEPENDENCIES
|
|
58
|
+
fudge
|
|
59
|
+
guard-rspec
|
|
60
|
+
has_strong_policy!
|
|
61
|
+
rake
|
|
62
|
+
rb-fsevent
|
|
63
|
+
rspec
|
|
64
|
+
simplecov
|
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2013 Jonathan Lozinski
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
[](https://travis-ci.org/loz/has_strong_policy)
|
|
2
|
+
[](https://codeclimate.com/github/loz/has_strong_policy)
|
|
3
|
+
|
|
4
|
+
# HasStrongPolicy
|
|
5
|
+
|
|
6
|
+
Simple delegation for your strong paramters
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
Add this line to your application's Gemfile:
|
|
11
|
+
|
|
12
|
+
gem 'has_strong_policy'
|
|
13
|
+
|
|
14
|
+
And then execute:
|
|
15
|
+
|
|
16
|
+
$ bundle
|
|
17
|
+
|
|
18
|
+
Or install it yourself as:
|
|
19
|
+
|
|
20
|
+
$ gem install has_strong_policy
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
This gem provides a simple delgation framework for controllers and similar for
|
|
25
|
+
using strong parameters in rails. This allows:
|
|
26
|
+
|
|
27
|
+
* Shared policy to be applied for multiple similar models (eg. STI)
|
|
28
|
+
* Shared policy for the same model in different contexts (e.g. APIs)
|
|
29
|
+
* More expressive declaration of paramter securing policies
|
|
30
|
+
|
|
31
|
+
### Connecting your controller
|
|
32
|
+
|
|
33
|
+
To use HasStrongPolicy in your rails controller, simply include it, and turn it on:
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
```ruby
|
|
37
|
+
class UserController < ApplicationController
|
|
38
|
+
include HasStrongPolicy::ControllerHelper
|
|
39
|
+
|
|
40
|
+
has_strong_policy
|
|
41
|
+
end
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
This will provider automatic delgation to a conventionally named ParamsPolicy,
|
|
45
|
+
in this case this would be the UserParamsPolicy.
|
|
46
|
+
|
|
47
|
+
To access the params, simply use the `policy_params` helper, and you'll receive
|
|
48
|
+
a clean param hash with all the policy already applied to strong params
|
|
49
|
+
|
|
50
|
+
You can specify a specifc class to delegate security to by providing `:using`:
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
```ruby
|
|
54
|
+
class SettingsController < ApplicationController
|
|
55
|
+
include HasStrongPolicy::ControllerHelper
|
|
56
|
+
|
|
57
|
+
has_strong_policy :using => UserParamsPolicy
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
#### Requesting the Params
|
|
62
|
+
|
|
63
|
+
You request the params filtered through the policy using `policy_params` in
|
|
64
|
+
place of regular `params`. You can also supply options, like so:
|
|
65
|
+
|
|
66
|
+
```ruby
|
|
67
|
+
User.new(policy_params(:as => :admin))
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Defining your securing policy
|
|
71
|
+
|
|
72
|
+
You can a plain old ruby object for your policy object, or use the given policy
|
|
73
|
+
definition class to build expressive rulesets.
|
|
74
|
+
|
|
75
|
+
#### Simple Ruby Interface
|
|
76
|
+
|
|
77
|
+
Your ruby class should be named conventionally (unless you explicitly specify
|
|
78
|
+
with `:using`. The object simply needs to respond to `:apply` taking the
|
|
79
|
+
rails params and an options hash.
|
|
80
|
+
|
|
81
|
+
```ruby
|
|
82
|
+
class UserParamsPolicy
|
|
83
|
+
def apply(params, options)
|
|
84
|
+
acceptable = [:email, :name]
|
|
85
|
+
if options[:role] == :admin
|
|
86
|
+
acceptable << :is_admin
|
|
87
|
+
end
|
|
88
|
+
params.require(:user).permit(acceptable)
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
#### Using the Policy class and DSL:
|
|
94
|
+
|
|
95
|
+
Secures Params provides a DSL based policy class which allows succinct definition
|
|
96
|
+
of policies for defaults, specific actions or older accesible :as style roles:
|
|
97
|
+
|
|
98
|
+
```ruby
|
|
99
|
+
class UserParamsPolicy < HasStrongPolicy::Policy
|
|
100
|
+
policy do |p|
|
|
101
|
+
p.required :user
|
|
102
|
+
p.permitted :first_name, :last_name, :dob
|
|
103
|
+
|
|
104
|
+
p.on :create do |p|
|
|
105
|
+
p.permitted :email
|
|
106
|
+
|
|
107
|
+
p.as :admin do |p|
|
|
108
|
+
p.permitted :is_admin
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Sub definitions inherit the policy from prior ones. So in the above case, user
|
|
116
|
+
has name and dob permitted, but in the create action they can also set email.
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
## Contributing
|
|
120
|
+
|
|
121
|
+
1. Fork it
|
|
122
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
123
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
124
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
125
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/TODO
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
TODO
|
|
2
|
+
|
|
3
|
+
[ ] - possibly supply controller as :context for block evals?
|
|
4
|
+
[ ] - nesting: p.secures :nested_attribute [, :using => :nested]
|
|
5
|
+
|
|
6
|
+
Context stuff.. (passing controller for additional flexibility)
|
|
7
|
+
|
|
8
|
+
with_context do |ctx|
|
|
9
|
+
if ctx.foo?
|
|
10
|
+
...
|
|
11
|
+
else
|
|
12
|
+
...
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'has_strong_policy/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |gem|
|
|
7
|
+
gem.name = "has_strong_policy"
|
|
8
|
+
gem.version = HasStrongPolicy::VERSION
|
|
9
|
+
gem.authors = ["Jonathan Lozinski"]
|
|
10
|
+
gem.email = ["jonathan.lozinski@gmail.com"]
|
|
11
|
+
gem.description = %q{Simple params policy delegation for rails}
|
|
12
|
+
gem.summary = %q{A simple delgation framework for strong parameters}
|
|
13
|
+
gem.homepage = ""
|
|
14
|
+
|
|
15
|
+
gem.files = `git ls-files`.split($/)
|
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
18
|
+
gem.require_paths = ["lib"]
|
|
19
|
+
gem.add_dependency 'activesupport'
|
|
20
|
+
end
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
require "has_strong_policy/version"
|
|
2
|
+
|
|
3
|
+
module HasStrongPolicy
|
|
4
|
+
autoload :ControllerHelper, 'has_strong_policy/controller_helper'
|
|
5
|
+
autoload :Policy, 'has_strong_policy/policy'
|
|
6
|
+
autoload :PolicyDefinition, 'has_strong_policy/policy_definition'
|
|
7
|
+
autoload :PolicySet, 'has_strong_policy/policy_set'
|
|
8
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
require 'active_support/core_ext'
|
|
2
|
+
|
|
3
|
+
module HasStrongPolicy::ControllerHelper
|
|
4
|
+
def self.included(base)
|
|
5
|
+
base.extend ClassMethods
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
module ClassMethods
|
|
9
|
+
def has_strong_policy(options = {})
|
|
10
|
+
include HasStrongPolicy::ControllerHelper::HasHasStrongPolicy
|
|
11
|
+
@_policy_class = options[:using]
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
module HasHasStrongPolicy
|
|
16
|
+
def self.included(base)
|
|
17
|
+
base.extend ClassMethods
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def policy_params
|
|
21
|
+
self.class.policy_class.new(params).apply
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
module ClassMethods
|
|
25
|
+
def policy_class
|
|
26
|
+
return @_policy_class if @_policy_class
|
|
27
|
+
name = self.name.gsub(/Controller/, '') + 'ParamsPolicy'
|
|
28
|
+
@_policy_class = name.constantize
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class HasStrongPolicy::Policy
|
|
2
|
+
def self.inherited(base)
|
|
3
|
+
base.instance_eval do
|
|
4
|
+
@policy_set = HasStrongPolicy::PolicySet.new
|
|
5
|
+
|
|
6
|
+
def policy_set
|
|
7
|
+
@policy_set
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.policy(&block)
|
|
13
|
+
policy_set.with_condition({},nil,&block)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def apply(params, options = {})
|
|
17
|
+
conditions = build_conditions(params, options)
|
|
18
|
+
self.class.policy_set.with_condition(conditions).apply(params, options)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def build_conditions(params, options)
|
|
24
|
+
conditions = {}
|
|
25
|
+
conditions[:action] = params[:action] if params[:action]
|
|
26
|
+
conditions[:as] = options[:as] if options[:as]
|
|
27
|
+
conditions
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class HasStrongPolicy::PolicyDefinition
|
|
2
|
+
def required(required)
|
|
3
|
+
@required = required
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def permitted(*keys)
|
|
7
|
+
@permitted ||= []
|
|
8
|
+
@permitted += keys
|
|
9
|
+
@permitted.flatten!
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def extend_from(target)
|
|
13
|
+
@required = target.get_required
|
|
14
|
+
@permitted = target.get_permitted
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def apply(params, options = {})
|
|
18
|
+
applied = params
|
|
19
|
+
applied = applied.require(@required) if @required
|
|
20
|
+
applied = applied.permit(*@permitted) if @permitted
|
|
21
|
+
applied
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
protected
|
|
25
|
+
|
|
26
|
+
def get_permitted
|
|
27
|
+
@permitted
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def get_required
|
|
31
|
+
@required
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
class HasStrongPolicy::PolicySet
|
|
2
|
+
def initialize
|
|
3
|
+
@definitions = Hash.new do |h,k|
|
|
4
|
+
h[k] = HasStrongPolicy::PolicyDefinition.new
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def with_condition(condition, parent = nil)
|
|
9
|
+
d = @definitions[condition]
|
|
10
|
+
d.extend_from(parent) if parent
|
|
11
|
+
proxy = Proxy.new(condition, self, d)
|
|
12
|
+
yield proxy if block_given?
|
|
13
|
+
proxy
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class Proxy
|
|
17
|
+
attr_reader :conditions, :set, :definition
|
|
18
|
+
|
|
19
|
+
def initialize(conditions, set, definition)
|
|
20
|
+
@conditions = conditions
|
|
21
|
+
@definition = definition
|
|
22
|
+
@set = set
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def apply(*args)
|
|
26
|
+
definition.apply(*args)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def required(*args)
|
|
30
|
+
definition.required(*args)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def permitted(*args)
|
|
34
|
+
definition.permitted(*args)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def on(action)
|
|
38
|
+
with_condition({:action => action}) do |definition|
|
|
39
|
+
yield definition
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def as(role)
|
|
44
|
+
with_condition({:as => role}) do |definition|
|
|
45
|
+
yield definition
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def with_condition(condition, &block)
|
|
50
|
+
set.with_condition(conditions.merge(condition), definition, &block)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module HasStrongPolicy
|
|
4
|
+
|
|
5
|
+
class ExampleController
|
|
6
|
+
include ::HasStrongPolicy::ControllerHelper
|
|
7
|
+
|
|
8
|
+
attr_accessor :params
|
|
9
|
+
|
|
10
|
+
def initialize(params = {})
|
|
11
|
+
@params = params
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class XYZController < ExampleController; end
|
|
16
|
+
class XYZParamsPolicy; end
|
|
17
|
+
class FooParamsPolicy; end
|
|
18
|
+
|
|
19
|
+
describe ControllerHelper do
|
|
20
|
+
|
|
21
|
+
describe ".secures_params" do
|
|
22
|
+
let(:klass) { ExampleController.dup }
|
|
23
|
+
subject { klass.new }
|
|
24
|
+
|
|
25
|
+
it "adds a policy_params helper into the controller" do
|
|
26
|
+
subject.should_not respond_to :policy_params
|
|
27
|
+
klass.has_strong_policy
|
|
28
|
+
subject.should respond_to :policy_params
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context "when provided :using => " do
|
|
32
|
+
before :each do
|
|
33
|
+
klass.has_strong_policy :using => FooParamsPolicy
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "uses named constant as the securing class" do
|
|
37
|
+
klass.policy_class.should == FooParamsPolicy
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
describe "#policy_params" do
|
|
43
|
+
let(:klass) { XYZController }
|
|
44
|
+
|
|
45
|
+
subject { klass.new({:example => :params})}
|
|
46
|
+
|
|
47
|
+
before :each do
|
|
48
|
+
klass.has_strong_policy
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "returns params processed through XYZParamsPolicy for XYZController" do
|
|
52
|
+
policy = stub
|
|
53
|
+
XYZParamsPolicy.should_receive(:new).with(subject.params).and_return(policy)
|
|
54
|
+
policy.should_receive(:apply).and_return({:policy => :params})
|
|
55
|
+
subject.policy_params.should == {:policy => :params}
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe HasStrongPolicy::PolicyDefinition do
|
|
4
|
+
describe "required" do
|
|
5
|
+
it "adds a required constraint to be applied" do
|
|
6
|
+
subject.required :foo
|
|
7
|
+
params = mock
|
|
8
|
+
|
|
9
|
+
params.should_receive(:require).with(:foo).and_return(:applied)
|
|
10
|
+
|
|
11
|
+
subject.apply(params).should == :applied
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe "permitted" do
|
|
16
|
+
it "adds a permitted constraint to be applied" do
|
|
17
|
+
subject.permitted :foo, :bar
|
|
18
|
+
params = mock
|
|
19
|
+
|
|
20
|
+
params.should_receive(:permit).with(:foo, :bar).and_return(:permitted)
|
|
21
|
+
subject.apply(params).should == :permitted
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "appends new directives" do
|
|
25
|
+
subject.permitted :foo, :bar
|
|
26
|
+
subject.permitted :baz
|
|
27
|
+
params = mock
|
|
28
|
+
|
|
29
|
+
params.should_receive(:permit).with(:foo, :bar, :baz).and_return(:permitted)
|
|
30
|
+
subject.apply(params).should == :permitted
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "extend_from" do
|
|
35
|
+
it "copies the directives of the target" do
|
|
36
|
+
target = described_class.new
|
|
37
|
+
target.required :foo
|
|
38
|
+
target.permitted :bar
|
|
39
|
+
|
|
40
|
+
subject.extend_from(target)
|
|
41
|
+
subject.permitted :baz
|
|
42
|
+
|
|
43
|
+
params = mock
|
|
44
|
+
required = mock
|
|
45
|
+
|
|
46
|
+
params.should_receive(:require).with(:foo).and_return(required)
|
|
47
|
+
required.should_receive(:permit).with(:bar, :baz).and_return(:extended)
|
|
48
|
+
|
|
49
|
+
subject.apply(params).should == :extended
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module HasStrongPolicy
|
|
4
|
+
describe PolicySet do
|
|
5
|
+
describe "#with_condition" do
|
|
6
|
+
it "returns the definition for given condition" do
|
|
7
|
+
subject.with_condition(:foo => :base).should respond_to :apply
|
|
8
|
+
|
|
9
|
+
subject.with_condition(:foo => :bar).definition.should ==
|
|
10
|
+
subject.with_condition(:foo => :bar).definition
|
|
11
|
+
|
|
12
|
+
subject.with_condition(:foo => :bar).definition.should_not ==
|
|
13
|
+
subject.with_condition(:bar => :baz).definition
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
context "with a block" do
|
|
17
|
+
it "yields the definition" do
|
|
18
|
+
definition = nil
|
|
19
|
+
subject.with_condition :foo => :bar do |d|
|
|
20
|
+
definition = d.definition
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
subject.with_condition(:foo => :bar).definition.should == definition
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "delegates to the definition" do
|
|
27
|
+
proxy = nil
|
|
28
|
+
subject.with_condition :foo => :bar do |d|
|
|
29
|
+
proxy = d
|
|
30
|
+
end
|
|
31
|
+
defn = mock
|
|
32
|
+
proxy.stub(:definition).and_return(defn)
|
|
33
|
+
defn.should_receive(:apply)
|
|
34
|
+
defn.should_receive(:required)
|
|
35
|
+
defn.should_receive(:permitted)
|
|
36
|
+
proxy.apply(:foo)
|
|
37
|
+
proxy.required(:foo)
|
|
38
|
+
proxy.permitted(:foo)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "supports nesting conditions" do
|
|
42
|
+
nested = nil
|
|
43
|
+
subject.with_condition :foo => :bar do |d|
|
|
44
|
+
d.with_condition :bar => :baz do |n|
|
|
45
|
+
nested = n
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
expected = nested.definition
|
|
50
|
+
actual = subject.with_condition(:foo => :bar, :bar => :baz).definition
|
|
51
|
+
|
|
52
|
+
expected.should == actual
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module HasStrongPolicy
|
|
4
|
+
|
|
5
|
+
class ExamplePolicy < Policy
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
class AnotherPolicy < Policy
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe Policy do
|
|
12
|
+
let(:params) do
|
|
13
|
+
MockStrongParams.new({
|
|
14
|
+
:user => {
|
|
15
|
+
:name => 'Joe Bloggs',
|
|
16
|
+
:email => 'joe@bloggs.com',
|
|
17
|
+
:age => 21,
|
|
18
|
+
:phone => '12345',
|
|
19
|
+
:role => 'admin'
|
|
20
|
+
},
|
|
21
|
+
:foo => {
|
|
22
|
+
:something => 'bar'
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
let(:klass) { ExamplePolicy.dup }
|
|
28
|
+
subject { klass.new }
|
|
29
|
+
|
|
30
|
+
it "has unique policy for each subclass" do
|
|
31
|
+
klass1 = ExamplePolicy.dup
|
|
32
|
+
klass2 = AnotherPolicy.dup
|
|
33
|
+
klass1.policy do |p|
|
|
34
|
+
p.required :user
|
|
35
|
+
end
|
|
36
|
+
klass2.policy do |p|
|
|
37
|
+
p.required :foo
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
first = klass1.new
|
|
41
|
+
second = klass2.new
|
|
42
|
+
|
|
43
|
+
first.apply(params).to_hash.should_not == second.apply(params).to_hash
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "Defining default policy" do
|
|
47
|
+
|
|
48
|
+
before :each do
|
|
49
|
+
klass.policy do |p|
|
|
50
|
+
p.required :user
|
|
51
|
+
p.permitted :name, :age, :phone
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "is applied to result set" do
|
|
56
|
+
applied = subject.apply(params)
|
|
57
|
+
applied.to_hash.should == {
|
|
58
|
+
:name => 'Joe Bloggs',
|
|
59
|
+
:age => 21,
|
|
60
|
+
:phone => '12345'
|
|
61
|
+
}
|
|
62
|
+
applied.should be_permitted
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
describe "Conditional Policies" do
|
|
67
|
+
describe "on" do
|
|
68
|
+
before :each do
|
|
69
|
+
klass.policy do |p|
|
|
70
|
+
p.required :user
|
|
71
|
+
p.permitted :name, :age, :phone
|
|
72
|
+
|
|
73
|
+
p.on :create do |d|
|
|
74
|
+
d.permitted :email
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
params[:action] = :create
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "is applied when action is in params" do
|
|
81
|
+
applied = subject.apply(params)
|
|
82
|
+
applied[:email].should == 'joe@bloggs.com'
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
#This not working causes failure above too :(
|
|
86
|
+
it "inherits prior conditions" do
|
|
87
|
+
applied = subject.apply(params)
|
|
88
|
+
applied[:name].should == 'Joe Bloggs'
|
|
89
|
+
applied[:phone].should == '12345'
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
it "does not apply when action does not match" do
|
|
93
|
+
params[:action] = :foo
|
|
94
|
+
applied = subject.apply(params)
|
|
95
|
+
|
|
96
|
+
applied[:email].should be_nil
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
describe "as" do
|
|
101
|
+
before :each do
|
|
102
|
+
klass.policy do |p|
|
|
103
|
+
p.required :user
|
|
104
|
+
p.permitted :name, :age, :phone
|
|
105
|
+
|
|
106
|
+
p.as :admin do |d|
|
|
107
|
+
d.permitted :role
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "is applied when an :as => :role option is supplied" do
|
|
113
|
+
applied = subject.apply(params, :as => :admin)
|
|
114
|
+
applied[:role].should == 'admin'
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
|
4
|
+
# loaded once.
|
|
5
|
+
#
|
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
|
7
|
+
require 'simplecov'
|
|
8
|
+
SimpleCov.start
|
|
9
|
+
|
|
10
|
+
require 'has_strong_policy'
|
|
11
|
+
|
|
12
|
+
require File.expand_path("../support/mock_strong_params", __FILE__)
|
|
13
|
+
|
|
14
|
+
RSpec.configure do |config|
|
|
15
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
16
|
+
config.run_all_when_everything_filtered = true
|
|
17
|
+
config.filter_run :focus
|
|
18
|
+
|
|
19
|
+
# Run specs in random order to surface order dependencies. If you find an
|
|
20
|
+
# order dependency and want to debug it, you can fix the order by providing
|
|
21
|
+
# the seed, which is printed after each run.
|
|
22
|
+
# --seed 1234
|
|
23
|
+
config.order = 'random'
|
|
24
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe "The Interface for Strong Params" do
|
|
4
|
+
let(:params) do
|
|
5
|
+
MockStrongParams.new({
|
|
6
|
+
:user => {
|
|
7
|
+
:name => "Joe Bloggs",
|
|
8
|
+
:age => 21,
|
|
9
|
+
:phone => "12345",
|
|
10
|
+
:email => "joe@bloggs.com"
|
|
11
|
+
},
|
|
12
|
+
:foo => {
|
|
13
|
+
}
|
|
14
|
+
})
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "does require" do
|
|
18
|
+
params.require(:user)[:name].should == 'Joe Bloggs'
|
|
19
|
+
params.require(:foo).should_not be_permitted
|
|
20
|
+
|
|
21
|
+
expect { params.require(:not_present) }.to raise_error
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "does permit" do
|
|
25
|
+
perm = params.require(:user).permit(:name, :age)
|
|
26
|
+
perm.should be_permitted
|
|
27
|
+
perm[:name].should == 'Joe Bloggs'
|
|
28
|
+
perm[:age].should == 21
|
|
29
|
+
perm[:email].should be_nil
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class MockStrongParams
|
|
2
|
+
#For Test
|
|
3
|
+
attr_writer :permitted
|
|
4
|
+
def initialize(params = {})
|
|
5
|
+
@params = params
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def [](key)
|
|
9
|
+
@params[key]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def []=(key, value)
|
|
13
|
+
@params[key] = value
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_hash
|
|
17
|
+
@params
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
#API
|
|
21
|
+
def require(key)
|
|
22
|
+
found = @params.fetch(key) { raise 'RequiredMissing' }
|
|
23
|
+
self.class.new found
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def permit(*keys)
|
|
27
|
+
permitted = self.class.new(@params.select {|k,v| keys.include? k})
|
|
28
|
+
permitted.permitted = true
|
|
29
|
+
permitted
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def permitted?
|
|
33
|
+
@permitted
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
metadata
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: has_strong_policy
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Jonathan Lozinski
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2013-03-09 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: activesupport
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :runtime
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
+
none: false
|
|
26
|
+
requirements:
|
|
27
|
+
- - ! '>='
|
|
28
|
+
- !ruby/object:Gem::Version
|
|
29
|
+
version: '0'
|
|
30
|
+
description: Simple params policy delegation for rails
|
|
31
|
+
email:
|
|
32
|
+
- jonathan.lozinski@gmail.com
|
|
33
|
+
executables: []
|
|
34
|
+
extensions: []
|
|
35
|
+
extra_rdoc_files: []
|
|
36
|
+
files:
|
|
37
|
+
- .gitignore
|
|
38
|
+
- .rspec
|
|
39
|
+
- Fudgefile
|
|
40
|
+
- Gemfile
|
|
41
|
+
- Gemfile.lock
|
|
42
|
+
- Guardfile
|
|
43
|
+
- LICENSE.txt
|
|
44
|
+
- README.md
|
|
45
|
+
- Rakefile
|
|
46
|
+
- TODO
|
|
47
|
+
- has_strong_policy.gemspec
|
|
48
|
+
- lib/has_strong_policy.rb
|
|
49
|
+
- lib/has_strong_policy/controller_helper.rb
|
|
50
|
+
- lib/has_strong_policy/policy.rb
|
|
51
|
+
- lib/has_strong_policy/policy_definition.rb
|
|
52
|
+
- lib/has_strong_policy/policy_set.rb
|
|
53
|
+
- lib/has_strong_policy/version.rb
|
|
54
|
+
- spec/lib/has_strong_policy/controller_helper_spec.rb
|
|
55
|
+
- spec/lib/has_strong_policy/policy_definition_spec.rb
|
|
56
|
+
- spec/lib/has_strong_policy/policy_set_spec.rb
|
|
57
|
+
- spec/lib/has_strong_policy/policy_spec.rb
|
|
58
|
+
- spec/spec_helper.rb
|
|
59
|
+
- spec/strong_param_interface_spec.rb
|
|
60
|
+
- spec/support/mock_strong_params.rb
|
|
61
|
+
homepage: ''
|
|
62
|
+
licenses: []
|
|
63
|
+
post_install_message:
|
|
64
|
+
rdoc_options: []
|
|
65
|
+
require_paths:
|
|
66
|
+
- lib
|
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
68
|
+
none: false
|
|
69
|
+
requirements:
|
|
70
|
+
- - ! '>='
|
|
71
|
+
- !ruby/object:Gem::Version
|
|
72
|
+
version: '0'
|
|
73
|
+
segments:
|
|
74
|
+
- 0
|
|
75
|
+
hash: 2612279817966036190
|
|
76
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
77
|
+
none: false
|
|
78
|
+
requirements:
|
|
79
|
+
- - ! '>='
|
|
80
|
+
- !ruby/object:Gem::Version
|
|
81
|
+
version: '0'
|
|
82
|
+
segments:
|
|
83
|
+
- 0
|
|
84
|
+
hash: 2612279817966036190
|
|
85
|
+
requirements: []
|
|
86
|
+
rubyforge_project:
|
|
87
|
+
rubygems_version: 1.8.23
|
|
88
|
+
signing_key:
|
|
89
|
+
specification_version: 3
|
|
90
|
+
summary: A simple delgation framework for strong parameters
|
|
91
|
+
test_files:
|
|
92
|
+
- spec/lib/has_strong_policy/controller_helper_spec.rb
|
|
93
|
+
- spec/lib/has_strong_policy/policy_definition_spec.rb
|
|
94
|
+
- spec/lib/has_strong_policy/policy_set_spec.rb
|
|
95
|
+
- spec/lib/has_strong_policy/policy_spec.rb
|
|
96
|
+
- spec/spec_helper.rb
|
|
97
|
+
- spec/strong_param_interface_spec.rb
|
|
98
|
+
- spec/support/mock_strong_params.rb
|