strongbolt 0.3.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (145) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +33 -0
  3. data/.gitignore +18 -0
  4. data/.rspec +1 -0
  5. data/.ruby-gemset +1 -0
  6. data/.ruby-version +1 -0
  7. data/Gemfile +4 -0
  8. data/Gemfile.lock +130 -0
  9. data/LICENSE.txt +22 -0
  10. data/README.md +182 -0
  11. data/Rakefile +1 -0
  12. data/app/assets/javascripts/strongbolt.js +1 -0
  13. data/app/assets/javascripts/strongbolt/role-capabilities.js +80 -0
  14. data/app/controllers/strongbolt/capabilities_controller.rb +77 -0
  15. data/app/controllers/strongbolt/roles_controller.rb +92 -0
  16. data/app/controllers/strongbolt/security_controller.rb +8 -0
  17. data/app/controllers/strongbolt/user_groups_controller.rb +76 -0
  18. data/app/controllers/strongbolt/user_groups_users_controller.rb +35 -0
  19. data/app/controllers/strongbolt_controller.rb +2 -0
  20. data/app/views/strongbolt/_menu.html.erb +13 -0
  21. data/app/views/strongbolt/capabilities/index.html.erb +53 -0
  22. data/app/views/strongbolt/capabilities/show.html.erb +53 -0
  23. data/app/views/strongbolt/roles/_capabilities.html.erb +47 -0
  24. data/app/views/strongbolt/roles/_capability.html.erb +21 -0
  25. data/app/views/strongbolt/roles/_form.html.erb +12 -0
  26. data/app/views/strongbolt/roles/edit.html.erb +14 -0
  27. data/app/views/strongbolt/roles/index.html.erb +54 -0
  28. data/app/views/strongbolt/roles/new.html.erb +11 -0
  29. data/app/views/strongbolt/roles/show.html.erb +52 -0
  30. data/app/views/strongbolt/user_groups/_form.html.erb +12 -0
  31. data/app/views/strongbolt/user_groups/edit.html.erb +14 -0
  32. data/app/views/strongbolt/user_groups/index.html.erb +46 -0
  33. data/app/views/strongbolt/user_groups/new.html.erb +13 -0
  34. data/app/views/strongbolt/user_groups/show.html.erb +88 -0
  35. data/lib/generators/strongbolt/fix_generator.rb +23 -0
  36. data/lib/generators/strongbolt/indexes_generator.rb +19 -0
  37. data/lib/generators/strongbolt/install_generator.rb +29 -0
  38. data/lib/generators/strongbolt/templates/fix.rb +5 -0
  39. data/lib/generators/strongbolt/templates/indexes.rb +21 -0
  40. data/lib/generators/strongbolt/templates/migration.rb +73 -0
  41. data/lib/generators/strongbolt/templates/strongbolt.rb +45 -0
  42. data/lib/generators/strongbolt/views_generator.rb +26 -0
  43. data/lib/strongbolt.rb +219 -0
  44. data/lib/strongbolt/base.rb +7 -0
  45. data/lib/strongbolt/bolted.rb +125 -0
  46. data/lib/strongbolt/bolted_controller.rb +297 -0
  47. data/lib/strongbolt/capabilities_role.rb +15 -0
  48. data/lib/strongbolt/capability.rb +165 -0
  49. data/lib/strongbolt/configuration.rb +111 -0
  50. data/lib/strongbolt/controllers/url_helpers.rb +37 -0
  51. data/lib/strongbolt/engine.rb +44 -0
  52. data/lib/strongbolt/errors.rb +38 -0
  53. data/lib/strongbolt/generators/migration.rb +35 -0
  54. data/lib/strongbolt/helpers.rb +18 -0
  55. data/lib/strongbolt/rails/routes.rb +20 -0
  56. data/lib/strongbolt/role.rb +46 -0
  57. data/lib/strongbolt/roles_user_group.rb +15 -0
  58. data/lib/strongbolt/rspec.rb +29 -0
  59. data/lib/strongbolt/rspec/user.rb +90 -0
  60. data/lib/strongbolt/tenantable.rb +304 -0
  61. data/lib/strongbolt/user_abilities.rb +292 -0
  62. data/lib/strongbolt/user_group.rb +24 -0
  63. data/lib/strongbolt/user_groups_user.rb +16 -0
  64. data/lib/strongbolt/users_tenant.rb +12 -0
  65. data/lib/strongbolt/version.rb +3 -0
  66. data/lib/tasks/strongbolt_tasks.rake +29 -0
  67. data/spec/controllers/strongbolt/capabilities_controller_spec.rb +254 -0
  68. data/spec/controllers/strongbolt/roles_controller_spec.rb +228 -0
  69. data/spec/controllers/strongbolt/user_groups_controller_spec.rb +216 -0
  70. data/spec/controllers/strongbolt/user_groups_users_controller_spec.rb +69 -0
  71. data/spec/controllers/without_authorization_controller_spec.rb +20 -0
  72. data/spec/dummy/.rspec +2 -0
  73. data/spec/dummy/README.rdoc +28 -0
  74. data/spec/dummy/Rakefile +6 -0
  75. data/spec/dummy/app/assets/images/.keep +0 -0
  76. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  77. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  78. data/spec/dummy/app/controllers/application_controller.rb +5 -0
  79. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  80. data/spec/dummy/app/controllers/posts_controller.rb +18 -0
  81. data/spec/dummy/app/controllers/test_controller.rb +3 -0
  82. data/spec/dummy/app/controllers/without_authorization_controller.rb +5 -0
  83. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  84. data/spec/dummy/app/mailers/.keep +0 -0
  85. data/spec/dummy/app/models/.keep +0 -0
  86. data/spec/dummy/app/models/concerns/.keep +0 -0
  87. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  88. data/spec/dummy/bin/bundle +3 -0
  89. data/spec/dummy/bin/rails +4 -0
  90. data/spec/dummy/bin/rake +4 -0
  91. data/spec/dummy/config.ru +4 -0
  92. data/spec/dummy/config/application.rb +29 -0
  93. data/spec/dummy/config/boot.rb +5 -0
  94. data/spec/dummy/config/database.yml +25 -0
  95. data/spec/dummy/config/environment.rb +5 -0
  96. data/spec/dummy/config/environments/development.rb +37 -0
  97. data/spec/dummy/config/environments/production.rb +78 -0
  98. data/spec/dummy/config/environments/test.rb +39 -0
  99. data/spec/dummy/config/initializers/assets.rb +8 -0
  100. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  101. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  102. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  103. data/spec/dummy/config/initializers/inflections.rb +16 -0
  104. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  105. data/spec/dummy/config/initializers/session_store.rb +3 -0
  106. data/spec/dummy/config/initializers/strongbolt.rb +32 -0
  107. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  108. data/spec/dummy/config/locales/en.yml +23 -0
  109. data/spec/dummy/config/routes.rb +12 -0
  110. data/spec/dummy/config/secrets.yml +22 -0
  111. data/spec/dummy/db/development.sqlite3 +0 -0
  112. data/spec/dummy/db/migrate/20150630212236_create_strongbolt_tables.rb +54 -0
  113. data/spec/dummy/db/migrate/20150630212251_create_strongbolt_tables_indexes.rb +21 -0
  114. data/spec/dummy/db/schema.rb +84 -0
  115. data/spec/dummy/db/test.sqlite3 +0 -0
  116. data/spec/dummy/lib/assets/.keep +0 -0
  117. data/spec/dummy/public/404.html +67 -0
  118. data/spec/dummy/public/422.html +67 -0
  119. data/spec/dummy/public/500.html +66 -0
  120. data/spec/dummy/public/favicon.ico +0 -0
  121. data/spec/fabricators/capability_fabricator.rb +4 -0
  122. data/spec/fabricators/role_fabricator.rb +9 -0
  123. data/spec/fabricators/user_fabricator.rb +3 -0
  124. data/spec/fabricators/user_group_fabricator.rb +9 -0
  125. data/spec/fixtures/application.rb +28 -0
  126. data/spec/fixtures/controllers.rb +5 -0
  127. data/spec/spec_helper.rb +89 -0
  128. data/spec/strongbolt/bolted_controller_spec.rb +706 -0
  129. data/spec/strongbolt/bolted_spec.rb +136 -0
  130. data/spec/strongbolt/capability_spec.rb +251 -0
  131. data/spec/strongbolt/configuration_spec.rb +119 -0
  132. data/spec/strongbolt/controllers/url_helpers_spec.rb +34 -0
  133. data/spec/strongbolt/helpers_spec.rb +43 -0
  134. data/spec/strongbolt/role_spec.rb +90 -0
  135. data/spec/strongbolt/tenantable_spec.rb +281 -0
  136. data/spec/strongbolt/user_abilities_spec.rb +509 -0
  137. data/spec/strongbolt/user_group_spec.rb +37 -0
  138. data/spec/strongbolt/users_tenant_spec.rb +36 -0
  139. data/spec/strongbolt_spec.rb +274 -0
  140. data/spec/support/controller_macros.rb +11 -0
  141. data/spec/support/db_setup.rb +134 -0
  142. data/spec/support/helpers.rb +62 -0
  143. data/spec/support/transactional_specs.rb +17 -0
  144. data/strongbolt.gemspec +32 -0
  145. metadata +407 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b2be7a6357fe3a1bac22a246b34013f1c5109c5e
4
+ data.tar.gz: 145bb831919b70d9e9165328f097f77249c83726
5
+ SHA512:
6
+ metadata.gz: 4a4612a54b4b84c47381bae52e9e8aca1a2992a23c6d7c48981beab4da8beaebbd5f45084c6ca4427d3513a491b530de9efebf5ca595cf7b0087a59aff5c35c6
7
+ data.tar.gz: f933dd404243f00ed6a081619b997aa04b10af0924cf82c42504b331dfe7c1b33851ab352da04ee9a7c0a64d1ac47ebb01ab4dad0c1cbe6bb79c316d71539d6a
@@ -0,0 +1,33 @@
1
+ root = true
2
+
3
+ # defaults over all files
4
+ [*]
5
+ charset = utf-8
6
+ end_of_line = lf
7
+ insert_final_newline = true
8
+ trim_trailing_whitespace = true
9
+
10
+ # documentation
11
+ [*.md]
12
+ indent_style = space
13
+ indent_size = 4
14
+
15
+ # ruby files
16
+ [{*.rb,*.ru,Gemfile,Capfile,Rakefile,Guardfile}]
17
+ indent_style = space
18
+ indent_size = 2
19
+
20
+ # config files
21
+ [*.yml]
22
+ indent_style = space
23
+ indent_size = 2
24
+
25
+ # javascript files
26
+ [*.{js,coffee}]
27
+ indent_style = space
28
+ indent_size = 2
29
+
30
+ # stylesheets
31
+ [*.{css,scss}]
32
+ indent_style = space
33
+ indent_size = 2
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ .DS_Store
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ spec/dummy/log/*
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1 @@
1
+ strongbolt
@@ -0,0 +1 @@
1
+ ruby-2.1.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in strongbolt.gemspec
4
+ gemspec
@@ -0,0 +1,130 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ strongbolt (0.3.6)
5
+ awesome_nested_set (~> 3.0.0)
6
+ grant (~> 3.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actionmailer (4.1.6)
12
+ actionpack (= 4.1.6)
13
+ actionview (= 4.1.6)
14
+ mail (~> 2.5, >= 2.5.4)
15
+ actionpack (4.1.6)
16
+ actionview (= 4.1.6)
17
+ activesupport (= 4.1.6)
18
+ rack (~> 1.5.2)
19
+ rack-test (~> 0.6.2)
20
+ actionview (4.1.6)
21
+ activesupport (= 4.1.6)
22
+ builder (~> 3.1)
23
+ erubis (~> 2.7.0)
24
+ activemodel (4.1.6)
25
+ activesupport (= 4.1.6)
26
+ builder (~> 3.1)
27
+ activerecord (4.1.6)
28
+ activemodel (= 4.1.6)
29
+ activesupport (= 4.1.6)
30
+ arel (~> 5.0.0)
31
+ activesupport (4.1.6)
32
+ i18n (~> 0.6, >= 0.6.9)
33
+ json (~> 1.7, >= 1.7.7)
34
+ minitest (~> 5.1)
35
+ thread_safe (~> 0.1)
36
+ tzinfo (~> 1.1)
37
+ arel (5.0.1.20140414130214)
38
+ awesome_nested_set (3.0.3)
39
+ activerecord (>= 4.0.0, < 5)
40
+ builder (3.2.2)
41
+ diff-lcs (1.2.5)
42
+ erubis (2.7.0)
43
+ fabrication (2.11.3)
44
+ fuubar (2.0.0)
45
+ rspec (~> 3.0)
46
+ ruby-progressbar (~> 1.4)
47
+ grant (3.0.0)
48
+ activerecord (>= 4.0.0)
49
+ hike (1.2.3)
50
+ i18n (0.6.11)
51
+ json (1.8.1)
52
+ mail (2.6.3)
53
+ mime-types (>= 1.16, < 3)
54
+ mime-types (2.4.3)
55
+ minitest (5.4.2)
56
+ multi_json (1.10.1)
57
+ rack (1.5.2)
58
+ rack-test (0.6.2)
59
+ rack (>= 1.0)
60
+ rails (4.1.6)
61
+ actionmailer (= 4.1.6)
62
+ actionpack (= 4.1.6)
63
+ actionview (= 4.1.6)
64
+ activemodel (= 4.1.6)
65
+ activerecord (= 4.1.6)
66
+ activesupport (= 4.1.6)
67
+ bundler (>= 1.3.0, < 2.0)
68
+ railties (= 4.1.6)
69
+ sprockets-rails (~> 2.0)
70
+ railties (4.1.6)
71
+ actionpack (= 4.1.6)
72
+ activesupport (= 4.1.6)
73
+ rake (>= 0.8.7)
74
+ thor (>= 0.18.1, < 2.0)
75
+ rake (10.3.2)
76
+ rspec (3.1.0)
77
+ rspec-core (~> 3.1.0)
78
+ rspec-expectations (~> 3.1.0)
79
+ rspec-mocks (~> 3.1.0)
80
+ rspec-core (3.1.5)
81
+ rspec-support (~> 3.1.0)
82
+ rspec-expectations (3.1.2)
83
+ diff-lcs (>= 1.2.0, < 2.0)
84
+ rspec-support (~> 3.1.0)
85
+ rspec-mocks (3.1.2)
86
+ rspec-support (~> 3.1.0)
87
+ rspec-rails (3.1.0)
88
+ actionpack (>= 3.0)
89
+ activesupport (>= 3.0)
90
+ railties (>= 3.0)
91
+ rspec-core (~> 3.1.0)
92
+ rspec-expectations (~> 3.1.0)
93
+ rspec-mocks (~> 3.1.0)
94
+ rspec-support (~> 3.1.0)
95
+ rspec-support (3.1.1)
96
+ ruby-progressbar (1.6.0)
97
+ shoulda-matchers (2.7.0)
98
+ activesupport (>= 3.0.0)
99
+ sprockets (2.12.3)
100
+ hike (~> 1.2)
101
+ multi_json (~> 1.0)
102
+ rack (~> 1.0)
103
+ tilt (~> 1.1, != 1.3.0)
104
+ sprockets-rails (2.2.2)
105
+ actionpack (>= 3.0)
106
+ activesupport (>= 3.0)
107
+ sprockets (>= 2.8, < 4.0)
108
+ sqlite3 (1.3.9)
109
+ thor (0.19.1)
110
+ thread_safe (0.3.4)
111
+ tilt (1.4.1)
112
+ tzinfo (1.2.2)
113
+ thread_safe (~> 0.1)
114
+
115
+ PLATFORMS
116
+ ruby
117
+
118
+ DEPENDENCIES
119
+ bundler (> 1.7.0)
120
+ fabrication
121
+ fuubar
122
+ rails (~> 4.1.0)
123
+ rake
124
+ rspec-rails (~> 3.1.0)
125
+ shoulda-matchers
126
+ sqlite3 (= 1.3.9)
127
+ strongbolt!
128
+
129
+ BUNDLED WITH
130
+ 1.11.2
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Thomas Césaré-Herriau
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.
@@ -0,0 +1,182 @@
1
+ # Strongbolt
2
+
3
+ RBAC framework for model-level authorization gem with very granular control on permissions, using Capabilities, Roles and UserGroups.
4
+
5
+ Only works with Rails 4.
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'grant', '>= 2.2', git: "git@github.com:AnalyticsMediaGroup/grant.git"
12
+ gem 'strongbolt', git: "git@github.com:AnalyticsMediaGroup/strongbolt.git"
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ ## Getting Started
19
+
20
+ To creates the required migrations, run:
21
+
22
+ $ rails g strongbolt:install && rake db:migrate
23
+
24
+ To create a Role and User Group that has full access and assign the group to all users (this allow to get started using StrongBolt), run:
25
+
26
+ $ rake strongbolt:seed
27
+
28
+ If you plan on using the built-in view to manage user groups, roles and permissions, also add to your application.js:
29
+
30
+ //= require strongbolt
31
+
32
+ You will need to have jQuery or a similar library with Ajax to make it work
33
+
34
+ ## Usage
35
+
36
+ ### Configuration
37
+
38
+ The initializer of strongbolt, `config/initializers/strongbolt.rb` has some included documentation to help you with configuring the little you need to for Strongbolt to work.
39
+
40
+ By default, the user class is `User` and there is no tenant set.
41
+
42
+ #### A note on the list of models
43
+
44
+ Strongbolt has been made to be used with the least configuration possible. If given a tenant, it will traverse the graph of dependencies on this tenant to try to configure all the tenant dependent models authorization check ups. However, some models may be totally independant or not belong to (directly or indirectly) to a tenant. You may also have no tenant at all. In these cases, some or all of your models won't be discovered by Strongbolt when running your app.
45
+ To avoid eager loading the whole application to automatically get the list of models, you can specify in the initializer the models of your application.
46
+ This list is prefilled when running the install generator.
47
+
48
+ ### Controllers
49
+
50
+ Strongbolt perform high level authorization on controllers, to avoid testing more granular authorization and increase the performance. For instance, if an user cannot find any Movies, he certainly won't be able to find the movie with the specific id 5.
51
+
52
+ #### Custom controller actions
53
+
54
+ Strongbolt relies on the usual Rails restful actions to guess the corresponding model action (edit requires update authorization, new requires create authorization, etc.). However, you will sometimes create other custom actions. In that case, you must specify in the controller how to map these custom controller actions to one of the 4 model actions using:
55
+
56
+ ```ruby
57
+ authorize_as_find :action1, :action2
58
+ authorize_as_create :action, :action2
59
+ authorize_as_update :action, :action2
60
+ authorize_as_destroy :action, :action2
61
+ ```
62
+
63
+ #### Skipping authorization
64
+
65
+ You can disable the controller-level authorization checks by using in the controllers:
66
+
67
+ ```ruby
68
+ skip_controller_authorization,
69
+ skip_controller_authorization, only: [:index]
70
+ skip_controller_authorization, except: [:update]
71
+ ```
72
+
73
+ You can also specify a list of controllers in the initializer `config/initializers/strongbolt.rb`. It is useful for third-party controllers, like devise for instance. The syntax is:
74
+
75
+ ```ruby
76
+ config.skip_controller_authorization_for "Devise::SessionsController", "Devise::RegistrationsController"
77
+ ```
78
+
79
+ You can also skip ALL authorization checks (BAD IDEA) using:
80
+
81
+ ```ruby
82
+ skip_all_authorization
83
+ skip_all_authorization, only: [:index]
84
+ skip_all_authorization, except: [:update]
85
+ ```
86
+
87
+ Sometimes you may want to render the views without checking again every single instance you're displaying (for the list of movies for instance, if the user can find ALL movies no need to test separatly each of them). You can skip the authorization checks when rendering pages by using:
88
+
89
+ ```ruby
90
+ render_without_authorization :index, :show
91
+ ```
92
+
93
+ Be careful when using one of this skipping authorization check as it may result in leaked data.
94
+
95
+ #### Controller not derived from a Model
96
+
97
+ Usually most of your controllers, in a RestFUL design, are backed by a specific model, derived from the name of the controller. In that case Strongbolt will know what model authorization it should test against. Otherwise, it will raise an error unless you specify the model for authorization:
98
+
99
+ ```ruby
100
+ self.model_for_authorization = "Movie"
101
+ ```
102
+
103
+ ### Models
104
+
105
+ Usually you will never need to configure anything on the models. In some cases though, to simplify the roles and permissions, you may want to authorize some models as if they were other models (in nested models, sometimes it is safe to assume that the lower level model should have the same permissions than its parent)>
106
+ To achieve this, use the following within your model:
107
+
108
+ ```ruby
109
+ authorize_as "Movie"
110
+ ```
111
+
112
+ ### Tenants
113
+
114
+ Strongbolt allows the utilization of _tenants_. Tenants are vertical scopes within your application.
115
+
116
+ > Let's take an example. A project tracking application (like Pivotal) can have several companies as clients, but each company's users can see only what concern them. _Company_ is a tenant of the application.
117
+
118
+ The initializer let you define the model(s) that should be considered tenants.
119
+
120
+ #### How to set what tenants a user has access to
121
+
122
+ Strongbolt comes with a table, `strongbolt_users_tenants`, that will store what tenants users have access to.
123
+
124
+ When a tenant is declared, it will add some features to the _User class_ that has been defined in the initializer.
125
+
126
+ First, an association between the _User class_ and the _Tenant class_ will be created, named after the _Tenant class_ name. It is a `has_many :trough => :users_tenants_` association.
127
+
128
+ > For instance, a `Company` tenant will generate a `companies` association.
129
+
130
+ A convenient instance method will also be created on the _User class_ to directly access the list of _Tenant class_ a _User_ can access. It is name `accessible_{tenants}` where `{tenants}` is the pluralize version of the _Tenant class_ name.
131
+
132
+ > `Company` will create an `accessible_companies` instance method
133
+
134
+ #### Tenanted models
135
+
136
+ A tenanted model is a model that belongs indirectly to a _Tenant class_.
137
+
138
+ > For instance, `Project` is a tenanted model of `Company`. Now, let's consider a `belong_to` association that links `Project` to a `Country`. The list of countries is stored in the table `countries` and does not belong to `Company`: `Country` is not a tenanted model.
139
+
140
+ Strongbolt will traverse your schema and automatically determine what models in your application is linked to your _Tenant class_.
141
+
142
+ > In our example, where `Project` belongs to `Company` and `Country`, but `Country` does not belong to `Company`, Strongbolt will automatically determine that `Project` is a tenanted model and `Country` is not.
143
+
144
+ Strongbolt will then create a `has_one` association on every tenanted model, so you can access directly the dependent _Tenant_
145
+
146
+ > For instance, every `Task` of a `Project` will have a `has_one :company, :through => :project` association automatically created (if not already existing).
147
+
148
+ #### Restricting permissions to accessible tenanted models
149
+
150
+ Strongbolt's capabilites have a boolean attribute, `require_tenant_access`, that specify whether the user can access all _tenanted models_ or only the ones that belong to the _Tenants_ he has access to.
151
+
152
+ > Let's look back at the example. Each companies has several _projects_. The normal user, belonging to a company, would only have access to his company's projects. You would then define for normal user a capability *requiring tenant access*
153
+
154
+ > An admin user, on the other hand, like an engineer of the application, could have access to all the companies' projects. An engineer's projects' permissions would then *not require tenant access*
155
+
156
+ It will then perform the right permission check based on this requirement and the relationship of the model being checked and the _Tenant class_. If the model being checked is not linked to any of the _Tenant classes_, it won't check any dependency.
157
+
158
+
159
+ ### Troubleshooting
160
+
161
+ #### Strongbolt::ModelNotFound
162
+
163
+ This means Strongbolt is trying to perform some controller-level authorizations but cannot infer the model from the controller name. In that case you must use in this controller:
164
+
165
+ ```ruby
166
+ self.model_for_authorization = "Movie"
167
+ ```
168
+
169
+ Or skip controller authorizations when it cannot be related to a model or it is not useful (like for Devise controllers), using either one of the methods described in *Skipping Authorization*.
170
+
171
+ #### Strongbolt::ActionNotConfigured
172
+
173
+ This happens when a controller is using a custom action which is not one of the 6 usual restful Rails actions (index, new, create, sho, edit, update, destroy). Refer to *Custom controller actions* to fix this.
174
+
175
+
176
+ ## Contributing
177
+
178
+ 1. Fork it ( http://github.com/<my-github-username>/strongbolt/fork )
179
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
180
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
181
+ 4. Push to the branch (`git push origin my-new-feature`)
182
+ 5. Create new Pull Request
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= require strongbolt/role-capabilities
@@ -0,0 +1,80 @@
1
+ (function() {
2
+ var RoleCapabilities;
3
+
4
+ RoleCapabilities = (function() {
5
+ function RoleCapabilities(table) {
6
+ this.table = table;
7
+ this.url = this.table.data('url');
8
+ this.setup();
9
+ }
10
+
11
+ RoleCapabilities.prototype.toggleAction = function(button) {
12
+ var granted, params, parent;
13
+ granted = !button.data('granted');
14
+ button.blur();
15
+ button.data("granted", granted);
16
+ parent = button.parent();
17
+ params = {
18
+ model: parent.data('model'),
19
+ require_ownership: parent.data('require-ownership'),
20
+ require_tenant_access: parent.data('require-tenant-access'),
21
+ action: button.data('action')
22
+ };
23
+ return this[granted ? 'addAction' : 'destroyAction'](params, function() {
24
+ if (granted) {
25
+ button.addClass('btn-success');
26
+ return button.removeClass('btn-danger');
27
+ } else {
28
+ button.addClass('btn-danger');
29
+ return button.removeClass('btn-success');
30
+ }
31
+ });
32
+ };
33
+
34
+ RoleCapabilities.prototype.destroyAction = function(params, callback) {
35
+ var options;
36
+ options = {
37
+ data: {
38
+ capability: params
39
+ },
40
+ type: "DELETE",
41
+ complete: callback
42
+ };
43
+ return this.request(options);
44
+ };
45
+
46
+ RoleCapabilities.prototype.addAction = function(params, callback) {
47
+ var options;
48
+ options = {
49
+ data: {
50
+ capability: params
51
+ },
52
+ type: "POST",
53
+ complete: callback
54
+ };
55
+ return this.request(options);
56
+ };
57
+
58
+ RoleCapabilities.prototype.request = function(options) {
59
+ options.url = this.url;
60
+ options.dataType = 'json';
61
+ return $.ajax(options);
62
+ };
63
+
64
+ RoleCapabilities.prototype.setup = function() {
65
+ return this.table.on('click', 'button[data-action]', (function(_this) {
66
+ return function(event) {
67
+ return _this.toggleAction($(event.currentTarget));
68
+ };
69
+ })(this));
70
+ };
71
+
72
+ return RoleCapabilities;
73
+
74
+ })();
75
+
76
+ $(document).ready(function() {
77
+ return new RoleCapabilities($("#role-capabilities"));
78
+ });
79
+
80
+ }).call(this);