cancancan 1.11.0 → 2.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/cancancan.gemspec +15 -19
- data/lib/cancan/ability/actions.rb +91 -0
- data/lib/cancan/ability/rules.rb +85 -0
- data/lib/cancan/ability.rb +74 -136
- data/lib/cancan/conditions_matcher.rb +93 -0
- data/lib/cancan/controller_additions.rb +34 -40
- data/lib/cancan/controller_resource.rb +47 -212
- data/lib/cancan/controller_resource_builder.rb +24 -0
- data/lib/cancan/controller_resource_finder.rb +40 -0
- data/lib/cancan/controller_resource_loader.rb +116 -0
- data/lib/cancan/controller_resource_name_finder.rb +21 -0
- data/lib/cancan/controller_resource_sanitizer.rb +30 -0
- data/lib/cancan/exceptions.rb +7 -3
- data/lib/cancan/matchers.rb +12 -3
- data/lib/cancan/model_adapters/abstract_adapter.rb +8 -8
- data/lib/cancan/model_adapters/active_record_4_adapter.rb +33 -10
- data/lib/cancan/model_adapters/active_record_5_adapter.rb +70 -0
- data/lib/cancan/model_adapters/active_record_adapter.rb +41 -81
- data/lib/cancan/model_adapters/can_can/model_adapters/active_record_adapter/joins.rb +39 -0
- data/lib/cancan/model_adapters/conditions_extractor.rb +75 -0
- data/lib/cancan/model_additions.rb +0 -1
- data/lib/cancan/rule.rb +36 -92
- data/lib/cancan/rules_compressor.rb +20 -0
- data/lib/cancan/version.rb +1 -1
- data/lib/cancan.rb +5 -12
- data/lib/generators/cancan/ability/ability_generator.rb +1 -1
- metadata +54 -65
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.travis.yml +0 -55
- data/Appraisals +0 -136
- data/CHANGELOG.rdoc +0 -503
- data/CONTRIBUTING.md +0 -23
- data/Gemfile +0 -3
- data/LICENSE +0 -22
- data/README.md +0 -188
- data/Rakefile +0 -9
- data/gemfiles/activerecord_3.0.gemfile +0 -18
- data/gemfiles/activerecord_3.1.gemfile +0 -20
- data/gemfiles/activerecord_3.2.gemfile +0 -20
- data/gemfiles/activerecord_4.0.gemfile +0 -17
- data/gemfiles/activerecord_4.1.gemfile +0 -17
- data/gemfiles/activerecord_4.2.gemfile +0 -18
- data/gemfiles/datamapper_1.x.gemfile +0 -14
- data/gemfiles/mongoid_2.x.gemfile +0 -20
- data/gemfiles/sequel_3.x.gemfile +0 -20
- data/lib/cancan/inherited_resource.rb +0 -20
- data/lib/cancan/model_adapters/active_record_3_adapter.rb +0 -47
- data/lib/cancan/model_adapters/data_mapper_adapter.rb +0 -34
- data/lib/cancan/model_adapters/mongoid_adapter.rb +0 -54
- data/lib/cancan/model_adapters/sequel_adapter.rb +0 -87
- data/spec/README.rdoc +0 -27
- data/spec/cancan/ability_spec.rb +0 -487
- data/spec/cancan/controller_additions_spec.rb +0 -141
- data/spec/cancan/controller_resource_spec.rb +0 -632
- data/spec/cancan/exceptions_spec.rb +0 -58
- data/spec/cancan/inherited_resource_spec.rb +0 -71
- data/spec/cancan/matchers_spec.rb +0 -29
- data/spec/cancan/model_adapters/active_record_4_adapter_spec.rb +0 -85
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +0 -446
- data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +0 -119
- data/spec/cancan/model_adapters/default_adapter_spec.rb +0 -7
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +0 -227
- data/spec/cancan/model_adapters/sequel_adapter_spec.rb +0 -132
- data/spec/cancan/rule_spec.rb +0 -52
- data/spec/matchers.rb +0 -13
- data/spec/spec.opts +0 -2
- data/spec/spec_helper.rb +0 -28
- data/spec/support/ability.rb +0 -7
data/README.md
DELETED
@@ -1,188 +0,0 @@
|
|
1
|
-
# CanCanCan
|
2
|
-
|
3
|
-
[![Gem Version](https://badge.fury.io/rb/cancancan.svg)](http://badge.fury.io/rb/cancancan)
|
4
|
-
[![Travis badge](https://travis-ci.org/CanCanCommunity/cancancan.png?branch=master)](https://travis-ci.org/CanCanCommunity/cancancan)
|
5
|
-
[![Code Climate Badge](https://codeclimate.com/github/CanCanCommunity/cancancan.png)](https://codeclimate.com/github/CanCanCommunity/cancancan)
|
6
|
-
[![Inch CI](http://inch-ci.org/github/CanCanCommunity/cancancan.png)](http://inch-ci.org/github/CanCanCommunity/cancancan)
|
7
|
-
|
8
|
-
[Wiki](https://github.com/CanCanCommunity/cancancan/wiki) | [RDocs](http://rdoc.info/projects/CanCanCommunity/cancancan) | [Screencast](http://railscasts.com/episodes/192-authorization-with-cancan)
|
9
|
-
|
10
|
-
CanCan is an authorization library for Ruby on Rails which restricts what resources a given user is allowed to access. All permissions are defined in a single location (the `Ability` class) and not duplicated across controllers, views, and database queries.
|
11
|
-
|
12
|
-
## Mission
|
13
|
-
|
14
|
-
This repo is a continuation of the dead [CanCan](https://github.com/ryanb/cancan) project. Our mission is to keep CanCan alive and moving forward, with maintenance fixes and new features. Pull Requests are welcome!
|
15
|
-
|
16
|
-
I am currently focusing on the 1.x branch for the immediate future, making sure it is up to date as well as ensuring compatibility with Rails 4+. I will take a look into the 2.x branch and try to see what improvements, reorganizations and redesigns Ryan was attempting and go forward from there.
|
17
|
-
|
18
|
-
Any help is greatly appreciated, feel free to submit pull-requests or open issues.
|
19
|
-
|
20
|
-
|
21
|
-
## Installation
|
22
|
-
|
23
|
-
In **Rails 3 and 4**, add this to your Gemfile and run the `bundle install` command.
|
24
|
-
|
25
|
-
gem 'cancancan', '~> 1.10'
|
26
|
-
|
27
|
-
## Getting Started
|
28
|
-
|
29
|
-
CanCanCan expects a `current_user` method to exist in the controller. First, set up some authentication (such as [Authlogic](https://github.com/binarylogic/authlogic) or [Devise](https://github.com/plataformatec/devise)). See [Changing Defaults](https://github.com/CanCanCommunity/cancancan/wiki/changing-defaults) if you need different behavior.
|
30
|
-
|
31
|
-
|
32
|
-
### 1. Define Abilities
|
33
|
-
|
34
|
-
User permissions are defined in an `Ability` class. CanCan 1.5 includes a Rails 3 and 4 generator for creating this class.
|
35
|
-
|
36
|
-
rails g cancan:ability
|
37
|
-
|
38
|
-
In Rails 2.3, just add a new class in `app/models/ability.rb` with the following contents:
|
39
|
-
|
40
|
-
```ruby
|
41
|
-
class Ability
|
42
|
-
include CanCan::Ability
|
43
|
-
|
44
|
-
def initialize(user)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
```
|
48
|
-
|
49
|
-
See [Defining Abilities](https://github.com/CanCanCommunity/cancancan/wiki/defining-abilities) for details.
|
50
|
-
|
51
|
-
|
52
|
-
### 2. Check Abilities & Authorization
|
53
|
-
|
54
|
-
The current user's permissions can then be checked using the `can?` and `cannot?` methods in the view and controller.
|
55
|
-
|
56
|
-
```erb
|
57
|
-
<% if can? :update, @article %>
|
58
|
-
<%= link_to "Edit", edit_article_path(@article) %>
|
59
|
-
<% end %>
|
60
|
-
```
|
61
|
-
|
62
|
-
See [Checking Abilities](https://github.com/CanCanCommunity/cancancan/wiki/checking-abilities) for more information
|
63
|
-
|
64
|
-
The `authorize!` method in the controller will raise an exception if the user is not able to perform the given action.
|
65
|
-
|
66
|
-
```ruby
|
67
|
-
def show
|
68
|
-
@article = Article.find(params[:id])
|
69
|
-
authorize! :read, @article
|
70
|
-
end
|
71
|
-
```
|
72
|
-
|
73
|
-
Setting this for every action can be tedious, therefore the `load_and_authorize_resource` method is provided to automatically authorize all actions in a RESTful style resource controller. It will use a before filter to load the resource into an instance variable and authorize it for every action.
|
74
|
-
|
75
|
-
```ruby
|
76
|
-
class ArticlesController < ApplicationController
|
77
|
-
load_and_authorize_resource
|
78
|
-
|
79
|
-
def show
|
80
|
-
# @article is already loaded and authorized
|
81
|
-
end
|
82
|
-
end
|
83
|
-
```
|
84
|
-
|
85
|
-
See [Authorizing Controller Actions](https://github.com/CanCanCommunity/cancancan/wiki/authorizing-controller-actions) for more information.
|
86
|
-
|
87
|
-
|
88
|
-
#### Strong Parameters
|
89
|
-
|
90
|
-
When using `strong_parameters` or Rails 4+, you have to sanitize inputs before saving the record, in actions such as `:create` and `:update`.
|
91
|
-
|
92
|
-
By default, CanCan will try to sanitize the input on `:create` and `:update` routes by seeing if your controller will respond to the following methods (in order):
|
93
|
-
|
94
|
-
1. `create_params` or `update_params` (depending on the action you are performing)
|
95
|
-
2. `<model_name>_params` such as `article_params` (this is the default convention in rails for naming your param method)
|
96
|
-
3. `resource_params` (a generically named method you could specify in each controller)
|
97
|
-
|
98
|
-
Additionally, `load_and_authorize_resource` can now take a `param_method` option to specify a custom method in the controller to run to sanitize input.
|
99
|
-
|
100
|
-
You can associate the `param_method` option with a symbol corresponding to the name of a method that will get called:
|
101
|
-
|
102
|
-
```ruby
|
103
|
-
class ArticlesController < ApplicationController
|
104
|
-
load_and_authorize_resource param_method: :my_sanitizer
|
105
|
-
|
106
|
-
def create
|
107
|
-
if @article.save
|
108
|
-
# hurray
|
109
|
-
else
|
110
|
-
render :new
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
private
|
115
|
-
|
116
|
-
def my_sanitizer
|
117
|
-
params.require(:article).permit(:name)
|
118
|
-
end
|
119
|
-
end
|
120
|
-
```
|
121
|
-
|
122
|
-
You can also use a string that will be evaluated in the context of the controller using `instance_eval` and needs to contain valid Ruby code. This does come in handy when using a PermittedParams class as suggested in Railscast 371:
|
123
|
-
|
124
|
-
load_and_authorize_resource param_method: 'permitted_params.article'
|
125
|
-
|
126
|
-
Finally, it's possible to associate `param_method` with a Proc object which will be called with the controller as the only argument:
|
127
|
-
|
128
|
-
load_and_authorize_resource param_method: Proc.new { |c| c.params.require(:article).permit(:name) }
|
129
|
-
|
130
|
-
See [Strong Parameters](https://github.com/CanCanCommunity/cancancan/wiki/Strong-Parameters) for more information.
|
131
|
-
|
132
|
-
### 3. Handle Unauthorized Access
|
133
|
-
|
134
|
-
If the user authorization fails, a `CanCan::AccessDenied` exception will be raised. You can catch this and modify its behavior in the `ApplicationController`.
|
135
|
-
|
136
|
-
```ruby
|
137
|
-
class ApplicationController < ActionController::Base
|
138
|
-
rescue_from CanCan::AccessDenied do |exception|
|
139
|
-
redirect_to root_url, :alert => exception.message
|
140
|
-
end
|
141
|
-
end
|
142
|
-
```
|
143
|
-
|
144
|
-
See [Exception Handling](https://github.com/CanCanCommunity/cancancan/wiki/exception-handling) for more information.
|
145
|
-
|
146
|
-
|
147
|
-
### 4. Lock It Down
|
148
|
-
|
149
|
-
If you want to ensure authorization happens on every action in your application, add `check_authorization` to your `ApplicationController`.
|
150
|
-
|
151
|
-
```ruby
|
152
|
-
class ApplicationController < ActionController::Base
|
153
|
-
check_authorization
|
154
|
-
end
|
155
|
-
```
|
156
|
-
|
157
|
-
This will raise an exception if authorization is not performed in an action. If you want to skip this, add `skip_authorization_check` to a controller subclass. See [Ensure Authorization](https://github.com/CanCanCommunity/cancancan/wiki/Ensure-Authorization) for more information.
|
158
|
-
|
159
|
-
|
160
|
-
## Wiki Docs
|
161
|
-
|
162
|
-
* [Upgrading to 1.6](https://github.com/CanCanCommunity/cancancan/wiki/Upgrading-to-1.6)
|
163
|
-
* [Defining Abilities](https://github.com/CanCanCommunity/cancancan/wiki/Defining-Abilities)
|
164
|
-
* [Checking Abilities](https://github.com/CanCanCommunity/cancancan/wiki/Checking-Abilities)
|
165
|
-
* [Authorizing Controller Actions](https://github.com/CanCanCommunity/cancancan/wiki/Authorizing-Controller-Actions)
|
166
|
-
* [Exception Handling](https://github.com/CanCanCommunity/cancancan/wiki/Exception-Handling)
|
167
|
-
* [Changing Defaults](https://github.com/CanCanCommunity/cancancan/wiki/Changing-Defaults)
|
168
|
-
* [See more](https://github.com/CanCanCommunity/cancancan/wiki)
|
169
|
-
|
170
|
-
## Questions or Problems?
|
171
|
-
|
172
|
-
If you have any issues with CanCan which you cannot find the solution to in the [documentation](https://github.com/CanCanCommunity/cancancan/wiki) or our mailing list: http://groups.google.com/group/cancancan, please add an [issue on GitHub](https://github.com/CanCanCommunity/cancancan/issues) or fork the project and send a pull request.
|
173
|
-
|
174
|
-
|
175
|
-
## Development
|
176
|
-
|
177
|
-
Cancancan uses [appraisals](https://github.com/thoughtbot/appraisal) to test the code base against multiple versions of Rails, as well as the different model adapters.
|
178
|
-
|
179
|
-
When first developing, you may need to run `bundle install` and then `appraisal install`, to install the different sets.
|
180
|
-
|
181
|
-
You can then run all appraisal files (like CI does), with `appraisal rake` or just run a specific set `appraisal activerecord_3.0 rake`.
|
182
|
-
|
183
|
-
See the [CONTRIBUTING](https://github.com/CanCanCommunity/cancancan/blob/develop/CONTRIBUTING.md) and [spec/README](https://github.com/CanCanCommunity/cancancan/blob/master/spec/README.rdoc) for more information.
|
184
|
-
|
185
|
-
|
186
|
-
## Special Thanks
|
187
|
-
|
188
|
-
CanCan was inspired by [declarative_authorization](https://github.com/stffn/declarative_authorization/) and [aegis](https://github.com/makandra/aegis). Also many thanks to the [CanCan contributors](https://github.com/CanCanCommunity/cancancan/contributors). See the [CHANGELOG](https://github.com/CanCanCommunity/cancancan/blob/master/CHANGELOG.rdoc) for the full list.
|
data/Rakefile
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activerecord", "~> 3.0.20", :require => "active_record"
|
6
|
-
gem "activesupport", "~> 3.0.20", :require => "active_support/all"
|
7
|
-
gem "meta_where"
|
8
|
-
|
9
|
-
platforms :jruby do
|
10
|
-
gem "activerecord-jdbcsqlite3-adapter"
|
11
|
-
gem "jdbc-sqlite3"
|
12
|
-
end
|
13
|
-
|
14
|
-
platforms :ruby, :mswin, :mingw do
|
15
|
-
gem "sqlite3"
|
16
|
-
end
|
17
|
-
|
18
|
-
gemspec :path => "../"
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activerecord", "~> 3.1.0", :require => "active_record"
|
6
|
-
|
7
|
-
platforms :ruby_18, :ruby_19 do
|
8
|
-
gem "i18n", "< 0.7"
|
9
|
-
end
|
10
|
-
|
11
|
-
platforms :jruby do
|
12
|
-
gem "activerecord-jdbcsqlite3-adapter"
|
13
|
-
gem "jdbc-sqlite3"
|
14
|
-
end
|
15
|
-
|
16
|
-
platforms :ruby, :mswin, :mingw do
|
17
|
-
gem "sqlite3"
|
18
|
-
end
|
19
|
-
|
20
|
-
gemspec :path => "../"
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activerecord", "~> 3.2.0", :require => "active_record"
|
6
|
-
|
7
|
-
platforms :ruby_18, :ruby_19 do
|
8
|
-
gem "i18n", "< 0.7"
|
9
|
-
end
|
10
|
-
|
11
|
-
platforms :jruby do
|
12
|
-
gem "activerecord-jdbcsqlite3-adapter"
|
13
|
-
gem "jdbc-sqlite3"
|
14
|
-
end
|
15
|
-
|
16
|
-
platforms :ruby, :mswin, :mingw do
|
17
|
-
gem "sqlite3"
|
18
|
-
end
|
19
|
-
|
20
|
-
gemspec :path => "../"
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activerecord", "~> 4.0.5", :require => "active_record"
|
6
|
-
gem "activesupport", "~> 4.0.5", :require => "active_support/all"
|
7
|
-
|
8
|
-
platforms :jruby do
|
9
|
-
gem "activerecord-jdbcsqlite3-adapter"
|
10
|
-
gem "jdbc-sqlite3"
|
11
|
-
end
|
12
|
-
|
13
|
-
platforms :ruby, :mswin, :mingw do
|
14
|
-
gem "sqlite3"
|
15
|
-
end
|
16
|
-
|
17
|
-
gemspec :path => "../"
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activerecord", "~> 4.1.1", :require => "active_record"
|
6
|
-
gem "activesupport", "~> 4.1.1", :require => "active_support/all"
|
7
|
-
|
8
|
-
platforms :jruby do
|
9
|
-
gem "activerecord-jdbcsqlite3-adapter"
|
10
|
-
gem "jdbc-sqlite3"
|
11
|
-
end
|
12
|
-
|
13
|
-
platforms :ruby, :mswin, :mingw do
|
14
|
-
gem "sqlite3"
|
15
|
-
end
|
16
|
-
|
17
|
-
gemspec :path => "../"
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activerecord", "~> 4.2.0", :require => "active_record"
|
6
|
-
gem "activesupport", "~> 4.2.0", :require => "active_support/all"
|
7
|
-
|
8
|
-
platforms :jruby do
|
9
|
-
gem "activerecord-jdbcsqlite3-adapter"
|
10
|
-
gem "jdbc-sqlite3"
|
11
|
-
end
|
12
|
-
|
13
|
-
platforms :ruby, :mswin, :mingw do
|
14
|
-
gem "sqlite3"
|
15
|
-
gem "pg"
|
16
|
-
end
|
17
|
-
|
18
|
-
gemspec :path => "../"
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activesupport", "~> 3.0", :require => "active_support/all"
|
6
|
-
gem "dm-core", "~> 1.0"
|
7
|
-
gem "dm-sqlite-adapter", "~> 1.0"
|
8
|
-
gem "dm-migrations", "~> 1.0"
|
9
|
-
|
10
|
-
platforms :ruby_18, :ruby_19 do
|
11
|
-
gem "i18n", "< 0.7"
|
12
|
-
end
|
13
|
-
|
14
|
-
gemspec :path => "../"
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "activesupport", "~> 3.0", :require => "active_support/all"
|
6
|
-
gem "mongoid", "~> 2.0.0"
|
7
|
-
|
8
|
-
platforms :ruby_18, :ruby_19 do
|
9
|
-
gem "i18n", "< 0.7"
|
10
|
-
end
|
11
|
-
|
12
|
-
platforms :ruby, :mswin, :mingw do
|
13
|
-
gem "bson_ext", "~> 1.1"
|
14
|
-
end
|
15
|
-
|
16
|
-
platforms :jruby do
|
17
|
-
gem "mongo", "~> 1.9.2"
|
18
|
-
end
|
19
|
-
|
20
|
-
gemspec :path => "../"
|
data/gemfiles/sequel_3.x.gemfile
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
# This file was generated by Appraisal
|
2
|
-
|
3
|
-
source "https://rubygems.org"
|
4
|
-
|
5
|
-
gem "sequel", "~> 3.47.0"
|
6
|
-
gem "activesupport", "~> 3.0", :require => "active_support/all"
|
7
|
-
|
8
|
-
platforms :ruby_18, :ruby_19 do
|
9
|
-
gem "i18n", "< 0.7"
|
10
|
-
end
|
11
|
-
|
12
|
-
platforms :jruby do
|
13
|
-
gem "jdbc-sqlite3"
|
14
|
-
end
|
15
|
-
|
16
|
-
platforms :ruby, :mswin, :mingw do
|
17
|
-
gem "sqlite3"
|
18
|
-
end
|
19
|
-
|
20
|
-
gemspec :path => "../"
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module CanCan
|
2
|
-
# For use with Inherited Resources
|
3
|
-
class InheritedResource < ControllerResource # :nodoc:
|
4
|
-
def load_resource_instance
|
5
|
-
if parent?
|
6
|
-
@controller.send :association_chain
|
7
|
-
@controller.instance_variable_get("@#{instance_name}")
|
8
|
-
elsif new_actions.include? @params[:action].to_sym
|
9
|
-
resource = @controller.send :build_resource
|
10
|
-
assign_attributes(resource)
|
11
|
-
else
|
12
|
-
@controller.send :resource
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def resource_base
|
17
|
-
@controller.send :end_of_association_chain
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module CanCan
|
2
|
-
module ModelAdapters
|
3
|
-
class ActiveRecord3Adapter < AbstractAdapter
|
4
|
-
include ActiveRecordAdapter
|
5
|
-
def self.for_class?(model_class)
|
6
|
-
model_class <= ActiveRecord::Base
|
7
|
-
end
|
8
|
-
|
9
|
-
def self.override_condition_matching?(subject, name, value)
|
10
|
-
name.kind_of?(MetaWhere::Column) if defined? MetaWhere
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.matches_condition?(subject, name, value)
|
14
|
-
subject_value = subject.send(name.column)
|
15
|
-
if name.method.to_s.ends_with? "_any"
|
16
|
-
value.any? { |v| meta_where_match? subject_value, name.method.to_s.sub("_any", ""), v }
|
17
|
-
elsif name.method.to_s.ends_with? "_all"
|
18
|
-
value.all? { |v| meta_where_match? subject_value, name.method.to_s.sub("_all", ""), v }
|
19
|
-
else
|
20
|
-
meta_where_match? subject_value, name.method, value
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.meta_where_match?(subject_value, method, value)
|
25
|
-
case method.to_sym
|
26
|
-
when :eq then subject_value == value
|
27
|
-
when :not_eq then subject_value != value
|
28
|
-
when :in then value.include?(subject_value)
|
29
|
-
when :not_in then !value.include?(subject_value)
|
30
|
-
when :lt then subject_value < value
|
31
|
-
when :lteq then subject_value <= value
|
32
|
-
when :gt then subject_value > value
|
33
|
-
when :gteq then subject_value >= value
|
34
|
-
when :matches then subject_value =~ Regexp.new("^" + Regexp.escape(value).gsub("%", ".*") + "$", true)
|
35
|
-
when :does_not_match then !meta_where_match?(subject_value, :matches, value)
|
36
|
-
else raise NotImplemented, "The #{method} MetaWhere condition is not supported."
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def build_relation(*where_conditions)
|
43
|
-
@model_class.where(*where_conditions).includes(joins)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module CanCan
|
2
|
-
module ModelAdapters
|
3
|
-
class DataMapperAdapter < AbstractAdapter
|
4
|
-
def self.for_class?(model_class)
|
5
|
-
model_class <= DataMapper::Resource
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.find(model_class, id)
|
9
|
-
model_class.get(id)
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.override_conditions_hash_matching?(subject, conditions)
|
13
|
-
conditions.any? { |k,v| !k.kind_of?(Symbol) }
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.matches_conditions_hash?(subject, conditions)
|
17
|
-
collection = DataMapper::Collection.new(subject.query, [ subject ])
|
18
|
-
!!collection.first(conditions)
|
19
|
-
end
|
20
|
-
|
21
|
-
def database_records
|
22
|
-
scope = @model_class.all(:conditions => ["0 = 1"])
|
23
|
-
cans, cannots = @rules.partition { |r| r.base_behavior }
|
24
|
-
return scope if cans.empty?
|
25
|
-
# apply unions first, then differences. this mean cannot overrides can
|
26
|
-
cans.each { |r| scope += @model_class.all(:conditions => r.conditions) }
|
27
|
-
cannots.each { |r| scope -= @model_class.all(:conditions => r.conditions) }
|
28
|
-
scope
|
29
|
-
end
|
30
|
-
end # class DataMapper
|
31
|
-
end # module ModelAdapters
|
32
|
-
end # module CanCan
|
33
|
-
|
34
|
-
DataMapper::Model.append_extensions(CanCan::ModelAdditions::ClassMethods)
|
@@ -1,54 +0,0 @@
|
|
1
|
-
module CanCan
|
2
|
-
module ModelAdapters
|
3
|
-
class MongoidAdapter < AbstractAdapter
|
4
|
-
def self.for_class?(model_class)
|
5
|
-
model_class <= Mongoid::Document
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.override_conditions_hash_matching?(subject, conditions)
|
9
|
-
conditions.any? do |k,v|
|
10
|
-
key_is_not_symbol = lambda { !k.kind_of?(Symbol) }
|
11
|
-
subject_value_is_array = lambda do
|
12
|
-
subject.respond_to?(k) && subject.send(k).is_a?(Array)
|
13
|
-
end
|
14
|
-
|
15
|
-
key_is_not_symbol.call || subject_value_is_array.call
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.matches_conditions_hash?(subject, conditions)
|
20
|
-
# To avoid hitting the db, retrieve the raw Mongo selector from
|
21
|
-
# the Mongoid Criteria and use Mongoid::Matchers#matches?
|
22
|
-
subject.matches?( subject.class.where(conditions).selector )
|
23
|
-
end
|
24
|
-
|
25
|
-
def database_records
|
26
|
-
if @rules.size == 0
|
27
|
-
@model_class.where(:_id => {'$exists' => false, '$type' => 7}) # return no records in Mongoid
|
28
|
-
elsif @rules.size == 1 && @rules[0].conditions.is_a?(Mongoid::Criteria)
|
29
|
-
@rules[0].conditions
|
30
|
-
else
|
31
|
-
# we only need to process can rules if
|
32
|
-
# there are no rules with empty conditions
|
33
|
-
rules = @rules.reject { |rule| rule.conditions.empty? && rule.base_behavior }
|
34
|
-
process_can_rules = @rules.count == rules.count
|
35
|
-
|
36
|
-
rules.inject(@model_class.all) do |records, rule|
|
37
|
-
if process_can_rules && rule.base_behavior
|
38
|
-
records.or rule.conditions
|
39
|
-
elsif !rule.base_behavior
|
40
|
-
records.excludes rule.conditions
|
41
|
-
else
|
42
|
-
records
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
# simplest way to add `accessible_by` to all Mongoid Documents
|
52
|
-
module Mongoid::Document::ClassMethods
|
53
|
-
include CanCan::ModelAdditions::ClassMethods
|
54
|
-
end
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module CanCan
|
2
|
-
module ModelAdapters
|
3
|
-
class SequelAdapter < AbstractAdapter
|
4
|
-
def self.for_class?(model_class)
|
5
|
-
model_class <= Sequel::Model
|
6
|
-
end
|
7
|
-
|
8
|
-
def self.find(model_class, id)
|
9
|
-
model_class[id]
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.override_condition_matching?(subject, name, value)
|
13
|
-
value.kind_of?(Hash)
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.matches_condition?(subject, name, value)
|
17
|
-
obj = subject.send(name)
|
18
|
-
if obj.nil?
|
19
|
-
false
|
20
|
-
else
|
21
|
-
value.each do |k, v|
|
22
|
-
if v.kind_of?(Hash)
|
23
|
-
return false unless self.matches_condition?(obj, k, v)
|
24
|
-
elsif obj.send(k) != v
|
25
|
-
return false
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def database_records
|
32
|
-
if @rules.size == 0
|
33
|
-
@model_class.where('1=0')
|
34
|
-
else
|
35
|
-
# only need to process can rules if there are no can rule with empty conditions
|
36
|
-
rules = @rules.reject { |rule| rule.base_behavior && rule.conditions.empty? }
|
37
|
-
rules.reject! { |rule| rule.base_behavior } if rules.count < @rules.count
|
38
|
-
|
39
|
-
can_condition_added = false
|
40
|
-
rules.reverse.inject(@model_class.dataset) do |records, rule|
|
41
|
-
normalized_conditions = normalize_conditions(rule.conditions)
|
42
|
-
if rule.base_behavior
|
43
|
-
if can_condition_added
|
44
|
-
records.or normalized_conditions
|
45
|
-
else
|
46
|
-
can_condition_added = true
|
47
|
-
records.where normalized_conditions
|
48
|
-
end
|
49
|
-
else
|
50
|
-
records.exclude normalized_conditions
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
private
|
57
|
-
|
58
|
-
def normalize_conditions(conditions, model_class = @model_class)
|
59
|
-
return conditions unless conditions.kind_of? Hash
|
60
|
-
conditions.inject({}) do |result_hash, (name, value)|
|
61
|
-
if value.kind_of? Hash
|
62
|
-
value = value.dup
|
63
|
-
association_class = model_class.association_reflection(name).associated_class
|
64
|
-
nested = value.inject({}) do |nested, (k, v)|
|
65
|
-
if v.kind_of?(Hash)
|
66
|
-
value.delete(k)
|
67
|
-
nested_class = association_class.association_reflection(k).associated_class
|
68
|
-
nested[k] = nested_class.where(normalize_conditions(v, association_class))
|
69
|
-
else
|
70
|
-
nested[k] = v
|
71
|
-
end
|
72
|
-
nested
|
73
|
-
end
|
74
|
-
result_hash[name] = association_class.where(nested)
|
75
|
-
else
|
76
|
-
result_hash[name] = value
|
77
|
-
end
|
78
|
-
result_hash
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
Sequel::Model.class_eval do
|
86
|
-
include CanCan::ModelAdditions
|
87
|
-
end
|
data/spec/README.rdoc
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
= CanCan Specs
|
2
|
-
|
3
|
-
== Running the specs
|
4
|
-
|
5
|
-
To run the specs first run the +bundle+ command to install the necessary gems and the +rake+ command to run the specs.
|
6
|
-
|
7
|
-
bundle
|
8
|
-
|
9
|
-
Then run the appraisal command to install all the necessary test sets:
|
10
|
-
|
11
|
-
appraisal install
|
12
|
-
|
13
|
-
You can then run all test sets:
|
14
|
-
|
15
|
-
appraisal rake
|
16
|
-
|
17
|
-
Or individual ones:
|
18
|
-
|
19
|
-
appraisal rails_3.0 rake
|
20
|
-
|
21
|
-
A list of the tests is in the +Appraisal+ file.
|
22
|
-
|
23
|
-
The specs support Ruby 1.8.7+
|
24
|
-
|
25
|
-
== Model Adapters
|
26
|
-
|
27
|
-
The model adapter ENV setting has been removed and replaced with the +Appraisal+ file.
|