action_policy 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +233 -171
- data/LICENSE.txt +1 -1
- data/README.md +7 -11
- data/lib/action_policy.rb +7 -1
- data/lib/action_policy/behaviour.rb +22 -16
- data/lib/action_policy/behaviours/policy_for.rb +10 -3
- data/lib/action_policy/behaviours/scoping.rb +2 -1
- data/lib/action_policy/behaviours/thread_memoized.rb +1 -3
- data/lib/action_policy/ext/module_namespace.rb +1 -6
- data/lib/action_policy/ext/policy_cache_key.rb +15 -33
- data/lib/action_policy/ext/{symbol_classify.rb → symbol_camelize.rb} +6 -6
- data/lib/action_policy/i18n.rb +1 -1
- data/lib/action_policy/lookup_chain.rb +41 -21
- data/lib/action_policy/policy/aliases.rb +7 -12
- data/lib/action_policy/policy/authorization.rb +14 -17
- data/lib/action_policy/policy/cache.rb +34 -18
- data/lib/action_policy/policy/core.rb +25 -12
- data/lib/action_policy/policy/defaults.rb +3 -9
- data/lib/action_policy/policy/execution_result.rb +3 -9
- data/lib/action_policy/policy/pre_check.rb +19 -58
- data/lib/action_policy/policy/reasons.rb +30 -20
- data/lib/action_policy/policy/scoping.rb +5 -6
- data/lib/action_policy/rails/controller.rb +6 -1
- data/lib/action_policy/rails/ext/active_record.rb +7 -0
- data/lib/action_policy/rails/policy/instrumentation.rb +1 -1
- data/lib/action_policy/rspec/be_authorized_to.rb +5 -9
- data/lib/action_policy/rspec/dsl.rb +3 -3
- data/lib/action_policy/rspec/have_authorized_scope.rb +5 -7
- data/lib/action_policy/testing.rb +1 -1
- data/lib/action_policy/utils/pretty_print.rb +21 -24
- data/lib/action_policy/utils/suggest_message.rb +1 -3
- data/lib/action_policy/version.rb +1 -1
- data/lib/generators/action_policy/install/templates/{application_policy.rb → application_policy.rb.tt} +1 -1
- data/lib/generators/action_policy/policy/policy_generator.rb +4 -1
- data/lib/generators/action_policy/policy/templates/{policy.rb → policy.rb.tt} +0 -0
- data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +0 -0
- data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
- metadata +30 -119
- data/.gitattributes +0 -2
- data/.github/FUNDING.yml +0 -1
- data/.github/ISSUE_TEMPLATE.md +0 -18
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -29
- data/.gitignore +0 -15
- data/.rubocop.yml +0 -54
- data/.tidelift.yml +0 -6
- data/.travis.yml +0 -31
- data/Gemfile +0 -22
- data/Rakefile +0 -27
- data/action_policy.gemspec +0 -44
- data/benchmarks/namespaced_lookup_cache.rb +0 -71
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/docs/.nojekyll +0 -0
- data/docs/CNAME +0 -1
- data/docs/README.md +0 -77
- data/docs/_sidebar.md +0 -27
- data/docs/aliases.md +0 -122
- data/docs/assets/docsify-search.js +0 -364
- data/docs/assets/docsify.min.js +0 -3
- data/docs/assets/fonts/FiraCode-Medium.woff +0 -0
- data/docs/assets/fonts/FiraCode-Regular.woff +0 -0
- data/docs/assets/images/banner.png +0 -0
- data/docs/assets/images/cache.png +0 -0
- data/docs/assets/images/cache.svg +0 -70
- data/docs/assets/images/layer.png +0 -0
- data/docs/assets/images/layer.svg +0 -35
- data/docs/assets/prism-ruby.min.js +0 -1
- data/docs/assets/styles.css +0 -347
- data/docs/assets/vue.min.css +0 -1
- data/docs/authorization_context.md +0 -92
- data/docs/behaviour.md +0 -113
- data/docs/caching.md +0 -273
- data/docs/controller_action_aliases.md +0 -109
- data/docs/custom_lookup_chain.md +0 -48
- data/docs/custom_policy.md +0 -53
- data/docs/debugging.md +0 -55
- data/docs/decorators.md +0 -27
- data/docs/favicon.ico +0 -0
- data/docs/graphql.md +0 -302
- data/docs/i18n.md +0 -44
- data/docs/index.html +0 -43
- data/docs/instrumentation.md +0 -84
- data/docs/lookup_chain.md +0 -17
- data/docs/namespaces.md +0 -77
- data/docs/non_rails.md +0 -28
- data/docs/pre_checks.md +0 -57
- data/docs/pundit_migration.md +0 -80
- data/docs/quick_start.md +0 -118
- data/docs/rails.md +0 -120
- data/docs/reasons.md +0 -120
- data/docs/scoping.md +0 -255
- data/docs/testing.md +0 -333
- data/docs/writing_policies.md +0 -107
- data/gemfiles/jruby.gemfile +0 -8
- data/gemfiles/rails42.gemfile +0 -8
- data/gemfiles/rails6.gemfile +0 -8
- data/gemfiles/railsmaster.gemfile +0 -6
- data/lib/action_policy/ext/string_match.rb +0 -14
- data/lib/action_policy/ext/yield_self_then.rb +0 -25
data/.gitattributes
DELETED
data/.github/FUNDING.yml
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
tidelift: "rubygems/action_policy"
|
data/.github/ISSUE_TEMPLATE.md
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
<!--
|
2
|
-
This template is for bug reports. If you are reporting a bug, please continue on. If you are here for another reason,
|
3
|
-
feel free to skip the rest of this template.
|
4
|
-
-->
|
5
|
-
|
6
|
-
### Tell us about your environment
|
7
|
-
|
8
|
-
**Ruby Version:**
|
9
|
-
|
10
|
-
**Framework Version (Rails, whatever):**
|
11
|
-
|
12
|
-
**Action Policy Version:**
|
13
|
-
|
14
|
-
### What did you do?
|
15
|
-
|
16
|
-
### What did you expect to happen?
|
17
|
-
|
18
|
-
### What actually happened?
|
@@ -1,29 +0,0 @@
|
|
1
|
-
<!--
|
2
|
-
First of all, thanks for contributing!
|
3
|
-
|
4
|
-
If it's a typo fix or minor documentation update feel free to skip the rest of this template!
|
5
|
-
-->
|
6
|
-
|
7
|
-
<!--
|
8
|
-
If it's a bug fix, then link it to the issue, for example:
|
9
|
-
|
10
|
-
Fixes #xxx
|
11
|
-
-->
|
12
|
-
|
13
|
-
|
14
|
-
<!--
|
15
|
-
Otherwise, describe the changes:
|
16
|
-
|
17
|
-
### What is the purpose of this pull request?
|
18
|
-
|
19
|
-
### What changes did you make? (overview)
|
20
|
-
|
21
|
-
### Is there anything you'd like reviewers to focus on?
|
22
|
-
|
23
|
-
-->
|
24
|
-
|
25
|
-
PR checklist:
|
26
|
-
|
27
|
-
- [ ] Tests included
|
28
|
-
- [ ] Documentation updated
|
29
|
-
- [ ] Changelog entry added
|
data/.gitignore
DELETED
data/.rubocop.yml
DELETED
@@ -1,54 +0,0 @@
|
|
1
|
-
require:
|
2
|
-
- standard/cop/semantic_blocks
|
3
|
-
- rubocop-md
|
4
|
-
|
5
|
-
inherit_gem:
|
6
|
-
standard: config/base.yml
|
7
|
-
|
8
|
-
AllCops:
|
9
|
-
Exclude:
|
10
|
-
- 'bin/*'
|
11
|
-
- 'tmp/**/*'
|
12
|
-
- 'Gemfile'
|
13
|
-
- 'vendor/**/*'
|
14
|
-
- 'gemfiles/**/*'
|
15
|
-
- 'lib/generators/**/templates/**/*'
|
16
|
-
DisplayCopNames: true
|
17
|
-
TargetRubyVersion: 2.4
|
18
|
-
|
19
|
-
Standard/SemanticBlocks:
|
20
|
-
Enabled: false
|
21
|
-
|
22
|
-
Style/FrozenStringLiteralComment:
|
23
|
-
Enabled: true
|
24
|
-
|
25
|
-
Style/TrailingCommaInArrayLiteral:
|
26
|
-
EnforcedStyleForMultiline: no_comma
|
27
|
-
|
28
|
-
Style/TrailingCommaInHashLiteral:
|
29
|
-
EnforcedStyleForMultiline: no_comma
|
30
|
-
|
31
|
-
Layout/AlignParameters:
|
32
|
-
EnforcedStyle: with_first_parameter
|
33
|
-
|
34
|
-
Lint/Void:
|
35
|
-
Exclude:
|
36
|
-
- '**/*.md'
|
37
|
-
|
38
|
-
# See https://github.com/rubocop-hq/rubocop/issues/4222
|
39
|
-
Lint/AmbiguousBlockAssociation:
|
40
|
-
Exclude:
|
41
|
-
- 'spec/**/*'
|
42
|
-
- '**/*.md'
|
43
|
-
|
44
|
-
Lint/DuplicateMethods:
|
45
|
-
Exclude:
|
46
|
-
- '**/*.md'
|
47
|
-
|
48
|
-
Naming/FileName:
|
49
|
-
Exclude:
|
50
|
-
- '**/*.md'
|
51
|
-
|
52
|
-
Layout/InitialIndentation:
|
53
|
-
Exclude:
|
54
|
-
- 'CHANGELOG.md'
|
data/.tidelift.yml
DELETED
data/.travis.yml
DELETED
@@ -1,31 +0,0 @@
|
|
1
|
-
sudo: false
|
2
|
-
language: ruby
|
3
|
-
cache: bundler
|
4
|
-
notifications:
|
5
|
-
email: false
|
6
|
-
|
7
|
-
before_install:
|
8
|
-
- gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
|
9
|
-
- gem install bundler -v '< 2'
|
10
|
-
|
11
|
-
script:
|
12
|
-
- bundle exec rake test:ci
|
13
|
-
|
14
|
-
matrix:
|
15
|
-
fast_finish: true
|
16
|
-
include:
|
17
|
-
- rvm: ruby-head
|
18
|
-
gemfile: gemfiles/railsmaster.gemfile
|
19
|
-
- rvm: jruby-9.2.8.0
|
20
|
-
gemfile: gemfiles/jruby.gemfile
|
21
|
-
- rvm: 2.6.0
|
22
|
-
gemfile: gemfiles/rails6.gemfile
|
23
|
-
- rvm: 2.5.3
|
24
|
-
gemfile: Gemfile
|
25
|
-
- rvm: 2.4.3
|
26
|
-
gemfile: gemfiles/rails42.gemfile
|
27
|
-
allow_failures:
|
28
|
-
- rvm: ruby-head
|
29
|
-
gemfile: gemfiles/railsmaster.gemfile
|
30
|
-
- rvm: jruby-9.2.8.0
|
31
|
-
gemfile: gemfiles/jruby.gemfile
|
data/Gemfile
DELETED
@@ -1,22 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gemspec
|
6
|
-
|
7
|
-
gem "pry-byebug", platform: :mri
|
8
|
-
|
9
|
-
gem "method_source"
|
10
|
-
gem "unparser"
|
11
|
-
|
12
|
-
gem 'sqlite3', "~> 1.3.0", platform: :mri
|
13
|
-
gem 'activerecord-jdbcsqlite3-adapter', '~> 50.0', platform: :jruby
|
14
|
-
gem 'jdbc-sqlite3', platform: :jruby
|
15
|
-
|
16
|
-
local_gemfile = File.join(__dir__, "Gemfile.local")
|
17
|
-
|
18
|
-
if File.exist?(local_gemfile)
|
19
|
-
eval(File.read(local_gemfile)) # rubocop:disable Security/Eval
|
20
|
-
else
|
21
|
-
gem "rails", "~> 5.0"
|
22
|
-
end
|
data/Rakefile
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "rake/testtask"
|
4
|
-
require "rubocop/rake_task"
|
5
|
-
require "rspec/core/rake_task"
|
6
|
-
|
7
|
-
RuboCop::RakeTask.new
|
8
|
-
|
9
|
-
RSpec::Core::RakeTask.new(:spec)
|
10
|
-
|
11
|
-
Rake::TestTask.new(:test) do |t|
|
12
|
-
t.libs << "test"
|
13
|
-
t.libs << "lib"
|
14
|
-
t.test_files = FileList["test/**/*_test.rb"]
|
15
|
-
end
|
16
|
-
|
17
|
-
namespace :test do
|
18
|
-
task :isolated do
|
19
|
-
Dir.glob("test/**/*_test.rb").all? do |file|
|
20
|
-
sh(Gem.ruby, "-w", "-Ilib:test", file)
|
21
|
-
end || raise("Failures")
|
22
|
-
end
|
23
|
-
|
24
|
-
task ci: %w[rubocop test:isolated spec]
|
25
|
-
end
|
26
|
-
|
27
|
-
task default: [:rubocop, :test, :spec]
|
data/action_policy.gemspec
DELETED
@@ -1,44 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
lib = File.expand_path("lib", __dir__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require "action_policy/version"
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = "action_policy"
|
9
|
-
spec.version = ActionPolicy::VERSION
|
10
|
-
spec.authors = ["Vladimir Dementyev"]
|
11
|
-
spec.email = ["dementiev.vm@gmail.com"]
|
12
|
-
|
13
|
-
spec.summary = "Authorization framework for Ruby/Rails application"
|
14
|
-
spec.description = "Authorization framework for Ruby/Rails application"
|
15
|
-
spec.homepage = "https://github.com/palkan/action_policy"
|
16
|
-
spec.license = "MIT"
|
17
|
-
|
18
|
-
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
19
|
-
f.match(%r{^(test|spec|features)/})
|
20
|
-
end
|
21
|
-
|
22
|
-
spec.metadata = {
|
23
|
-
"bug_tracker_uri" => "http://github.com/palkan/action_policy/issues",
|
24
|
-
"changelog_uri" => "https://github.com/palkan/action_policy/blob/master/CHANGELOG.md",
|
25
|
-
"documentation_uri" => "https://actionpolicy.evilmartians.io/",
|
26
|
-
"homepage_uri" => "https://actionpolicy.evilmartians.io/",
|
27
|
-
"source_code_uri" => "http://github.com/palkan/action_policy"
|
28
|
-
}
|
29
|
-
|
30
|
-
spec.require_paths = ["lib"]
|
31
|
-
|
32
|
-
spec.required_ruby_version = ">= 2.4.0"
|
33
|
-
|
34
|
-
spec.add_development_dependency "ammeter", "~> 1.1.3"
|
35
|
-
spec.add_development_dependency "bundler", ">= 1.15"
|
36
|
-
spec.add_development_dependency "minitest", "~> 5.0"
|
37
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
38
|
-
spec.add_development_dependency "rspec", "~> 3.3"
|
39
|
-
spec.add_development_dependency "rubocop", "~> 0.67.0"
|
40
|
-
spec.add_development_dependency "rubocop-md", "~> 0.2"
|
41
|
-
spec.add_development_dependency "standard", "~> 0.0.39"
|
42
|
-
spec.add_development_dependency "benchmark-ips", "~> 2.7.0"
|
43
|
-
spec.add_development_dependency "i18n"
|
44
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
#
|
4
|
-
# This benchmark measures the efficiency of NamespaceCache.
|
5
|
-
#
|
6
|
-
# Run it multiple times with cache on/off to see the results:
|
7
|
-
#
|
8
|
-
# $ bundle exec ruby namespaced_lookup_cache.rb
|
9
|
-
# $ bundle exec ruby namespaced_lookup_cache.rb
|
10
|
-
# $ NO_CACHE=1 bundle exec ruby namespaced_lookup_cache.rb
|
11
|
-
# $ NO_CACHE=1 bundle exec ruby namespaced_lookup_cache.rb
|
12
|
-
#
|
13
|
-
|
14
|
-
$LOAD_PATH.unshift File.expand_path("../lib", __dir__)
|
15
|
-
|
16
|
-
require "action_policy"
|
17
|
-
require "benchmark/ips"
|
18
|
-
|
19
|
-
GC.disable
|
20
|
-
|
21
|
-
class A; end
|
22
|
-
|
23
|
-
class B; end
|
24
|
-
|
25
|
-
module X
|
26
|
-
class BPolicy < ActionPolicy::Base; end
|
27
|
-
|
28
|
-
module Y
|
29
|
-
module Z
|
30
|
-
class APolicy < ActionPolicy::Base; end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
a = A.new
|
36
|
-
b = B.new
|
37
|
-
|
38
|
-
if ENV["NO_CACHE"]
|
39
|
-
ActionPolicy::LookupChain.namespace_cache_enabled = false
|
40
|
-
end
|
41
|
-
|
42
|
-
Benchmark.ips do |x|
|
43
|
-
x.warmup = 0
|
44
|
-
|
45
|
-
x.report("cache A") do
|
46
|
-
ActionPolicy.lookup(a, namespace: X::Y::Z)
|
47
|
-
end
|
48
|
-
|
49
|
-
x.report("cache B") do
|
50
|
-
ActionPolicy.lookup(b, namespace: X::Y::Z)
|
51
|
-
end
|
52
|
-
|
53
|
-
x.report("no cache A") do
|
54
|
-
ActionPolicy.lookup(a, namespace: X::Y::Z)
|
55
|
-
end
|
56
|
-
|
57
|
-
x.report("no cache B") do
|
58
|
-
ActionPolicy.lookup(b, namespace: X::Y::Z)
|
59
|
-
end
|
60
|
-
|
61
|
-
x.hold! "temp_results"
|
62
|
-
|
63
|
-
x.compare!
|
64
|
-
end
|
65
|
-
|
66
|
-
#
|
67
|
-
# Comparison:
|
68
|
-
# cache B: 178577.4 i/s
|
69
|
-
# cache A: 173061.4 i/s - same-ish: difference falls within error
|
70
|
-
# no cache A: 97991.7 i/s - same-ish: difference falls within error
|
71
|
-
# no cache B: 42505.4 i/s - 4.20x slower
|
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "action_policy"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|
data/bin/setup
DELETED
data/docs/.nojekyll
DELETED
File without changes
|
data/docs/CNAME
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
actionpolicy.evilmartians.io
|
data/docs/README.md
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
[![Gem Version](https://badge.fury.io/rb/action_policy.svg)](https://badge.fury.io/rb/action_policy)
|
2
|
-
[![Build Status](https://travis-ci.org/palkan/action_policy.svg?branch=master)](https://travis-ci.org/palkan/action_policy)
|
3
|
-
|
4
|
-
## Action Policy
|
5
|
-
|
6
|
-
> Authorization framework for Ruby and Rails.
|
7
|
-
<br>Composable. Extensible. Performant.
|
8
|
-
|
9
|
-
**NOTE:** this documentation is for the version "0.3.0+".
|
10
|
-
|
11
|
-
## What is it?
|
12
|
-
|
13
|
-
_Authorization_ is an act of giving **someone** official
|
14
|
-
permission to **do something** (to not be confused with [_authentication_](https://en.wikipedia.org/wiki/Authentication)).
|
15
|
-
|
16
|
-
Action Policy provides flexible tools to build an _authorization layer_ for your application.
|
17
|
-
|
18
|
-
<div class="chart-container">
|
19
|
-
<img src="assets/images/layer.svg" alt="Authorization layer" width="80%">
|
20
|
-
</div>
|
21
|
-
|
22
|
-
**NOTE:** Action Policy does not force you to use a specific authorization model (i.e., roles, permissions, etc.) and does not provide one. It only answers a single question: **How to verify access?**
|
23
|
-
|
24
|
-
## Where to go from here?
|
25
|
-
- [Quick start](./quick_start.md)
|
26
|
-
- [Using with Rails](./rails.md)
|
27
|
-
- [Using with other Ruby frameworks](./non_rails.md)
|
28
|
-
- [Using with GraphQL Ruby](./graphql.md)
|
29
|
-
|
30
|
-
## Project State
|
31
|
-
|
32
|
-
The project is being used in production since mid 2018. Major features have been implemented, API has been stabilized. Check out our [development board](https://github.com/palkan/action_policy/projects/1) to see what's coming next.
|
33
|
-
|
34
|
-
## History
|
35
|
-
|
36
|
-
Action Policy gem is an _extraction_-kind of a library. Most of the code has been used in production for several years in different [Evil Martians][] projects.
|
37
|
-
|
38
|
-
We have decided to collect all our authorization techniques and pack them into a standalone gem–and that is how Action Policy was born!
|
39
|
-
|
40
|
-
## What about the existing solutions?
|
41
|
-
|
42
|
-
Why did we decide to build our own authorization gem instead of using the existing solutions, such as [Pundit][] and [CanCanCan][]?
|
43
|
-
|
44
|
-
**TL;DR they didn't solve all of our problems.**
|
45
|
-
|
46
|
-
[Pundit][] has been our framework of choice for a long time. Being too _dead-simple_, it required a lot of hacking to fulfill business logic requirements.
|
47
|
-
|
48
|
-
These _hacks_ later became Action Policy (initially, we even called it "Pundit, re-visited").
|
49
|
-
|
50
|
-
We also took a few ideas from [CanCanCan][]—such as [default rules and rule aliases](./aliases.md).
|
51
|
-
|
52
|
-
It is also worth noting that Action Policy (despite having a _Railsy_ name) is designed to be **Rails-free**. On the other hand, it contains some Rails-specific extensions and seamlessly integrates into the framework.
|
53
|
-
|
54
|
-
So, what are the main reasons to consider Action Policy as your authorization tool?
|
55
|
-
|
56
|
-
- **Performance**: multiple [caching strategies](./caching.md) out-of-the-box make authorization overhead as small as possible–especially useful when your rules involve DB queries; you can also monitor the performance and detect the bottlenecks using the built-in [instrumentation](./instrumentation) features.
|
57
|
-
|
58
|
-
- **Composition & Customization**: use [only the features you need](./custom_policy.md) or easily extend the functionality–it's just Ruby classes and modules, (almost) zero magic! And you can add authorization [anywhere in your code](./non_rails.md), not only in controllers.
|
59
|
-
|
60
|
-
- **Code Organization**: use [namespaces](./namespaces.md) to organize your policies (for example, when you have multiple authorization strategies); add [pre-checks](./pre_checks.md) to make rules more readable and better express your business-logic.
|
61
|
-
|
62
|
-
- **...and more**: [testability](./testing.md), [i18n](./i18n.md) integrations, [actionable errors](./reasons.md).
|
63
|
-
|
64
|
-
Learn more about the motivation behind the Action Policy and its features by watching this [RailsConf talk](https://www.youtube.com/watch?v=NVwx0DARDis).
|
65
|
-
|
66
|
-
## Resources
|
67
|
-
|
68
|
-
- Seattle.rb, 2019 "A Denial!" talk [[slides](https://speakerdeck.com/palkan/seattle-dot-rb-2019-a-denial)]
|
69
|
-
|
70
|
-
- RailsConf, 2018 "Access Denied" talk [[video](https://www.youtube.com/watch?v=NVwx0DARDis), [slides](https://speakerdeck.com/palkan/railsconf-2018-access-denied-the-missing-guide-to-authorization-in-rails)]
|
71
|
-
|
72
|
-
<a href="https://evilmartians.com/?utm_source=action_policy">
|
73
|
-
<img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
|
74
|
-
|
75
|
-
[CanCanCan]: https://github.com/CanCanCommunity/cancancan
|
76
|
-
[Pundit]: https://github.com/varvet/pundit
|
77
|
-
[Evil Martians]: https://evilmartians.com
|