cancan 1.4.1 → 1.5.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +21 -0
- data/Gemfile +17 -0
- data/LICENSE +1 -1
- data/README.rdoc +16 -77
- data/Rakefile +8 -0
- data/lib/cancan.rb +8 -3
- data/lib/cancan/ability.rb +24 -26
- data/lib/cancan/controller_additions.rb +50 -0
- data/lib/cancan/controller_resource.rb +33 -15
- data/lib/cancan/exceptions.rb +3 -0
- data/lib/cancan/model_adapters/abstract_adapter.rb +40 -0
- data/lib/cancan/model_adapters/active_record_adapter.rb +119 -0
- data/lib/cancan/model_adapters/data_mapper_adapter.rb +33 -0
- data/lib/cancan/model_adapters/default_adapter.rb +7 -0
- data/lib/cancan/model_adapters/mongoid_adapter.rb +41 -0
- data/lib/cancan/{active_record_additions.rb → model_additions.rb} +5 -16
- data/lib/cancan/{can_definition.rb → rule.rb} +29 -25
- data/lib/generators/cancan/ability/USAGE +4 -0
- data/lib/generators/cancan/ability/ability_generator.rb +11 -0
- data/lib/generators/cancan/ability/templates/ability.rb +28 -0
- data/spec/README.rdoc +28 -0
- data/spec/cancan/ability_spec.rb +11 -3
- data/spec/cancan/controller_additions_spec.rb +30 -0
- data/spec/cancan/controller_resource_spec.rb +68 -2
- data/spec/cancan/inherited_resource_spec.rb +3 -1
- data/spec/cancan/model_adapters/active_record_adapter_spec.rb +185 -0
- data/spec/cancan/model_adapters/data_mapper_adapter_spec.rb +115 -0
- data/spec/cancan/model_adapters/default_adapter_spec.rb +7 -0
- data/spec/cancan/model_adapters/mongoid_adapter_spec.rb +168 -0
- data/spec/cancan/rule_spec.rb +39 -0
- data/spec/spec_helper.rb +2 -24
- metadata +26 -17
- data/lib/cancan/query.rb +0 -97
- data/spec/cancan/active_record_additions_spec.rb +0 -75
- data/spec/cancan/can_definition_spec.rb +0 -57
- data/spec/cancan/query_spec.rb +0 -107
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,24 @@
|
|
1
|
+
1.5.0 (not yet released)
|
2
|
+
|
3
|
+
* Added an Ability generator - see issue #170
|
4
|
+
|
5
|
+
* Added DataMapper support (thanks natemueller)
|
6
|
+
|
7
|
+
* Added Mongoid support (thanks bowsersenior)
|
8
|
+
|
9
|
+
* Added skip_load_and_authorize_resource methods to controller class - see issue #164
|
10
|
+
|
11
|
+
* Added support for uncountable resources in index action - see issue #193
|
12
|
+
|
13
|
+
* Cleaned up README and added spec/README
|
14
|
+
|
15
|
+
* Internal: renamed CanDefinition to Rule
|
16
|
+
|
17
|
+
* Internal: added a model adapter layer for easily supporting more ORMs
|
18
|
+
|
19
|
+
* Internal: added .rvmrc to auto-switch to 1.8.7 with gemset - see issue #231
|
20
|
+
|
21
|
+
|
1
22
|
1.4.1 (November 12, 2010)
|
2
23
|
|
3
24
|
* Renaming skip_authorization to skip_authorization_check - see issue #169
|
data/Gemfile
CHANGED
@@ -1,2 +1,19 @@
|
|
1
1
|
source "http://rubygems.org"
|
2
|
+
|
3
|
+
case ENV["MODEL_ADAPTER"]
|
4
|
+
when nil, "active_record"
|
5
|
+
gem "sqlite3-ruby", :require => "sqlite3"
|
6
|
+
gem "activerecord", :require => "active_record"
|
7
|
+
gem "with_model"
|
8
|
+
when "data_mapper"
|
9
|
+
gem "dm-core", "~> 1.0.2"
|
10
|
+
gem "dm-sqlite-adapter", "~> 1.0.2"
|
11
|
+
gem "dm-migrations", "~> 1.0.2"
|
12
|
+
when "mongoid"
|
13
|
+
gem "bson_ext", "~> 1.1"
|
14
|
+
gem "mongoid", "~> 2.0.0.beta.19"
|
15
|
+
else
|
16
|
+
raise "Unknown model adapter: #{ENV["MODEL_ADAPTER"]}"
|
17
|
+
end
|
18
|
+
|
2
19
|
gemspec
|
data/LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= CanCan
|
2
2
|
|
3
|
-
Wiki[
|
3
|
+
Wiki[https://github.com/ryanb/cancan/wiki] | RDocs[http://rdoc.info/projects/ryanb/cancan] | Screencast[http://railscasts.com/episodes/192-authorization-with-cancan]
|
4
4
|
|
5
5
|
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.
|
6
6
|
|
@@ -22,7 +22,7 @@ Alternatively, you can install it as a plugin.
|
|
22
22
|
|
23
23
|
== Getting Started
|
24
24
|
|
25
|
-
CanCan expects a +current_user+ method to exist. If you have not already, set up some authentication (such as Authlogic[
|
25
|
+
CanCan expects a +current_user+ method to exist in controllers. If you have not already, 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/ryanb/cancan/wiki/changing-defaults] if you need different behavior.
|
26
26
|
|
27
27
|
Next create a class called +Ability+ in "models/ability.rb" or anywhere else in the load path. It should look similar to this.
|
28
28
|
|
@@ -38,15 +38,15 @@ Next create a class called +Ability+ in "models/ability.rb" or anywhere else in
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
-
The +current_user+ is passed in to this method which is where the abilities are defined. See
|
41
|
+
The +current_user+ is passed in to this method which is where the abilities are defined. See {Defining Abilities}[https://github.com/ryanb/cancan/wiki/defining-abilities] for what can go here.
|
42
42
|
|
43
|
-
The current user's permissions can be accessed using the "can?" and "cannot?" methods in the view and controller.
|
43
|
+
The current user's permissions can then be accessed using the "can?" and "cannot?" methods in the view and controller.
|
44
44
|
|
45
45
|
<% if can? :update, @article %>
|
46
46
|
<%= link_to "Edit", edit_article_path(@article) %>
|
47
47
|
<% end %>
|
48
48
|
|
49
|
-
See {Checking Abilities}[
|
49
|
+
See {Checking Abilities}[https://github.com/ryanb/cancan/wiki/checking-abilities] for more information
|
50
50
|
|
51
51
|
The "authorize!" method in the controller will raise an exception if the user is not able to perform the given action.
|
52
52
|
|
@@ -65,7 +65,7 @@ Setting this for every action can be tedious, therefore the +load_and_authorize_
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
-
See {Authorizing Controller Actions}[
|
68
|
+
See {Authorizing Controller Actions}[https://github.com/ryanb/cancan/wiki/authorizing-controller-actions] for more information
|
69
69
|
|
70
70
|
If the user authorization fails, a <tt>CanCan::AccessDenied</tt> exception will be raised. You can catch this and modify its behavior in the +ApplicationController+.
|
71
71
|
|
@@ -76,87 +76,26 @@ If the user authorization fails, a <tt>CanCan::AccessDenied</tt> exception will
|
|
76
76
|
end
|
77
77
|
end
|
78
78
|
|
79
|
-
See {Exception Handling}[
|
80
|
-
|
81
|
-
|
82
|
-
== Defining Abilities
|
83
|
-
|
84
|
-
As shown above, the +Ability+ class is where all user permissions are defined. The current user model is passed into the initialize method so the permissions can be modified based on any user attributes. CanCan makes no assumption about how roles are handled in your application. See {Role Based Authorization}[http://wiki.github.com/ryanb/cancan/role-based-authorization] for an example.
|
85
|
-
|
86
|
-
The +can+ method is used to define permissions and requires two arguments. The first one is the action you're setting the permission for, the second one is the class of object you're setting it on.
|
87
|
-
|
88
|
-
can :update, Article
|
89
|
-
|
90
|
-
You can pass an array for either of these parameters to match any one. In this case the user will have the ability to update or destroy both articles and comments.
|
91
|
-
|
92
|
-
can [:update, :destroy], [Article, Comment]
|
93
|
-
|
94
|
-
Use :+manage+ to represent any action and :+all+ to represent any class. Here are some examples.
|
95
|
-
|
96
|
-
can :manage, Article # has permissions to do anything to articles
|
97
|
-
can :read, :all # has permission to read any model
|
98
|
-
can :manage, :all # has permission to do anything to any model
|
99
|
-
|
100
|
-
You can pass a hash of conditions as the third argument to further define what the user is able to access. Here the user will only have permission to read active projects which he owns.
|
101
|
-
|
102
|
-
can :read, Project, :active => true, :user_id => user.id
|
103
|
-
|
104
|
-
See {Defining Abilities with Hashes}[http://wiki.github.com/ryanb/cancan/defining-abilities-with-hashes] for more information.
|
105
|
-
|
106
|
-
Blocks can also be used if you need more control.
|
107
|
-
|
108
|
-
can :update, Project do |project|
|
109
|
-
project.groups.include?(user.group)
|
110
|
-
end
|
111
|
-
|
112
|
-
If the block returns true then the user has that ability for that project, otherwise he will be denied access. See {Defining Abilities with Blocks}[http://wiki.github.com/ryanb/cancan/defining-abilities-with-blocks] for more information.
|
113
|
-
|
114
|
-
|
115
|
-
== Aliasing Actions
|
116
|
-
|
117
|
-
You will usually be working with four actions when defining and checking permissions: :+read+, :+create+, :+update+, :+destroy+. These aren't the same as the 7 RESTful actions in Rails. CanCan automatically adds some default aliases for mapping those actions.
|
118
|
-
|
119
|
-
alias_action :index, :show, :to => :read
|
120
|
-
alias_action :new, :to => :create
|
121
|
-
alias_action :edit, :to => :update
|
122
|
-
|
123
|
-
Notice the +edit+ action is aliased to +update+. This means if the user is able to update a record he also has permission to edit it. You can define your own aliases in the +Ability+ class.
|
124
|
-
|
125
|
-
alias_action :update, :destroy, :to => :modify
|
126
|
-
can :modify, Comment
|
127
|
-
can? :update, Comment # => true
|
128
|
-
|
129
|
-
The +alias_action+ method is an instance method and usually called in +initialize+. See {Custom Actions}[http://wiki.github.com/ryanb/cancan/custom-actions] for information on adding other actions.
|
130
|
-
|
131
|
-
|
132
|
-
== Fetching Records
|
133
|
-
|
134
|
-
It is possible to fetch records which the user has permission to read using the +accessible_by+ scope in Active Record.
|
135
|
-
|
136
|
-
@articles = Article.accessible_by(current_ability)
|
137
|
-
|
138
|
-
Since version 1.4 this is done automatically when loading resources in the index action, so one rarely needs to do it manually.
|
139
|
-
|
140
|
-
This will only work when abilities are defined using hash conditions, not blocks. See {Fetching Records}[http://wiki.github.com/ryanb/cancan/fetching-records] for more information.
|
79
|
+
See {Exception Handling}[https://github.com/ryanb/cancan/wiki/exception-handling] for more information.
|
141
80
|
|
142
81
|
|
143
82
|
== Additional Docs
|
144
83
|
|
145
|
-
* {Upgrading to 1.4}[
|
146
|
-
* {Nested Resources}[
|
147
|
-
* {Testing Abilities}[
|
148
|
-
* {Accessing Request Data}[
|
149
|
-
* {Admin Namespace}[
|
150
|
-
* {See more}[
|
84
|
+
* {Upgrading to 1.4}[https://github.com/ryanb/cancan/wiki/Upgrading-to-1.4]
|
85
|
+
* {Nested Resources}[https://github.com/ryanb/cancan/wiki/nested-resources]
|
86
|
+
* {Testing Abilities}[https://github.com/ryanb/cancan/wiki/testing-abilities]
|
87
|
+
* {Accessing Request Data}[https://github.com/ryanb/cancan/wiki/accessing-request-data]
|
88
|
+
* {Admin Namespace}[https://github.com/ryanb/cancan/wiki/admin-namespace]
|
89
|
+
* {See more}[https://github.com/ryanb/cancan/wiki]
|
151
90
|
|
152
91
|
|
153
92
|
== Questions or Problems?
|
154
93
|
|
155
|
-
If you have any issues with CanCan which you cannot find the solution to in the documentation, please add an {issue on GitHub}[
|
94
|
+
If you have any issues with CanCan which you cannot find the solution to in the documentation, please add an {issue on GitHub}[https://github.com/ryanb/cancan/issues] or fork the project and send a pull request.
|
156
95
|
|
157
|
-
To get the specs running you should call +bundle+ and then +rake+. Specs currently do not work in Ruby 1.9 due to the RR mocking framework.
|
96
|
+
To get the specs running you should call +bundle+ and then +rake+. Specs currently do not work in Ruby 1.9 due to the RR mocking framework. See the {spec/README}[https://github.com/ryanb/cancan/blob/master/spec/README.rdoc] for more information.
|
158
97
|
|
159
98
|
|
160
99
|
== Special Thanks
|
161
100
|
|
162
|
-
CanCan was inspired by declarative_authorization[
|
101
|
+
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/ryanb/cancan/contributors]. See the CHANGELOG[https://github.com/ryanb/cancan/blob/master/CHANGELOG.rdoc] for the full list.
|
data/Rakefile
CHANGED
@@ -7,4 +7,12 @@ RSpec::Core::RakeTask.new do |t|
|
|
7
7
|
t.verbose = false
|
8
8
|
end
|
9
9
|
|
10
|
+
desc "Run specs for all adapters"
|
11
|
+
task :spec_all do
|
12
|
+
%w[active_record data_mapper mongoid].each do |model_adapter|
|
13
|
+
puts "MODEL_ADAPTER = #{model_adapter}"
|
14
|
+
system "rake spec MODEL_ADAPTER=#{model_adapter}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
10
18
|
task :default => :spec
|
data/lib/cancan.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
require 'cancan/ability'
|
2
|
-
require 'cancan/
|
2
|
+
require 'cancan/rule'
|
3
3
|
require 'cancan/controller_resource'
|
4
4
|
require 'cancan/controller_additions'
|
5
|
-
require 'cancan/
|
5
|
+
require 'cancan/model_additions'
|
6
6
|
require 'cancan/exceptions'
|
7
|
-
require 'cancan/query'
|
8
7
|
require 'cancan/inherited_resource'
|
8
|
+
|
9
|
+
require 'cancan/model_adapters/abstract_adapter'
|
10
|
+
require 'cancan/model_adapters/default_adapter'
|
11
|
+
require 'cancan/model_adapters/active_record_adapter' if defined? ActiveRecord
|
12
|
+
require 'cancan/model_adapters/data_mapper_adapter' if defined? DataMapper
|
13
|
+
require 'cancan/model_adapters/mongoid_adapter' if defined? Mongoid
|
data/lib/cancan/ability.rb
CHANGED
@@ -54,8 +54,8 @@ module CanCan
|
|
54
54
|
#
|
55
55
|
# Also see the RSpec Matchers to aid in testing.
|
56
56
|
def can?(action, subject, *extra_args)
|
57
|
-
match =
|
58
|
-
|
57
|
+
match = relevant_rules_for_match(action, subject).detect do |rule|
|
58
|
+
rule.matches_conditions?(action, subject, extra_args)
|
59
59
|
end
|
60
60
|
match ? match.base_behavior : false
|
61
61
|
end
|
@@ -122,7 +122,7 @@ module CanCan
|
|
122
122
|
# end
|
123
123
|
#
|
124
124
|
def can(action = nil, subject = nil, conditions = nil, &block)
|
125
|
-
|
125
|
+
rules << Rule.new(true, action, subject, conditions, block)
|
126
126
|
end
|
127
127
|
|
128
128
|
# Defines an ability which cannot be done. Accepts the same arguments as "can".
|
@@ -138,7 +138,7 @@ module CanCan
|
|
138
138
|
# end
|
139
139
|
#
|
140
140
|
def cannot(action = nil, subject = nil, conditions = nil, &block)
|
141
|
-
|
141
|
+
rules << Rule.new(false, action, subject, conditions, block)
|
142
142
|
end
|
143
143
|
|
144
144
|
# Alias one or more actions into another one.
|
@@ -186,11 +186,9 @@ module CanCan
|
|
186
186
|
@aliased_actions = {}
|
187
187
|
end
|
188
188
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
def query(action, subject)
|
193
|
-
Query.new(subject, relevant_can_definitions_for_query(action, subject))
|
189
|
+
def model_adapter(model_class, action)
|
190
|
+
adapter_class = ModelAdapters::AbstractAdapter.adapter_class(model_class)
|
191
|
+
adapter_class.new(model_class, relevant_rules_for_query(action, model_class))
|
194
192
|
end
|
195
193
|
|
196
194
|
# See ControllerAdditions#authorize! for documentation.
|
@@ -215,18 +213,18 @@ module CanCan
|
|
215
213
|
|
216
214
|
def attributes_for(action, subject)
|
217
215
|
attributes = {}
|
218
|
-
|
219
|
-
attributes.merge!(
|
216
|
+
relevant_rules(action, subject).map do |rule|
|
217
|
+
attributes.merge!(rule.attributes_from_conditions) if rule.base_behavior
|
220
218
|
end
|
221
219
|
attributes
|
222
220
|
end
|
223
221
|
|
224
222
|
def has_block?(action, subject)
|
225
|
-
|
223
|
+
relevant_rules(action, subject).any?(&:only_block?)
|
226
224
|
end
|
227
225
|
|
228
226
|
def has_raw_sql?(action, subject)
|
229
|
-
|
227
|
+
relevant_rules(action, subject).any?(&:only_raw_sql?)
|
230
228
|
end
|
231
229
|
|
232
230
|
private
|
@@ -259,30 +257,30 @@ module CanCan
|
|
259
257
|
results
|
260
258
|
end
|
261
259
|
|
262
|
-
def
|
263
|
-
@
|
260
|
+
def rules
|
261
|
+
@rules ||= []
|
264
262
|
end
|
265
263
|
|
266
|
-
# Returns an array of
|
264
|
+
# Returns an array of Rule instances which match the action and subject
|
267
265
|
# This does not take into consideration any hash conditions or block statements
|
268
|
-
def
|
269
|
-
|
270
|
-
|
271
|
-
|
266
|
+
def relevant_rules(action, subject)
|
267
|
+
rules.reverse.select do |rule|
|
268
|
+
rule.expanded_actions = expand_actions(rule.actions)
|
269
|
+
rule.relevant? action, subject
|
272
270
|
end
|
273
271
|
end
|
274
272
|
|
275
|
-
def
|
276
|
-
|
277
|
-
if
|
273
|
+
def relevant_rules_for_match(action, subject)
|
274
|
+
relevant_rules(action, subject).each do |rule|
|
275
|
+
if rule.only_raw_sql?
|
278
276
|
raise Error, "The can? and cannot? call cannot be used with a raw sql 'can' definition. The checking code cannot be determined for #{action.inspect} #{subject.inspect}"
|
279
277
|
end
|
280
278
|
end
|
281
279
|
end
|
282
280
|
|
283
|
-
def
|
284
|
-
|
285
|
-
if
|
281
|
+
def relevant_rules_for_query(action, subject)
|
282
|
+
relevant_rules(action, subject).each do |rule|
|
283
|
+
if rule.only_block?
|
286
284
|
raise Error, "The accessible_by call cannot be used with a block 'can' definition. The SQL cannot be determined for #{action.inspect} #{subject.inspect}"
|
287
285
|
end
|
288
286
|
end
|
@@ -166,6 +166,52 @@ module CanCan
|
|
166
166
|
cancan_resource_class.add_before_filter(self, :authorize_resource, *args)
|
167
167
|
end
|
168
168
|
|
169
|
+
# Skip both the loading and authorization behavior of CanCan for this given controller. This is primarily
|
170
|
+
# useful to skip the behavior of a superclass. You can pass :only and :except options to specify which actions
|
171
|
+
# to skip the effects on. It will apply to all actions by default.
|
172
|
+
#
|
173
|
+
# class ProjectsController < SomeOtherController
|
174
|
+
# skip_load_and_authorize_resource :only => :index
|
175
|
+
# end
|
176
|
+
#
|
177
|
+
# You can also pass the resource name as the first argument to skip that resource.
|
178
|
+
def skip_load_and_authorize_resource(*args)
|
179
|
+
skip_load_resource(*args)
|
180
|
+
skip_authorize_resource(*args)
|
181
|
+
end
|
182
|
+
|
183
|
+
# Skip both the loading behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
|
184
|
+
# only do authorization on certain actions. You can pass :only and :except options to specify which actions to
|
185
|
+
# skip the effects on. It will apply to all actions by default.
|
186
|
+
#
|
187
|
+
# class ProjectsController < ApplicationController
|
188
|
+
# load_and_authorize_resource
|
189
|
+
# skip_load_resource :only => :index
|
190
|
+
# end
|
191
|
+
#
|
192
|
+
# You can also pass the resource name as the first argument to skip that resource.
|
193
|
+
def skip_load_resource(*args)
|
194
|
+
options = args.extract_options!
|
195
|
+
name = args.first
|
196
|
+
cancan_skipper[:load][name] = options
|
197
|
+
end
|
198
|
+
|
199
|
+
# Skip both the authorization behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
|
200
|
+
# only do loading on certain actions. You can pass :only and :except options to specify which actions to
|
201
|
+
# skip the effects on. It will apply to all actions by default.
|
202
|
+
#
|
203
|
+
# class ProjectsController < ApplicationController
|
204
|
+
# load_and_authorize_resource
|
205
|
+
# skip_authorize_resource :only => :index
|
206
|
+
# end
|
207
|
+
#
|
208
|
+
# You can also pass the resource name as the first argument to skip that resource.
|
209
|
+
def skip_authorize_resource(*args)
|
210
|
+
options = args.extract_options!
|
211
|
+
name = args.first
|
212
|
+
cancan_skipper[:authorize][name] = options
|
213
|
+
end
|
214
|
+
|
169
215
|
# Add this to a controller to ensure it performs authorization through +authorized+! or +authorize_resource+ call.
|
170
216
|
# If neither of these authorization methods are called, a CanCan::AuthorizationNotPerformed exception will be raised.
|
171
217
|
# This is normally added to the ApplicationController to ensure all controller actions do authorization.
|
@@ -209,6 +255,10 @@ module CanCan
|
|
209
255
|
ControllerResource
|
210
256
|
end
|
211
257
|
end
|
258
|
+
|
259
|
+
def cancan_skipper
|
260
|
+
@_cancan_skipper ||= {:authorize => {}, :load => {}}
|
261
|
+
end
|
212
262
|
end
|
213
263
|
|
214
264
|
def self.included(base)
|
@@ -26,21 +26,38 @@ module CanCan
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def load_resource
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
unless skip?(:load)
|
30
|
+
if load_instance?
|
31
|
+
self.resource_instance ||= load_resource_instance
|
32
|
+
elsif load_collection?
|
33
|
+
self.collection_instance ||= load_collection
|
34
|
+
end
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
36
38
|
def authorize_resource
|
37
|
-
|
39
|
+
unless skip?(:authorize)
|
40
|
+
@controller.authorize!(authorization_action, resource_instance || resource_class_with_parent)
|
41
|
+
end
|
38
42
|
end
|
39
43
|
|
40
44
|
def parent?
|
41
45
|
@options.has_key?(:parent) ? @options[:parent] : @name && @name != name_from_controller.to_sym
|
42
46
|
end
|
43
47
|
|
48
|
+
def skip?(behavior) # This could probably use some refactoring
|
49
|
+
options = @controller.class.cancan_skipper[behavior][@name]
|
50
|
+
if options.nil?
|
51
|
+
false
|
52
|
+
elsif options == {}
|
53
|
+
true
|
54
|
+
elsif options[:except] && ![options[:except]].flatten.include?(@params[:action].to_sym)
|
55
|
+
true
|
56
|
+
elsif [options[:only]].flatten.include?(@params[:action].to_sym)
|
57
|
+
true
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
44
61
|
protected
|
45
62
|
|
46
63
|
def load_resource_instance
|
@@ -51,9 +68,12 @@ module CanCan
|
|
51
68
|
end
|
52
69
|
end
|
53
70
|
|
71
|
+
def load_instance?
|
72
|
+
parent? || member_action?
|
73
|
+
end
|
74
|
+
|
54
75
|
def load_collection?
|
55
|
-
resource_base.respond_to?(:accessible_by) &&
|
56
|
-
!current_ability.has_block?(authorization_action, resource_class)
|
76
|
+
resource_base.respond_to?(:accessible_by) && !current_ability.has_block?(authorization_action, resource_class)
|
57
77
|
end
|
58
78
|
|
59
79
|
def load_collection
|
@@ -61,20 +81,18 @@ module CanCan
|
|
61
81
|
end
|
62
82
|
|
63
83
|
def build_resource
|
64
|
-
|
65
|
-
|
66
|
-
else
|
67
|
-
resource = resource_base.send("new")
|
68
|
-
end
|
84
|
+
method_name = @options[:singleton] && resource_base.respond_to?("build_#{name}") ? "build_#{name}" : "new"
|
85
|
+
resource = resource_base.send(method_name, @params[name] || {})
|
69
86
|
initial_attributes.each do |name, value|
|
70
87
|
resource.send("#{name}=", value)
|
71
88
|
end
|
72
|
-
resource.attributes = @params[name] if @params[name]
|
73
89
|
resource
|
74
90
|
end
|
75
91
|
|
76
92
|
def initial_attributes
|
77
|
-
current_ability.attributes_for(@params[:action].to_sym, resource_class)
|
93
|
+
current_ability.attributes_for(@params[:action].to_sym, resource_class).delete_if do |key, value|
|
94
|
+
@params[name] && @params[name].include?(key)
|
95
|
+
end
|
78
96
|
end
|
79
97
|
|
80
98
|
def find_resource
|
@@ -118,7 +136,7 @@ module CanCan
|
|
118
136
|
end
|
119
137
|
|
120
138
|
def resource_instance
|
121
|
-
@controller.instance_variable_get("@#{instance_name}")
|
139
|
+
@controller.instance_variable_get("@#{instance_name}") if load_instance?
|
122
140
|
end
|
123
141
|
|
124
142
|
def collection_instance=(instance)
|