action_policy 0.4.3 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (124) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +221 -174
  3. data/LICENSE.txt +1 -1
  4. data/README.md +7 -11
  5. data/lib/.rbnext/2.7/action_policy/behaviours/policy_for.rb +62 -0
  6. data/lib/.rbnext/2.7/action_policy/i18n.rb +56 -0
  7. data/lib/.rbnext/2.7/action_policy/policy/cache.rb +101 -0
  8. data/lib/.rbnext/2.7/action_policy/policy/pre_check.rb +162 -0
  9. data/lib/.rbnext/2.7/action_policy/rspec/be_authorized_to.rb +89 -0
  10. data/lib/.rbnext/2.7/action_policy/rspec/have_authorized_scope.rb +124 -0
  11. data/lib/.rbnext/2.7/action_policy/utils/pretty_print.rb +159 -0
  12. data/lib/.rbnext/3.0/action_policy/behaviour.rb +115 -0
  13. data/lib/.rbnext/3.0/action_policy/behaviours/policy_for.rb +62 -0
  14. data/lib/.rbnext/3.0/action_policy/behaviours/scoping.rb +35 -0
  15. data/lib/.rbnext/3.0/action_policy/behaviours/thread_memoized.rb +59 -0
  16. data/lib/.rbnext/3.0/action_policy/ext/policy_cache_key.rb +72 -0
  17. data/lib/.rbnext/3.0/action_policy/policy/aliases.rb +69 -0
  18. data/lib/.rbnext/3.0/action_policy/policy/authorization.rb +87 -0
  19. data/lib/.rbnext/3.0/action_policy/policy/cache.rb +101 -0
  20. data/lib/.rbnext/3.0/action_policy/policy/core.rb +161 -0
  21. data/lib/.rbnext/3.0/action_policy/policy/defaults.rb +31 -0
  22. data/lib/.rbnext/3.0/action_policy/policy/execution_result.rb +37 -0
  23. data/lib/.rbnext/3.0/action_policy/policy/pre_check.rb +162 -0
  24. data/lib/.rbnext/3.0/action_policy/policy/reasons.rb +212 -0
  25. data/lib/.rbnext/3.0/action_policy/policy/scoping.rb +160 -0
  26. data/lib/.rbnext/3.0/action_policy/rspec/be_authorized_to.rb +89 -0
  27. data/lib/.rbnext/3.0/action_policy/rspec/have_authorized_scope.rb +124 -0
  28. data/lib/.rbnext/3.0/action_policy/utils/pretty_print.rb +159 -0
  29. data/lib/.rbnext/3.0/action_policy/utils/suggest_message.rb +19 -0
  30. data/lib/action_policy.rb +7 -1
  31. data/lib/action_policy/behaviour.rb +22 -16
  32. data/lib/action_policy/behaviours/policy_for.rb +10 -3
  33. data/lib/action_policy/behaviours/scoping.rb +2 -1
  34. data/lib/action_policy/behaviours/thread_memoized.rb +1 -3
  35. data/lib/action_policy/ext/module_namespace.rb +1 -6
  36. data/lib/action_policy/ext/policy_cache_key.rb +10 -30
  37. data/lib/action_policy/ext/{symbol_classify.rb → symbol_camelize.rb} +6 -6
  38. data/lib/action_policy/i18n.rb +1 -1
  39. data/lib/action_policy/lookup_chain.rb +41 -21
  40. data/lib/action_policy/policy/aliases.rb +7 -12
  41. data/lib/action_policy/policy/authorization.rb +8 -7
  42. data/lib/action_policy/policy/cache.rb +11 -17
  43. data/lib/action_policy/policy/core.rb +25 -12
  44. data/lib/action_policy/policy/defaults.rb +3 -9
  45. data/lib/action_policy/policy/execution_result.rb +3 -9
  46. data/lib/action_policy/policy/pre_check.rb +19 -58
  47. data/lib/action_policy/policy/reasons.rb +32 -20
  48. data/lib/action_policy/policy/scoping.rb +5 -6
  49. data/lib/action_policy/rails/controller.rb +6 -1
  50. data/lib/action_policy/rails/ext/active_record.rb +7 -0
  51. data/lib/action_policy/rails/policy/instrumentation.rb +1 -1
  52. data/lib/action_policy/rspec/be_authorized_to.rb +5 -9
  53. data/lib/action_policy/rspec/dsl.rb +3 -3
  54. data/lib/action_policy/rspec/have_authorized_scope.rb +5 -7
  55. data/lib/action_policy/utils/pretty_print.rb +21 -24
  56. data/lib/action_policy/utils/suggest_message.rb +1 -3
  57. data/lib/action_policy/version.rb +1 -1
  58. data/lib/generators/action_policy/install/templates/{application_policy.rb → application_policy.rb.tt} +1 -1
  59. data/lib/generators/action_policy/policy/policy_generator.rb +4 -1
  60. data/lib/generators/action_policy/policy/templates/{policy.rb → policy.rb.tt} +0 -0
  61. data/lib/generators/rspec/templates/{policy_spec.rb → policy_spec.rb.tt} +0 -0
  62. data/lib/generators/test_unit/templates/{policy_test.rb → policy_test.rb.tt} +0 -0
  63. metadata +55 -119
  64. data/.gitattributes +0 -2
  65. data/.github/FUNDING.yml +0 -1
  66. data/.github/ISSUE_TEMPLATE.md +0 -18
  67. data/.github/PULL_REQUEST_TEMPLATE.md +0 -29
  68. data/.gitignore +0 -15
  69. data/.rubocop.yml +0 -54
  70. data/.tidelift.yml +0 -6
  71. data/.travis.yml +0 -31
  72. data/Gemfile +0 -22
  73. data/Rakefile +0 -27
  74. data/action_policy.gemspec +0 -44
  75. data/benchmarks/namespaced_lookup_cache.rb +0 -71
  76. data/bin/console +0 -14
  77. data/bin/setup +0 -8
  78. data/docs/.nojekyll +0 -0
  79. data/docs/CNAME +0 -1
  80. data/docs/README.md +0 -79
  81. data/docs/_sidebar.md +0 -27
  82. data/docs/aliases.md +0 -122
  83. data/docs/assets/docsify-search.js +0 -364
  84. data/docs/assets/docsify.min.js +0 -3
  85. data/docs/assets/fonts/FiraCode-Medium.woff +0 -0
  86. data/docs/assets/fonts/FiraCode-Regular.woff +0 -0
  87. data/docs/assets/images/banner.png +0 -0
  88. data/docs/assets/images/cache.png +0 -0
  89. data/docs/assets/images/cache.svg +0 -70
  90. data/docs/assets/images/layer.png +0 -0
  91. data/docs/assets/images/layer.svg +0 -35
  92. data/docs/assets/prism-ruby.min.js +0 -1
  93. data/docs/assets/styles.css +0 -347
  94. data/docs/assets/vue.min.css +0 -1
  95. data/docs/authorization_context.md +0 -92
  96. data/docs/behaviour.md +0 -113
  97. data/docs/caching.md +0 -291
  98. data/docs/controller_action_aliases.md +0 -109
  99. data/docs/custom_lookup_chain.md +0 -48
  100. data/docs/custom_policy.md +0 -53
  101. data/docs/debugging.md +0 -55
  102. data/docs/decorators.md +0 -27
  103. data/docs/favicon.ico +0 -0
  104. data/docs/graphql.md +0 -302
  105. data/docs/i18n.md +0 -44
  106. data/docs/index.html +0 -43
  107. data/docs/instrumentation.md +0 -84
  108. data/docs/lookup_chain.md +0 -17
  109. data/docs/namespaces.md +0 -77
  110. data/docs/non_rails.md +0 -28
  111. data/docs/pre_checks.md +0 -57
  112. data/docs/pundit_migration.md +0 -80
  113. data/docs/quick_start.md +0 -118
  114. data/docs/rails.md +0 -120
  115. data/docs/reasons.md +0 -120
  116. data/docs/scoping.md +0 -255
  117. data/docs/testing.md +0 -333
  118. data/docs/writing_policies.md +0 -107
  119. data/gemfiles/jruby.gemfile +0 -8
  120. data/gemfiles/rails42.gemfile +0 -9
  121. data/gemfiles/rails6.gemfile +0 -8
  122. data/gemfiles/railsmaster.gemfile +0 -6
  123. data/lib/action_policy/ext/string_match.rb +0 -14
  124. data/lib/action_policy/ext/yield_self_then.rb +0 -25
@@ -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'
@@ -1,6 +0,0 @@
1
- ci:
2
- type:
3
- development:
4
- tests:
5
- unlicensed: skip
6
- outdated: skip
@@ -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.5
22
- gemfile: gemfiles/rails6.gemfile
23
- - rvm: 2.5.3
24
- gemfile: Gemfile
25
- - rvm: 2.5.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]
@@ -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
@@ -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
@@ -1,8 +0,0 @@
1
- #!/usr/bin/env bash
2
- set -euo pipefail
3
- IFS=$'\n\t'
4
- set -vx
5
-
6
- bundle install
7
-
8
- # Do any other automated setup that you need to do here
File without changes
data/docs/CNAME DELETED
@@ -1 +0,0 @@
1
- actionpolicy.evilmartians.io
@@ -1,79 +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
- - RubyRussia, 2019 "Welcome, or access denied?" talk ([video](https://www.youtube.com/watch?v=y15a2g7v8i0) [RU], [slides](https://speakerdeck.com/palkan/rubyrussia-2019-welcome-or-access-denied))
69
-
70
- - Seattle.rb, 2019 "A Denial!" talk [[slides](https://speakerdeck.com/palkan/seattle-dot-rb-2019-a-denial)]
71
-
72
- - 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)]
73
-
74
- <a href="https://evilmartians.com/?utm_source=action_policy">
75
- <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
76
-
77
- [CanCanCan]: https://github.com/CanCanCommunity/cancancan
78
- [Pundit]: https://github.com/varvet/pundit
79
- [Evil Martians]: https://evilmartians.com
@@ -1,27 +0,0 @@
1
- * Getting Started
2
- * [Quick Start](quick_start.md)
3
- * [Writing Policies](writing_policies.md)
4
- * [Rails Integration](rails.md)
5
- * [Non-Rails Usage](non_rails.md)
6
- * [GraphQL Integration](graphql.md)
7
- * [Testing](testing.md)
8
- * Features
9
- * [Authorization Behaviour](behaviour.md)
10
- * [Policy Lookup](lookup_chain.md)
11
- * [Authorization Context](authorization_context.md)
12
- * [Aliases](aliases.md)
13
- * [Pre-Checks](pre_checks.md)
14
- * [Scoping](scoping.md)
15
- * [Caching](caching.md)
16
- * [Namespaces](namespaces.md)
17
- * [Failure Reasons](reasons.md)
18
- * [Instrumentation](instrumentation.md)
19
- * [I18n Support](i18n.md)
20
- * [Debugging](debugging.md)
21
- * Tips & Tricks
22
- * [From Pundit to Action Policy](./pundit_migration.md)
23
- * [Dealing with Decorators](./decorators.md)
24
- * [Controller Action Aliases](controller_action_aliases.md)
25
- * Customize
26
- * [Base Policy](custom_policy.md)
27
- * [Lookup Chain](custom_lookup_chain.md)
@@ -1,122 +0,0 @@
1
- # Rule Aliases
2
-
3
- Action Policy allows you to add rule aliases. It is useful when you rely on _implicit_ rules in controllers. For example:
4
-
5
- ```ruby
6
- class PostsController < ApplicationController
7
- before_action :load_post, only: [:edit, :update, :destroy]
8
-
9
- private
10
-
11
- def load_post
12
- @post = Post.find(params[:id])
13
- # depending on action, an `edit?`, `update?` or `destroy?`
14
- # rule would be applied
15
- authorize! @post
16
- end
17
- end
18
- ```
19
-
20
- In your policy, you can create aliases to avoid duplication:
21
-
22
- ```ruby
23
- class PostPolicy < ApplicationPolicy
24
- alias_rule :edit?, :destroy?, to: :update?
25
- end
26
- ```
27
-
28
- **NOTE**: `alias_rule` is available only if you inherit from `ActionPolicy::Base` or include `ActionPolicy::Policy::Aliases` into your `ApplicationPolicy`.
29
-
30
- **Why not just use Ruby's `alias`?**
31
-
32
- An alias created with `alias_rule` is resolved at _authorization time_ (during an `authorize!` or `allowed_to?` call), and it does not add an alias method to the class.
33
-
34
- That allows us to write tests easier, as we should only test the rule, not the alias–and to leverage [caching](caching.md) better.
35
-
36
- By default, `ActionPolicy::Base` adds one alias: `alias_rule :new?, to: :create?`.
37
-
38
- ## Default rule
39
-
40
- You can add a _default_ rule–the rule that would be applied if the rule specified during authorization is missing (like a "wildcard" alias):
41
-
42
- ```ruby
43
- class PostPolicy < ApplicationPolicy
44
- # For an ApplicationPolicy, makes :manage? match anything that is
45
- # not :index?, :create? or :new?
46
- default_rule :manage?
47
-
48
- # If you want manage? to catch really everything, place this alias
49
- #alias_rule :index?, :create?, :new?, to: :manage?
50
- def manage?
51
- # ...
52
- end
53
- end
54
- ```
55
-
56
- Now when you call `authorize! post` with any rule not defined in the policy class, the `manage?` rule is applied. Note that `index?` `create?` and `new?` are already defined in the [superclass by default](custom_policy.md) (returning `false`) - if you want the same behaviour for *all* actions, define aliases like in the example above (commented out).
57
-
58
- By default, `ActionPolicy::Base` sets `manage?` as a default rule.
59
-
60
- ## Aliases and Private Methods
61
-
62
- Rules in `action_policy` can only be public methods. Trying to use a private method as a rule will raise an error. Thus, aliases can also only point to public methods.
63
-
64
- ## Rule resolution with subclasses
65
-
66
- Here's the order in which aliases and concrete rule methods are resolved in regards to subclasses:
67
-
68
- 1. If there is a concrete rule method on the subclass, this is called, else
69
- 2. If there is a matching alias then this is called, else
70
- * When aliases are defined on the subclass they will overwrite matching aliases on the superclass.
71
- 3. If there is a concrete rule method on the superclass, then this is called, else
72
- 4. If there is a default rule defined, then this is called, else
73
- 5. `ActionPolicy::UnknownRule` is raised.
74
-
75
- Here's an example with the expected results:
76
-
77
- ```ruby
78
- class SuperPolicy < ApplicationPolicy
79
- default_rule :manage?
80
-
81
- alias_rule :update?, :destroy?, :create?, to: :edit?
82
-
83
- def manage?
84
- end
85
-
86
- def edit?
87
- end
88
-
89
- def index?
90
- end
91
- end
92
-
93
- class SubPolicy < AbstractPolicy
94
- default_rule nil
95
-
96
- alias_rule :index?, :update?, to: :manage?
97
-
98
- def create?
99
- end
100
- end
101
- ```
102
-
103
- Authorizing against the SuperPolicy:
104
-
105
- * `update?` will resolve to `edit?`
106
- * `destroy?` will resolve to `edit?`
107
- * `create?` will resolve to `edit?`
108
- * `manage?` will resolve to `manage?`
109
- * `edit?` will resolve to `edit?`
110
- * `index?` will resolve to `index?`
111
- * `something?` will resolve to `manage?`
112
-
113
- Authorizing against the SubPolicy:
114
-
115
- * `index?` will resolve to `manage?`
116
- * `update?` will resolve to `manage?`
117
- * `create?` will resolve to `create?`
118
- * `destroy?` will resolve to `edit?`
119
- * `manage?` will resolve to `manage?`
120
- * `edit?` will resolve to `edit?`
121
- * `index?` will resolve to `manage?`
122
- * `something?` will raise `ActionPolicy::UnknownRule`