Compare commits

...

108 Commits

Author SHA1 Message Date
acc76446c5 Making initial changes to add authorize after update 2013-06-28 23:34:07 -04:00
Ryan Bates
f2f40c7aac releasing 1.6.10 2013-05-07 11:29:15 -07:00
Ryan Bates
ea2b07f416 fix matches_conditons_hash for string values on 1.8 2013-05-07 11:23:08 -07:00
Ryan Bates
60cf6a67ef Merge pull request #675 from bukalapak/master
porting #668 to master branch
2013-05-03 16:15:31 -07:00
Vasiliy Ermolovich
ff2b632f15 Merge pull request #728 from zephyr-dev/patch-1
Add docs for id_param option of load_resource
2013-02-21 21:49:22 -08:00
Ryan Bates
ba82241c0a Merge pull request #705 from albertobajo/mongoid_find_by
Fixed load_resource "find_by" in mongoid resources
2013-02-21 17:50:03 -08:00
Ryan Bates
cbd352c799 Merge pull request #806 from yuszuv/support_for_nested_joins
added support for nested join conditions
2013-02-21 17:45:54 -08:00
Ryan Bates
1cb33bdac5 Merge pull request #800 from wopata/master
Working around a SQL Injection Vulnerability in Ruby on Rails (CVE-2012-5664)
2013-02-21 17:43:36 -08:00
Ben Moss
9f7f520fa7 Add docs for id_param option of load_resource
Added in https://github.com/ryanb/cancan/pull/425 but lacked documentation
2013-02-20 10:05:15 -05:00
Ryan Bates
38d4654523 releasing 1.6.9 2013-02-04 14:18:38 -08:00
jan
e3ba6688b5 added support for nested join conditions 2013-01-20 17:24:17 +01:00
Roland Venesz
d3a8929111 Creating a Project here is unnecessary 2013-01-03 13:26:24 +01:00
Roland Venesz
d5123e0eb3 Working around CVE-2012-5664 2013-01-03 13:16:30 +01:00
Ryan Bates
3f4ee12025 add gem version badge (thanks Gemfury) 2012-12-11 16:58:20 -08:00
Ryan Bates
4dcd544594 Merge pull request #765 from jonsgreen/issue/cancan_inserting_and_null_687
Issue #687: cancan inserting "AND (NULL)" at the end of sql
2012-10-25 14:25:46 -07:00
jonathangreenberg
f5b3fcd8db Issue #687: cancan inserting "AND (NULL)" at the end of sql
Ensure that empty conditions does not trigger unmergeable conditions
2012-10-24 05:36:41 -04:00
Vasiliy Ermolovich
3b50fedd5d Merge pull request #708 from calebthompson/patch-1
Refold generated Ability comments at 80 characters
2012-10-15 11:09:33 -07:00
Vasiliy Ermolovich
d4be93bc83 add contributing guide
[ci skip]
2012-10-13 21:01:46 +03:00
Vasiliy Ermolovich
9a84277549 show build status fro master branch 2012-10-13 20:57:48 +03:00
Caleb Thompson
857dd075c5 Refold generated Ability comments at 80 characters
A lot of people still fold their code at 80 characters, so it is
nice to have generated code consider this.
2012-08-01 17:44:21 -03:00
Alberto Bajo
4a5700c07e Fixed load_resource "find_by" in mongoid resources
Latest versions of Mongoid supports "find_by" query, but syntax
is slightly different than Active Record.
2012-07-30 22:58:17 +02:00
Ryan Bates
b4285ae43c Merge pull request #676 from brynary/master
Add Code Climate badge
2012-07-03 10:48:55 -07:00
Ryan Bates
2db73e60c6 Merge pull request #670 from andhapp/fix-issue-664
Namespaced Controllers not building new resource from params(regression 1.6.8)
2012-07-02 13:47:15 -07:00
Ryan Bates
cad4db2d7b Merge pull request #660 from fl00r/master
Segmentation fault on aliasing
2012-07-02 13:36:44 -07:00
Ryan Bates
d20d90d2c2 Merge pull request #655 from DavidMikeSimon/master
Fix for issue #560
2012-07-02 13:27:21 -07:00
Bryan Helmkamp
8b993ee27d Add Code Climate badge 2012-07-02 14:32:04 -03:00
Nugroho Herucahyono
ce7d3fecdb porting #668 to 1.6.x 2012-07-02 13:05:19 +07:00
Anuj Dutta
60bc9e98a7 Add code for fixing issue #664 (regression in 1.6.8). 2012-06-29 18:53:16 +01:00
Ryan Bates
1e89b31bad releasing 1.6.8 2012-06-25 16:17:32 -07:00
fl00r
925274d29a Fixing Segmentation fault on aliasing 2012-06-23 18:25:13 +04:00
David Mike Simon
b162871c6d Spec to test against nested joins being thrown away ala issue 560 2012-06-19 16:58:15 -07:00
Ryan Bates
5f1be25419 preparing for 1.6.8 2012-06-19 12:56:51 -07:00
Ryan Bates
6d7bce78fc updating changelog 2012-06-19 11:58:59 -07:00
Ryan Bates
a0200166cc removing project status section from readme since contributors are now kind enough to keep tabs on the issue tracker 2012-06-19 11:37:45 -07:00
Ryan Bates
112a995327 clearing leftover whitespace 2012-06-19 11:36:59 -07:00
Ryan Bates
944804183e load ostruct for OpenStruct used in spec 2012-06-19 11:35:58 -07:00
Ryan Bates
2b89dbbdfa Merge pull request #653 from andhapp/fix-pull-request-640
Init attributes in InheritedResources controller w/ specs
2012-06-19 10:53:22 -07:00
Ryan Bates
aff8ca60e4 Merge pull request #650 from andhapp/fix-pull-request-486
Fixes Nested Resource Loading
2012-06-19 10:50:29 -07:00
Ryan Bates
33e33c584e Merge pull request #618 from spatil/master
Check for defined ActionController::Base instead ActionController
2012-06-19 10:41:14 -07:00
David Mike Simon
cfc355c006 Fix for issue 560 where joins could be thrown away by ActiveRecordAdapter::merge_joins 2012-06-18 19:40:48 -07:00
Anuj Dutta
a1254ca1c6 Fix pull request 640. For some reason github didn't allow a clean merge althought there weren't any conflicts. Fix it so that it's easier to just merge via the UI. 2012-06-19 00:13:19 +01:00
Mike Pack
88aba4664a Refactor out attribute assignment 2012-06-19 00:08:27 +01:00
Mike Pack
b965f5bab4 Add specs for resource attributes.
Remove inconsistent line breaks.
2012-06-19 00:08:27 +01:00
mccraig mccraig of the clan mccraig
c2c0b86c3a initialise attributes after a resource is created by an InheritedResources controller 2012-06-19 00:08:26 +01:00
Mark Sim
d5baed6281 Fixes Nested Resource Loading 2012-06-18 06:52:32 +01:00
Ryan Bates
7bf683d8f4 Merge pull request #645 from andhapp/issue-644
Allow users to specify a mix of can and cannot rule for mongoid
2012-06-11 09:52:38 -07:00
Anuj Dutta
da663aaed1 Fix for issue-644 to allow users to specify a mix of can and cannot rules with mongo. 2012-06-10 22:54:45 +01:00
Ryan Bates
80a8c39a93 Merge pull request #632 from andhapp/fix-issue-327
Fix to handle MetaWhere and non-MetaWhere conditions correctly.
2012-05-29 10:04:18 -07:00
Ryan Bates
b3f9ffe93b Merge pull request #625 from rogercampos/merging
Adding Ability#merge
2012-05-28 11:02:51 -07:00
Anuj Dutta
c27ead5b9f Fix to handle MetaWhere and non-MetaWhere conditions correctly. 2012-05-26 18:00:50 +01:00
Ryan Bates
0c21831b4d Merge pull request #619 from derekprior/namespace-fix
Updated: port fix for namespaced params from 2.0 back to 1.6
2012-05-14 09:24:25 -07:00
Chris Gunther
b347c7b78c port fix for namespaced params from 2.0 back to 1.6 2012-05-14 10:52:29 -04:00
Ryan Bates
1cdd7b3c18 Merge pull request #509 from moffff/master
Fix 'spec/spec_helper.rb:20: uninitialized constant WithModel (NameError)'
2012-05-11 08:59:41 -07:00
Ryan Bates
7f4f469e58 Merge pull request #492 from soopa/master
Fix "uninitialized constant CanCan::Rule::ModelAdapters"
2012-05-11 08:51:50 -07:00
Gimi Liang
14e1f5cad4 Merge pull request #535 from manuelmeurer/patch-2
Fixed a small typo
2012-05-11 08:17:55 -07:00
Gimi Liang
8e46ccad8c Merge pull request #616 from NickClark/rails_2_3_readme_clarification
Clarify readme for rails 2.3 users
2012-05-11 08:12:22 -07:00
Nicholas Clark
0bbe2e1802 Clarify readme for rails 2.3 users 2012-05-10 19:03:51 -04:00
Ryan Bates
10cbfbb923 adding a .rbenv-version file 2012-05-10 14:24:13 -07:00
Ryan Bates
a8a85f13a3 Merge pull request #541 from icrowley/master
Fixed bug with params for actions that build new instances with namespaced models
2012-05-10 13:51:45 -07:00
Ryan Bates
c1f7181336 Merge pull request #505 from nertzy/update_with_model
Use latest with_model gem
2012-05-10 11:45:27 -07:00
Ryan Bates
70515de8c1 Merge pull request #556 from mauriciozaffari/master
Pass forward :if and :unless options to the before filter.
2012-05-10 11:00:32 -07:00
Ryan Bates
b73bd062a8 Merge pull request #564 from flop/master
False positives on multiple nested abilities definitions
2012-05-10 10:59:08 -07:00
Ryan Bates
d1176245e6 Merge pull request #559 from plentz/patch-1
Adding travis-ci badge
2012-05-10 10:47:13 -07:00
Ryan Bates
78e1a17258 Merge pull request #587 from route/patch-1
Just add singleton to description of authorize_resource
2012-05-10 09:27:03 -07:00
Ryan Bates
6e8bc851be Merge pull request #607 from Mixbook/master
Added support for value to be Enumerable
2012-05-10 09:25:59 -07:00
Aryk Grosz
65bbf0e354 Add check for Enumerable as condition value 2012-04-23 00:51:55 -07:00
Ryan Bates
aed37cda03 adding project status message to readme 2012-04-17 14:00:30 -07:00
Shailesh Patil
51702e0f7b checked for ActionContoller::Base instead of just ActionContoller 2012-04-03 15:44:41 +05:30
Dmitriy Vorotilin
f166b5945a Just add singleton to description of authorize_resource 2012-03-23 01:34:04 +04:00
Florent Piteau
ba01349eb0 Don't remove key-value from the subject hash we might want to use it again. 2012-02-29 15:49:19 +01:00
Diego Plentz
37a42e3666 adding travis-ci badge 2012-02-14 23:41:18 -02:00
Mauricio Zaffari
83e2dcebd0 Pass forward :if and :unless options to the before filter. i.e:
load_and_authorize_resource :if => condition == true
2012-02-02 21:06:38 -02:00
Dmitry Afanasyev
baadcb923b Fixed bug with params for actions that build new instances with namespaced models 2012-01-06 01:21:11 +04:00
Manuel Meurer
e65f9bd4fd Fixed typo 2011-12-25 19:55:35 +01:00
Artem Kornienko
f18f53c9ce Fixed problem with 'with_model' gem in DataMapper tests and Mongoid tests. 2011-11-09 18:38:19 +02:00
Grant Hutchins
98312940e4 Use latest with_model gem
Now with_model clears the association class cache
between specs, which fixes a test pollution
problem.
2011-11-02 22:37:37 -04:00
Roger Campos
7797b37c7e Adding Ability#merge 2011-10-31 14:08:50 +01:00
soopa
80ceaf8e17 fix uninitialized constant warning in CanCan::Rule#model_adapter 2011-10-14 20:06:43 -05:00
Ryan Bates
9eebeb2155 releasing 1.6.7 with nested resource fix 2011-10-04 15:04:28 -07:00
Ryan Bates
67a3038628 quick fix to get nested resources working again - closes #482 2011-10-04 15:02:59 -07:00
Ryan Bates
26b40f2b49 releasing version 1.6.6 2011-09-28 17:00:32 -07:00
Ryan Bates
98326394f0 removing jruby/rubinius from travis.yml for now until I figure out why they aren't passing 2011-09-28 16:24:03 -07:00
Patrick Morgan
b3fc5add34 Correct "return cant jump across threads" error when using check_authorization() 2011-09-28 16:05:38 -07:00
Ryan Bates
610d7e3ec4 Merge pull request #425 from skhisma/master
Allow custom IDs to be specified when calling load_resource
2011-09-28 13:44:19 -07:00
Ryan Bates
cfb801ed8d Merge pull request #424 from whilefalse/master
Support for namespaced models and engines
2011-09-28 13:34:30 -07:00
Ryan Bates
0edd310c41 Merge pull request #476 from kirkconnell/with_model-version-fix
Specs fail when running in a freshly installed environment.
2011-09-28 11:57:17 -07:00
kirkconnell
5ab7dea2f0 use version 1.x of with_model to avoid errors in class comparisons 2011-09-20 18:43:39 -06:00
Ryan Bates
916f97fbf3 updating Rails gem dev dependency 2011-07-23 19:53:18 -07:00
Ryan Bates
2be3f98e11 removing 1.9.2 from .travis.yml 2011-07-23 19:33:43 -07:00
Ryan Bates
0343f8f0b5 Merge pull request #427 from bai/master
Add .travis.yml for building cancan on a lovely Travis CI service
2011-07-23 19:31:45 -07:00
Ryan Bates
987dce0dc2 Merge pull request #421 from amc-projects/master
Compatibility fix for rspec-instafail and rspec1
2011-07-23 14:46:37 -07:00
Ryan Bates
e0492f5d75 Merge pull request #426 from manuelmeurer/patch-1
Fixed documentation for skip_load_resource and skip_authorize_resource.
2011-07-23 13:31:03 -07:00
beawesomeinstead
0fc67e4d56 These lines are defaults, should be fine this way 2011-07-21 17:02:12 +03:00
beawesomeinstead
d24ef454e0 Run rake instead of rake test 2011-07-21 15:48:20 +03:00
Manuel Meurer
e561532bab Fixed typos. 2011-07-21 05:12:09 -07:00
beawesomeinstead
1ab4e2d48c The first try to make cancan pass on Travis CI 2011-07-21 14:51:47 +03:00
Geoff Parsons
7937a282a3 :id_param option to load_resource allows specification of the param name to find members 2011-07-20 13:42:24 -04:00
Steven Anderson
d35419fa4c Added the needed camelize to recent patch for engines and namespaced models 2011-07-20 10:03:50 +01:00
Steven Anderson
6c497b8dd9 Added support for engines and namespaced models. 2011-07-20 09:31:53 +01:00
Michael MacDonald
3b33b36de9 Compatibility fix for using cancan with rspec-instafail and rspec1 2011-07-19 10:27:08 +10:00
Ryan Bates
600a3e16a5 Merge pull request #410 from psanford/improve_datamapper_loading
Load datamapper class methods via append_extensions.
2011-07-01 13:01:32 -07:00
psanford
ccd7a94d40 Load datamapper class methods via append_extensions.
This relaxes the previous requirement that cancan has to be loaded
before any models are. append_extensions will apply to all
previously loaded models as well as ones loaded after.
2011-07-01 12:48:20 -07:00
Ryan Bates
8f815c422a Merge pull request #409 from nhocki/patch-1
Make CanCan Default Message a translatable text.
2011-07-01 11:44:23 -07:00
Nicolás Hock Isaza
1c3e61725f Change the i18n default name to :"unauthorized.default" 2011-07-01 13:10:20 -05:00
Nicolás Hock Isaza
71f60bc4ac Adding tests for i18n translation for default messages 2011-06-30 18:16:47 -05:00
Nicolás Hock Isaza
596ad235a9 Make CanCan Default Message a translatable text. Default to the one you had. 2011-06-30 13:22:49 -07:00
Ryan Bates
613ab1c1ab delegating ControllerResource find to model adapter, uses 'get' for DataMapper - closes #373 2011-05-21 13:57:17 -07:00
Ryan Bates
c031f82dd2 allow :find_by option to be full find method name - closes #335 2011-05-19 23:37:36 -04:00
29 changed files with 621 additions and 75 deletions

1
.rbenv-version Normal file
View File

@ -0,0 +1 @@
1.8.7-p357

7
.travis.yml Normal file
View File

@ -0,0 +1,7 @@
rvm:
- 1.8.7
- ree
notifications:
recipients:
- graf.otodrakula@gmail.com
- ryan@railscasts.com

View File

@ -1,3 +1,71 @@
1.6.10 (May 7, 2013)
* fix matches_conditons_hash for string values on 1.8 (thanks rrosen)
* work around SQL injection vulnerability in older Rails versions (thanks steerio) - issue #800
* add support for nested join conditions (thanks yuszuv) - issue #806
* fix load_resource "find_by" in mongoid resources (thanks albertobajo) - issue #705
* fix namespace split behavior (thanks xinuc) - issue #668
1.6.9 (February 4, 2013)
* fix inserting AND (NULL) to end of SQL queries (thanks jonsgreen) - issue #687
* fix merge_joins for nested association hashes (thanks DavidMikeSimon) - issues #655, #560
* raise error on recursive alias_action (thanks fl00r) - issue #660
* fix namespace controllers not loading params (thanks andhapp) - issues #670, #664
1.6.8 (June 25, 2012)
* improved support for namespaced controllers and models
* pass :if and :unless options for load and authorize resource (thanks mauriciozaffari)
* Travis CI badge (thanks plentz)
* adding Ability#merge for combining multiple abilities (thanks rogercampos)
* support for multiple MetaWhere rules (thanks andhapp)
* various fixes for DataMapper, Mongoid, and Inherited Resource integration
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.7...1.6.8]
1.6.7 (October 4, 2011)
* fixing nested resource problem caused by namespace addition - issue #482
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.6...1.6.7]
1.6.6 (September 28, 2011)
* correct "return cant jump across threads" error when using check_authorization (thanks codeprimate) - issues #463, #469
* fixing tests in development by specifying with_model version (thanks kirkconnell) - issue #476
* added travis.yml file for TravisCI support (thanks bai) - issue #427
* better support for namespaced models (thanks whilefalse) - issues #424
* adding :id_param option to load_and_authorize_resource (thanks skhisma) - issue #425
* make default unauthorized message translatable text (thanks nhocki) - issue #409
* improving DataMapper behavior (thanks psanford, maxsum-corin) - issue #410, #373
* allow :find_by option to be full find method name - issue #335
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.5...1.6.6]
1.6.5 (May 18, 2011)
* pass action and subject through AccessDenied exception when :through isn't found - issue #366
@ -14,12 +82,15 @@
* improve scope merging - issue #328
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.4...1.6.5]
1.6.4 (March 29, 2011)
* Fixed mongoid 'or' error - see issue #322
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.3...1.6.4]
1.6.3 (March 25, 2011)
@ -27,11 +98,15 @@
* Return subject passed to authorize! - see issue #314
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.2...1.6.3]
1.6.2 (March 18, 2011)
* Fixed instance loading when :singleton option is used - see issue #310
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.1...1.6.2]
1.6.1 (March 15, 2011)
@ -41,6 +116,8 @@
* Reverted Inherited Resources "collection" override since it doesn't seem to be working - see issue #305
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.6.0...1.6.1]
1.6.0 (March 11, 2011)
@ -62,6 +139,8 @@
* Raise an exception when trying to make a Ability condition with both a hash of conditions and a block - see issue #269
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.5.1...1.6.0]
1.5.1 (January 20, 2011)
@ -69,6 +148,8 @@
* Improving Mongoid support for multiple can and cannot definitions (thanks stellard) - see issue #239
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.5.0...1.5.1]
1.5.0 (January 11, 2011)
@ -90,6 +171,8 @@
* Internal: added .rvmrc to auto-switch to 1.8.7 with gemset - see issue #231
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.4.1...1.5.0]
1.4.1 (November 12, 2010)
@ -103,6 +186,8 @@
* Fix odd behavior when "cache_classes = false" (thanks mphalliday) - see issue #174
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.4.0...1.4.1]
1.4.0 (October 5, 2010)
@ -142,11 +227,15 @@
* No longer calling block in +can+ definition when checking on class - see issue #116
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.4...1.4.0]
1.3.4 (August 31, 2010)
* Don't stop at +cannot+ with hash conditions when checking class (thanks tamoya) - see issue #131
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.3...1.3.4]
1.3.3 (August 20, 2010)
@ -154,16 +243,22 @@
* Pluralize nested associations for conditions in accessible_by (thanks mlooney) - see issue #123
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.2...1.3.3]
1.3.2 (August 7, 2010)
* Fixing slice error when passing in custom resource name - see issue #112
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.1...1.3.2]
1.3.1 (August 6, 2010)
* Fixing protected sanitize_sql error - see issue #111
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.3.0...1.3.1]
1.3.0 (August 6, 2010)
@ -191,6 +286,8 @@
* Supporting deeply nested aliases - see issue #98
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.2.0...1.3.0]
1.2.0 (July 16, 2010)
@ -206,11 +303,15 @@
* Adding joins clause to accessible_by when conditions are across associations
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.1.1...1.2.0]
1.1.1 (April 17, 2010)
* Fixing behavior in Rails 3 by properly initializing ResourceAuthorization
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.1...1.1.1]
1.1.0 (April 17, 2010)
@ -234,6 +335,8 @@
* Support additional arguments to can? which get passed to the block - see issue #48
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.2...1.1]
1.0.2 (Dec 30, 2009)
@ -243,6 +346,8 @@
* Adding custom message argument to unauthorized! method (thanks tjwallace) - see issue #18
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.1...1.0.2]
1.0.1 (Dec 14, 2009)
@ -250,6 +355,8 @@
* Don't fetch parent of nested resource if *_id parameter is missing so it works with shallow nested routes - see issue #14
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/1.0.0...1.0.1]
1.0.0 (Dec 13, 2009)
@ -265,6 +372,8 @@
* BACKWARDS INCOMPATIBLE: turning load and authorize resource methods into class methods which set up the before filter so they can accept additional arguments.
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.2.1...1.0.0]
0.2.1 (Nov 26, 2009)
@ -274,6 +383,8 @@
* support custom objects (usually symbols) in can definition - see issue #8
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.2.0...0.2.1]
0.2.0 (Nov 17, 2009)
@ -285,6 +396,8 @@
* BACKWARDS INCOMPATIBLE: use Ability#initialize instead of 'prepare' to set up abilities - see issue #4
* {see the full list of changes}[https://github.com/ryanb/cancan/compare/0.1.0...0.2.0]
0.1.0 (Nov 16, 2009)

11
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,11 @@
### Please read before contributing
1) If you have any questions about CanCan, search the [Wiki](https://github.com/ryanb/cancan/wiki) or use [Stack Overflow](http://stackoverflow.com/questions/tagged/cancan). Do not post questions here.
2) If you find a security bug, **DO NOT** submit an issue here. Please send an e-mail to [ryan@railscasts.com](mailto:ryan@railscasts.com) instead.
3) Do a small search on the issues tracker before submitting your issue to see if it was already reported / fixed. In case it was not, create your report including Rails and CanCan versions. If you are getting exceptions, please include the full backtrace.
That's it! The more information you give, the more easy it becomes for us to track it down and fix it. Ideal scenario would be adding the issue to CanCan test suite or to a sample application.
Thanks!

View File

@ -3,8 +3,8 @@ source "http://rubygems.org"
case ENV["MODEL_ADAPTER"]
when nil, "active_record"
gem "sqlite3"
gem "activerecord", :require => "active_record"
gem "with_model"
gem "activerecord", '~> 3.0.9', :require => "active_record"
gem "with_model", "~> 0.2.5"
gem "meta_where"
when "data_mapper"
gem "dm-core", "~> 1.0.2"

View File

@ -1,4 +1,4 @@
= CanCan
= CanCan {<img src="https://fury-badge.herokuapp.com/rb/cancan.png" alt="Gem Version" />}[http://badge.fury.io/rb/cancan] {<img src="https://secure.travis-ci.org/ryanb/cancan.png?branch=master" />}[http://travis-ci.org/ryanb/cancan] {<img src="https://codeclimate.com/badge.png" />}[https://codeclimate.com/github/ryanb/cancan]
Wiki[https://github.com/ryanb/cancan/wiki] | RDocs[http://rdoc.info/projects/ryanb/cancan] | Screencast[http://railscasts.com/episodes/192-authorization-with-cancan]
@ -31,6 +31,15 @@ User permissions are defined in an +Ability+ class. CanCan 1.5 includes a Rails
rails g cancan:ability
In Rails 2.3, just add a new class in `app/models/ability.rb` with the folowing contents:
class Ability
include CanCan::Ability
def initialize(user)
end
end
See {Defining Abilities}[https://github.com/ryanb/cancan/wiki/defining-abilities] for details.

View File

@ -1,6 +1,6 @@
Gem::Specification.new do |s|
s.name = "cancan"
s.version = "1.6.5"
s.version = "1.6.10"
s.author = "Ryan Bates"
s.email = "ryan@railscasts.com"
s.homepage = "http://github.com/ryanb/cancan"
@ -10,8 +10,8 @@ Gem::Specification.new do |s|
s.files = Dir["{lib,spec}/**/*", "[A-Z]*", "init.rb"] - ["Gemfile.lock"]
s.require_path = "lib"
s.add_development_dependency 'rspec', '~> 2.1.0'
s.add_development_dependency 'rails', '~> 3.0.0'
s.add_development_dependency 'rspec', '~> 2.6.0'
s.add_development_dependency 'rails', '~> 3.0.9'
s.add_development_dependency 'rr', '~> 0.10.11' # 1.0.0 has respond_to? issues: http://github.com/btakita/rr/issues/issue/43
s.add_development_dependency 'supermodel', '~> 0.1.4'

View File

@ -172,10 +172,16 @@ module CanCan
# This way one can use params[:action] in the controller to determine the permission.
def alias_action(*args)
target = args.pop[:to]
validate_target(target)
aliased_actions[target] ||= []
aliased_actions[target] += args
end
# User shouldn't specify targets with names of real actions or it will cause Seg fault
def validate_target(target)
raise Error, "You can't specify target (#{target}) as alias because it is real action name" if aliased_actions.values.flatten.include? target
end
# Returns a hash of aliased actions. The key is the target and the value is an array of actions aliasing the key.
def aliased_actions
@aliased_actions ||= default_alias_actions
@ -228,6 +234,13 @@ module CanCan
relevant_rules(action, subject).any?(&:only_raw_sql?)
end
def merge(ability)
ability.send(:rules).each do |rule|
rules << rule.dup
end
self
end
private
def unauthorized_message_keys(action, subject)

View File

@ -94,7 +94,12 @@ module CanCan
# [:+find_by+]
# Find using a different attribute other than id. For example.
#
# load_resource :find_by => :permalink # will use find_by_permlink!(params[:id])
# load_resource :find_by => :permalink # will use find_by_permalink!(params[:id])
#
# [:+id_param+]
# Find using a param key other than :id. For example:
#
# load_resource :id_key => :url # will use find(params[:url])
#
# [:+collection+]
# Specify which actions are resource collection actions in addition to :+index+. This
@ -151,6 +156,9 @@ module CanCan
# [:+except+]
# Does not apply before filter to given actions.
#
# [:+singleton+]
# Pass +true+ if this is a singleton resource through a +has_one+ association.
#
# [:+parent+]
# True or false depending on if the resource is considered a parent resource. This defaults to +true+ if a resource
# name is given which does not match the controller.
@ -186,7 +194,7 @@ module CanCan
skip_authorize_resource(*args)
end
# Skip both the loading behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
# Skip the loading behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
# only do authorization on certain actions. You can pass :only and :except options to specify which actions to
# skip the effects on. It will apply to all actions by default.
#
@ -202,7 +210,7 @@ module CanCan
cancan_skipper[:load][name] = options
end
# Skip both the authorization behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
# Skip the authorization behavior of CanCan. This is useful when using +load_and_authorize_resource+ but want to
# only do loading on certain actions. You can pass :only and :except options to specify which actions to
# skip the effects on. It will apply to all actions by default.
#
@ -247,9 +255,9 @@ module CanCan
#
def check_authorization(options = {})
self.after_filter(options.slice(:only, :except)) do |controller|
return if controller.instance_variable_defined?(:@_authorized)
return if options[:if] && !controller.send(options[:if])
return if options[:unless] && controller.send(options[:unless])
next if controller.instance_variable_defined?(:@_authorized)
next if options[:if] && !controller.send(options[:if])
next if options[:unless] && controller.send(options[:unless])
raise AuthorizationNotPerformed, "This action failed the check_authorization because it does not authorize_resource. Add skip_authorization_check to bypass this check."
end
end
@ -382,7 +390,7 @@ module CanCan
end
end
if defined? ActionController
if defined? ActionController::Base
ActionController::Base.class_eval do
include CanCan::ControllerAdditions
end

View File

@ -6,8 +6,8 @@ module CanCan
options = args.extract_options!
resource_name = args.first
before_filter_method = options.delete(:prepend) ? :prepend_before_filter : :before_filter
controller_class.send(before_filter_method, options.slice(:only, :except)) do |controller|
controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except)).send(method)
controller_class.send(before_filter_method, options.slice(:only, :except, :if, :unless)) do |controller|
controller.class.cancan_resource_class.new(controller, resource_name, options.except(:only, :except, :if, :unless)).send(method)
end
end
@ -24,6 +24,10 @@ module CanCan
def load_and_authorize_resource
load_resource
authorize_resource
if update_actions.include?(@params[:action].to_sym)
update_resource
authorize_resource # Reauthorize the now-updated resource
end
end
def load_resource
@ -82,7 +86,15 @@ module CanCan
end
def build_resource
resource = resource_base.new(@params[name] || {})
resource = resource_base.new(resource_params || {})
assign_attributes(resource)
end
def update_resource
resource.assign_attributes(resource_params || {})
end
def assign_attributes(resource)
resource.send("#{parent_name}=", parent_resource) if @options[:singleton] && parent_resource
initial_attributes.each do |attr_name, value|
resource.send("#{attr_name}=", value)
@ -92,7 +104,7 @@ module CanCan
def initial_attributes
current_ability.attributes_for(@params[:action].to_sym, resource_class).delete_if do |key, value|
@params[name] && @params[name].include?(key)
resource_params && resource_params.include?(key)
end
end
@ -100,20 +112,38 @@ module CanCan
if @options[:singleton] && parent_resource.respond_to?(name)
parent_resource.send(name)
else
@options[:find_by] ? resource_base.send("find_by_#{@options[:find_by]}!", id_param) : resource_base.find(id_param)
if @options[:find_by]
if resource_base.respond_to? "find_by_#{@options[:find_by]}!"
resource_base.send("find_by_#{@options[:find_by]}!", id_param)
elsif resource_base.respond_to? "find_by"
resource_base.send("find_by", { @options[:find_by].to_sym => id_param })
else
resource_base.send(@options[:find_by], id_param)
end
else
adapter.find(resource_base, id_param)
end
end
end
def adapter
ModelAdapters::AbstractAdapter.adapter_class(resource_class)
end
def authorization_action
parent? ? :show : @params[:action].to_sym
end
def id_param
@params[parent? ? :"#{name}_id" : :id]
if @options[:id_param]
@params[@options[:id_param]]
else
@params[parent? ? :"#{name}_id" : :id]
end.to_s
end
def member_action?
new_actions.include?(@params[:action].to_sym) || @options[:singleton] || (@params[:id] && !collection_actions.include?(@params[:action].to_sym))
new_actions.include?(@params[:action].to_sym) || @options[:singleton] || ( (@params[:id] || @params[@options[:id_param]]) && !collection_actions.include?(@params[:action].to_sym))
end
# Returns the class used for this resource. This can be overriden by the :class option.
@ -122,7 +152,7 @@ module CanCan
def resource_class
case @options[:class]
when false then name.to_sym
when nil then name.to_s.camelize.constantize
when nil then namespaced_name.to_s.camelize.constantize
when String then @options[:class].constantize
else @options[:class]
end
@ -191,6 +221,29 @@ module CanCan
@name || name_from_controller
end
def resource_params
if @options[:class]
params_key = extract_key(@options[:class])
return @params[params_key] if @params[params_key]
end
resource_params_by_namespaced_name
end
def resource_params_by_namespaced_name
@params[extract_key(namespaced_name)]
end
def namespace
@params[:controller].split(/::|\//)[0..-2]
end
def namespaced_name
[namespace, name.camelize].join('::').singularize.camelize.constantize
rescue NameError
name
end
def name_from_controller
@params[:controller].sub("Controller", "").underscore.split('/').last.singularize
end
@ -206,5 +259,15 @@ module CanCan
def new_actions
[:new, :create] + [@options[:new]].flatten
end
def update_actions
[:update] #TODO: check what @options is for
end
private
def extract_key(value)
value.to_s.underscore.gsub('/', '_')
end
end
end

View File

@ -40,7 +40,7 @@ module CanCan
@message = message
@action = action
@subject = subject
@default_message = "You are not authorized to access this page."
@default_message = I18n.t(:"unauthorized.default", :default => "You are not authorized to access this page.")
end
def to_s

View File

@ -6,7 +6,8 @@ module CanCan
@controller.send :association_chain
@controller.instance_variable_get("@#{instance_name}")
elsif new_actions.include? @params[:action].to_sym
@controller.send :build_resource
resource = @controller.send :build_resource
assign_attributes(resource)
else
@controller.send :resource
end

View File

@ -1,5 +1,5 @@
RSpec = Spec unless defined? RSpec # for RSpec 1 compatability
RSpec::Matchers.define :be_able_to do |*args|
rspec_module = defined?(RSpec::Core) ? 'RSpec' : 'Spec' # for RSpec 1 compatability
Kernel.const_get(rspec_module)::Matchers.define :be_able_to do |*args|
match do |ability|
ability.can?(*args)
end

View File

@ -15,6 +15,11 @@ module CanCan
false # override in subclass
end
# Override if you need custom find behavior
def self.find(model_class, id)
model_class.find(id)
end
# Used to determine if this model adapter will override the matching behavior for a hash of conditions.
# If this returns true then matches_conditions_hash? will be called. See Rule#matches_conditions_hash
def self.override_conditions_hash_matching?(subject, conditions)

View File

@ -66,11 +66,22 @@ module CanCan
return conditions unless conditions.kind_of? Hash
conditions.inject({}) do |result_hash, (name, value)|
if value.kind_of? Hash
value = value.dup
association_class = model_class.reflect_on_association(name).class_name.constantize
name = model_class.reflect_on_association(name).table_name.to_sym
value = tableized_conditions(value, association_class)
nested = value.inject({}) do |nested,(k,v)|
if v.kind_of? Hash
value.delete(k)
nested[k] = v
else
name = model_class.reflect_on_association(name).table_name.to_sym
result_hash[name] = value
end
nested
end
result_hash.merge!(tableized_conditions(nested,association_class))
else
result_hash[name] = value
end
result_hash[name] = value
result_hash
end
end
@ -89,7 +100,12 @@ module CanCan
if override_scope
@model_class.scoped.merge(override_scope)
elsif @model_class.respond_to?(:where) && @model_class.respond_to?(:joins)
@model_class.where(conditions).joins(joins)
mergeable_conditions = @rules.select {|rule| rule.unmergeable? }.blank?
if mergeable_conditions
@model_class.where(conditions).joins(joins)
else
@model_class.where(*(@rules.map(&:conditions))).joins(joins)
end
else
@model_class.scoped(:conditions => conditions, :joins => joins)
end
@ -140,8 +156,8 @@ module CanCan
# Takes two hashes and does a deep merge.
def merge_joins(base, add)
add.each do |name, nested|
if base[name].is_a?(Hash) && !nested.empty?
merge_joins(base[name], nested)
if base[name].is_a?(Hash)
merge_joins(base[name], nested) unless nested.empty?
else
base[name] = nested
end

View File

@ -5,6 +5,10 @@ module CanCan
model_class <= DataMapper::Resource
end
def self.find(model_class, id)
model_class.get(id)
end
def self.override_conditions_hash_matching?(subject, conditions)
conditions.any? { |k,v| !k.kind_of?(Symbol) }
end
@ -27,6 +31,4 @@ module CanCan
end # module ModelAdapters
end # module CanCan
DataMapper::Model.class_eval do
include CanCan::ModelAdditions::ClassMethods
end
DataMapper::Model.append_extensions(CanCan::ModelAdditions::ClassMethods)

View File

@ -30,8 +30,9 @@ module CanCan
else
# we only need to process can rules if
# there are no rules with empty conditions
rules = @rules.reject { |rule| rule.conditions.empty? }
rules = @rules.reject { |rule| rule.conditions.empty? && rule.base_behavior }
process_can_rules = @rules.count == rules.count
rules.inject(@model_class.all) do |records, rule|
if process_can_rules && rule.base_behavior
records.or rule.conditions

View File

@ -54,6 +54,11 @@ module CanCan
@conditions == {} || @conditions.nil?
end
def unmergeable?
@conditions.respond_to?(:keys) && @conditions.present? &&
(!@conditions.keys.first.kind_of? Symbol)
end
def associations_hash(conditions = @conditions)
hash = {}
conditions.map do |name, value|
@ -111,7 +116,7 @@ module CanCan
else
!attribute.nil? && matches_conditions_hash?(attribute, value)
end
elsif value.kind_of?(Array) || value.kind_of?(Range)
elsif !value.is_a?(String) && value.kind_of?(Enumerable)
value.include? attribute
else
attribute == value
@ -123,7 +128,7 @@ module CanCan
end
def nested_subject_matches_conditions?(subject_hash)
parent, child = subject_hash.shift
parent, child = subject_hash.first
matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
end
@ -136,7 +141,7 @@ module CanCan
end
def model_adapter(subject)
ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
CanCan::ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
end
end
end

View File

@ -11,18 +11,22 @@ class Ability
# can :read, :all
# end
#
# The first argument to `can` is the action you are giving the user permission to do.
# If you pass :manage it will apply to every action. Other common actions here are
# :read, :create, :update and :destroy.
# The first argument to `can` is the action you are giving the user
# permission to do.
# If you pass :manage it will apply to every action. Other common actions
# here are :read, :create, :update and :destroy.
#
# The second argument is the resource the user can perform the action on. If you pass
# :all it will apply to every resource. Otherwise pass a Ruby class of the resource.
# The second argument is the resource the user can perform the action on.
# If you pass :all it will apply to every resource. Otherwise pass a Ruby
# class of the resource.
#
# The third argument is an optional hash of conditions to further filter the objects.
# The third argument is an optional hash of conditions to further filter the
# objects.
# For example, here the user can only update published articles.
#
# can :update, Article, :published => true
#
# See the wiki for details: https://github.com/ryanb/cancan/wiki/Defining-Abilities
# See the wiki for details:
# https://github.com/ryanb/cancan/wiki/Defining-Abilities
end
end

View File

@ -87,6 +87,10 @@ describe CanCan::Ability do
@ability.can?(:increment, 123).should be_true
end
it "should raise an Error if alias target is an exist action" do
lambda{ @ability.alias_action :show, :to => :show }.should raise_error(CanCan::Error, "You can't specify target (show) as alias because it is real action name")
end
it "should always call block with arguments when passing no arguments to can" do
@ability.can do |action, object_class, object|
action.should == :foo
@ -249,7 +253,15 @@ describe CanCan::Ability do
@ability.can?(:read, 1..5).should be_true
@ability.can?(:read, 4..6).should be_false
end
it "should accept a set as a condition value" do
mock(object_with_foo_2 = Object.new).foo { 2 }
mock(object_with_foo_3 = Object.new).foo { 3 }
@ability.can :read, Object, :foo => [1, 2, 5].to_set
@ability.can?(:read, object_with_foo_2).should be_true
@ability.can?(:read, object_with_foo_3).should be_false
end
it "should not match subjects return nil for methods that must match nested a nested conditions hash" do
mock(object_with_foo = Object.new).foo { :bar }
@ability.can :read, Array, :first => { :foo => :bar }
@ -257,6 +269,12 @@ describe CanCan::Ability do
@ability.can?(:read, []).should be_false
end
it "should match strings but not substrings specified in a conditions hash" do
@ability.can :read, String, :presence => "declassified"
@ability.can?(:read, "declassified").should be_true
@ability.can?(:read, "classified").should be_false
end
it "should not stop at cannot definition when comparing class" do
@ability.can :read, Range
@ability.cannot :read, Range, :begin => 1
@ -297,7 +315,15 @@ describe CanCan::Ability do
@ability.can?(:read, "foobar" => Range).should be_false
@ability.can?(:read, 123 => Range).should be_true
end
it "passing a hash of subjects with multiple definitions should check permissions correctly" do
@ability.can :read, Range, :string => {:length => 4}
@ability.can [:create, :read], Range, :string => {:upcase => 'FOO'}
@ability.can?(:read, "foo" => Range).should be_true
@ability.can?(:read, "foobar" => Range).should be_false
@ability.can?(:read, 1234 => Range).should be_true
end
it "should allow to check ability on Hash-like object" do
class Container < Hash; end
@ability.can :read, Container
@ -416,4 +442,17 @@ describe CanCan::Ability do
@ability.unauthorized_message(:edit, 1..3).should == "edit range"
end
end
describe "#merge" do
it "should add the rules from the given ability" do
@ability.can :use, :tools
another_ability = Object.new
another_ability.extend(CanCan::Ability)
another_ability.can :use, :search
@ability.merge(another_ability)
@ability.can?(:use, :search).should be_true
@ability.send(:rules).size.should == 2
end
end
end

View File

@ -49,14 +49,14 @@ describe CanCan::ControllerAdditions do
it "authorize_resource should setup a before filter which passes call to ControllerResource" do
stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.authorize_resource
mock(@controller_class).before_filter(:except => :show) { |options, block| block.call(@controller) }
@controller_class.authorize_resource :foo => :bar, :except => :show
mock(@controller_class).before_filter(:except => :show, :if => true) { |options, block| block.call(@controller) }
@controller_class.authorize_resource :foo => :bar, :except => :show, :if => true
end
it "load_resource should setup a before filter which passes call to ControllerResource" do
stub(CanCan::ControllerResource).new(@controller, nil, :foo => :bar).mock!.load_resource
mock(@controller_class).before_filter(:only => [:show, :index]) { |options, block| block.call(@controller) }
@controller_class.load_resource :foo => :bar, :only => [:show, :index]
mock(@controller_class).before_filter(:only => [:show, :index], :unless => false) { |options, block| block.call(@controller) }
@controller_class.load_resource :foo => :bar, :only => [:show, :index], :unless => false
end
it "skip_authorization_check should set up a before filter which sets @_authorized to true" do

View File

@ -20,7 +20,7 @@ describe CanCan::ControllerResource do
end
it "should not load resource into an instance variable if already set" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
@controller.instance_variable_set(:@project, :some_project)
resource = CanCan::ControllerResource.new(@controller)
resource.load_resource
@ -35,6 +35,30 @@ describe CanCan::ControllerResource do
@controller.instance_variable_get(:@project).should == project
end
it "should attempt to load a resource with the same namespace as the controller when using :: for namespace" do
module MyEngine
class Project < ::Project; end
end
project = MyEngine::Project.create!
@params.merge!(:controller => "MyEngine::ProjectsController", :action => "show", :id => project.id)
resource = CanCan::ControllerResource.new(@controller)
resource.load_resource
@controller.instance_variable_get(:@project).should == project
end
# Rails includes namespace in params, see issue #349
it "should create through the namespaced params" do
module MyEngine
class Project < ::Project; end
end
@params.merge!(:controller => "MyEngine::ProjectsController", :action => "create", :my_engine_project => {:name => "foobar"})
resource = CanCan::ControllerResource.new(@controller)
resource.load_resource
@controller.instance_variable_get(:@project).name.should == "foobar"
end
it "should properly load resource for namespaced controller when using '::' for namespace" do
project = Project.create!
@params.merge!(:controller => "Admin::ProjectsController", :action => "show", :id => project.id)
@ -43,6 +67,16 @@ describe CanCan::ControllerResource do
@controller.instance_variable_get(:@project).should == project
end
it "has the specified nested resource_class when using / for namespace" do
module Admin
class Dashboard; end
end
@ability.can(:index, "admin/dashboard")
@params.merge!(:controller => "admin/dashboard", :action => "index")
resource = CanCan::ControllerResource.new(@controller, :authorize => true)
resource.send(:resource_class).should == Admin::Dashboard
end
it "should build a new resource with hash if params[:id] is not specified" do
@params.merge!(:action => "create", :project => {:name => "foobar"})
resource = CanCan::ControllerResource.new(@controller)
@ -50,6 +84,20 @@ describe CanCan::ControllerResource do
@controller.instance_variable_get(:@project).name.should == "foobar"
end
it "should build a new resource for namespaced model with hash if params[:id] is not specified" do
@params.merge!(:action => "create", 'sub_project' => {:name => "foobar"})
resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project)
resource.load_resource
@controller.instance_variable_get(:@project).name.should == "foobar"
end
it "should build a new resource for namespaced controller and namespaced model with hash if params[:id] is not specified" do
@params.merge!(:controller => "Admin::SubProjectsController", :action => "create", 'sub_project' => {:name => "foobar"})
resource = CanCan::ControllerResource.new(@controller, :class => Project)
resource.load_resource
@controller.instance_variable_get(:@sub_project).name.should == "foobar"
end
it "should build a new resource with attributes from current ability" do
@params.merge!(:action => "new")
@ability.can(:create, Project, :name => "from conditions")
@ -110,7 +158,7 @@ describe CanCan::ControllerResource do
end
it "should perform authorization using controller action and loaded model" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
@controller.instance_variable_set(:@project, :some_project)
stub(@controller).authorize!(:show, :some_project) { raise CanCan::AccessDenied }
resource = CanCan::ControllerResource.new(@controller)
@ -118,14 +166,14 @@ describe CanCan::ControllerResource do
end
it "should perform authorization using controller action and non loaded model" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
stub(@controller).authorize!(:show, Project) { raise CanCan::AccessDenied }
resource = CanCan::ControllerResource.new(@controller)
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
end
it "should call load_resource and authorize_resource for load_and_authorize_resource" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
resource = CanCan::ControllerResource.new(@controller)
mock(resource).load_resource
mock(resource).authorize_resource
@ -133,7 +181,7 @@ describe CanCan::ControllerResource do
end
it "should not build a single resource when on custom collection action even with id" do
@params.merge!(:action => "sort", :id => 123)
@params.merge!(:action => "sort", :id => "123")
resource = CanCan::ControllerResource.new(@controller, :collection => [:sort, :list])
resource.load_resource
@controller.instance_variable_get(:@project).should be_nil
@ -149,7 +197,7 @@ describe CanCan::ControllerResource do
end
it "should build a resource when on custom new action even when params[:id] exists" do
@params.merge!(:action => "build", :id => 123)
@params.merge!(:action => "build", :id => "123")
stub(Project).new { :some_project }
resource = CanCan::ControllerResource.new(@controller, :new => :build)
resource.load_resource
@ -183,39 +231,47 @@ describe CanCan::ControllerResource do
resource.should_not be_parent
end
it "should have the specified resource_class if 'name' is passed to load_resource" do
class Section
end
resource = CanCan::ControllerResource.new(@controller, :section)
resource.send(:resource_class).should == Section
end
it "should load parent resource through proper id parameter" do
project = Project.create!
@params.merge!(:action => "index", :project_id => project.id)
resource = CanCan::ControllerResource.new(@controller, :project, :parent => true)
@params.merge!(:controller => "categories", :action => "index", :project_id => project.id)
resource = CanCan::ControllerResource.new(@controller, :project)
resource.load_resource
@controller.instance_variable_get(:@project).should == project
end
it "should load resource through the association of another parent resource using instance variable" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
category = Object.new
@controller.instance_variable_set(:@category, category)
stub(category).projects.stub!.find(123) { :some_project }
stub(category).projects.stub!.find("123") { :some_project }
resource = CanCan::ControllerResource.new(@controller, :through => :category)
resource.load_resource
@controller.instance_variable_get(:@project).should == :some_project
end
it "should load resource through the custom association name" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
category = Object.new
@controller.instance_variable_set(:@category, category)
stub(category).custom_projects.stub!.find(123) { :some_project }
stub(category).custom_projects.stub!.find("123") { :some_project }
resource = CanCan::ControllerResource.new(@controller, :through => :category, :through_association => :custom_projects)
resource.load_resource
@controller.instance_variable_get(:@project).should == :some_project
end
it "should load resource through the association of another parent resource using method" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
category = Object.new
stub(@controller).category { category }
stub(category).projects.stub!.find(123) { :some_project }
stub(category).projects.stub!.find("123") { :some_project }
resource = CanCan::ControllerResource.new(@controller, :through => :category)
resource.load_resource
@controller.instance_variable_get(:@project).should == :some_project
@ -252,10 +308,10 @@ describe CanCan::ControllerResource do
end
it "should load through first matching if multiple are given" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
category = Object.new
@controller.instance_variable_set(:@category, category)
stub(category).projects.stub!.find(123) { :some_project }
stub(category).projects.stub!.find("123") { :some_project }
resource = CanCan::ControllerResource.new(@controller, :through => [:category, :user])
resource.load_resource
@controller.instance_variable_get(:@project).should == :some_project
@ -312,8 +368,16 @@ describe CanCan::ControllerResource do
@controller.instance_variable_get(:@project).should == project
end
it "should load the model using a custom namespaced class" do
project = Sub::Project.create!
@params.merge!(:action => "show", :id => project.id)
resource = CanCan::ControllerResource.new(@controller, :class => ::Sub::Project)
resource.load_resource
@controller.instance_variable_get(:@project).should == project
end
it "should authorize based on resource name if class is false" do
@params.merge!(:action => "show", :id => 123)
@params.merge!(:action => "show", :id => "123")
stub(@controller).authorize!(:show, :project) { raise CanCan::AccessDenied }
resource = CanCan::ControllerResource.new(@controller, :class => false)
lambda { resource.authorize_resource }.should raise_error(CanCan::AccessDenied)
@ -328,6 +392,21 @@ describe CanCan::ControllerResource do
@controller.instance_variable_get(:@custom_project).should == project
end
it "should load resource using custom ID param" do
project = Project.create!
@params.merge!(:action => "show", :the_project => project.id)
resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project)
resource.load_resource
@controller.instance_variable_get(:@project).should == project
end
# CVE-2012-5664
it "should always convert id param to string" do
@params.merge!(:action => "show", :the_project => { :malicious => "I am" })
resource = CanCan::ControllerResource.new(@controller, :id_param => :the_project)
resource.send(:id_param).class.should == String
end
it "should load resource using custom find_by attribute" do
project = Project.create!(:name => "foo")
@params.merge!(:action => "show", :id => "foo")
@ -336,6 +415,14 @@ describe CanCan::ControllerResource do
@controller.instance_variable_get(:@project).should == project
end
it "should allow full find method to be passed into find_by option" do
project = Project.create!(:name => "foo")
@params.merge!(:action => "show", :id => "foo")
resource = CanCan::ControllerResource.new(@controller, :find_by => :find_by_name)
resource.load_resource
@controller.instance_variable_get(:@project).should == project
end
it "should raise ImplementationRemoved when adding :name option" do
lambda {
CanCan::ControllerResource.new(@controller, :name => :foo)

View File

@ -32,4 +32,27 @@ describe CanCan::AccessDenied do
@exception.message.should == "Access denied!"
end
end
describe "i18n in the default message" do
after(:each) do
I18n.backend = nil
end
it "uses i18n for the default message" do
I18n.backend.store_translations :en, :unauthorized => {:default => "This is a different message"}
@exception = CanCan::AccessDenied.new
@exception.message.should == "This is a different message"
end
it "defaults to a nice message" do
@exception = CanCan::AccessDenied.new
@exception.message.should == "You are not authorized to access this page."
end
it "does not use translation if a message is given" do
@exception = CanCan::AccessDenied.new("Hey! You're not welcome here")
@exception.message.should == "Hey! You're not welcome here"
@exception.message.should_not == "You are not authorized to access this page."
end
end
end

View File

@ -39,4 +39,22 @@ describe CanCan::InheritedResource do
CanCan::InheritedResource.new(@controller).load_resource
@controller.instance_variable_get(:@projects).should == :projects
end
it "should build a new resource with attributes from current ability" do
@params[:action] = "new"
@ability.can(:create, Project, :name => "from conditions")
stub(@controller).build_resource { Struct.new(:name).new }
resource = CanCan::InheritedResource.new(@controller)
resource.load_resource
@controller.instance_variable_get(:@project).name.should == "from conditions"
end
it "should override initial attributes with params" do
@params.merge!(:action => "new", :project => {:name => "from params"})
@ability.can(:create, Project, :name => "from conditions")
stub(@controller).build_resource { Struct.new(:name).new }
resource = CanCan::ControllerResource.new(@controller)
resource.load_resource
@controller.instance_variable_get(:@project).name.should == "from params"
end
end

View File

@ -1,10 +1,6 @@
if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
require "spec_helper"
RSpec.configure do |config|
config.extend WithModel
end
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
describe CanCan::ModelAdapters::ActiveRecordAdapter do
@ -24,10 +20,12 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
t.boolean "secret"
t.integer "priority"
t.integer "category_id"
t.integer "user_id"
end
model do
belongs_to :category
has_many :comments
belongs_to :user
end
end
@ -41,6 +39,15 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
end
end
with_model :user do
table do |t|
end
model do
has_many :articles
end
end
before(:each) do
Article.delete_all
Comment.delete_all
@ -56,6 +63,11 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::ActiveRecordAdapter
end
it "should find record" do
article = Article.create!
CanCan::ModelAdapters::ActiveRecordAdapter.find(Article, article.id).should == article
end
it "should not fetch any records when no abilities are defined" do
Article.create!
Article.accessible_by(@ability).should be_empty
@ -132,7 +144,7 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
article1 = Article.create!(:secret => true, :category => category1)
article2 = Article.create!(:secret => true, :category => category2)
category1.articles.accessible_by(@ability).should == [article1]
end
end
it "should raise an exception when trying to merge scope with other conditions" do
@ability.can :read, Article, :published => true
@ -195,6 +207,16 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
@ability.model_adapter(Article, :read).conditions.should == "'t'='t'"
end
it "should return appropriate sql conditions in complex case with nested joins" do
@ability.can :read, Comment, :article => { :category => { :visible => true } }
@ability.model_adapter(Comment, :read).conditions.should == { Category.table_name.to_sym => { :visible => true } }
end
it "should return appropriate sql conditions in complex case with nested joins of different depth" do
@ability.can :read, Comment, :article => { :published => true, :category => { :visible => true } }
@ability.model_adapter(Comment, :read).conditions.should == { Article.table_name.to_sym => { :published => true }, Category.table_name.to_sym => { :visible => true } }
end
it "should not forget conditions when calling with SQL string" do
@ability.can :read, Article, :published => true
@ability.can :read, Article, ['secret=?', false]
@ -226,6 +248,21 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
@ability.model_adapter(Article, :read).joins.should == [:project]
end
it "should merge nested and non-nested joins" do
@ability.can :read, Article, :project => { :blocked => false }
@ability.can :read, Article, :project => { :comments => { :spam => true } }
@ability.model_adapter(Article, :read).joins.should == [{:project=>[:comments]}]
end
it "should merge :all conditions with other conditions" do
user = User.create!
article = Article.create!(:user => user)
ability = Ability.new(user)
ability.can :manage, :all
ability.can :manage, Article, :user_id => user.id
Article.accessible_by(ability).should == [article]
end
it "should restrict articles given a MetaWhere condition" do
@ability.can :read, Article, :priority.lt => 2
article1 = Article.create!(:priority => 1)
@ -235,6 +272,16 @@ if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
@ability.should_not be_able_to(:read, article2)
end
it "should merge MetaWhere and non-MetaWhere conditions" do
@ability.can :read, Article, :priority.lt => 2
@ability.can :read, Article, :priority => 1
article1 = Article.create!(:priority => 1)
article2 = Article.create!(:priority => 3)
Article.accessible_by(@ability).should == [article1]
@ability.should be_able_to(:read, article1)
@ability.should_not be_able_to(:read, article2)
end
it "should match any MetaWhere condition" do
adapter = CanCan::ModelAdapters::ActiveRecordAdapter
article1 = Article.new(:priority => 1, :name => "Hello World")

View File

@ -36,6 +36,11 @@ if ENV["MODEL_ADAPTER"] == "data_mapper"
CanCan::ModelAdapters::AbstractAdapter.adapter_class(Article).should == CanCan::ModelAdapters::DataMapperAdapter
end
it "should find record" do
article = Article.create
CanCan::ModelAdapters::DataMapperAdapter.find(Article, article.id).should == article
end
it "should not fetch any records when no abilities are defined" do
Article.create
Article.accessible_by(@ability).should be_empty

View File

@ -36,6 +36,11 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
CanCan::ModelAdapters::AbstractAdapter.adapter_class(MongoidProject).should == CanCan::ModelAdapters::MongoidAdapter
end
it "should find record" do
project = MongoidProject.create
CanCan::ModelAdapters::MongoidAdapter.find(MongoidProject, project.id).should == project
end
it "should compare properties on mongoid documents with the conditions hash" do
model = MongoidProject.new
@ability.can :read, MongoidProject, :id => model.id
@ -68,6 +73,17 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
MongoidProject.accessible_by(@ability, :read).entries.should == [sir]
end
it "should return the correct records when a mix of can and cannot rules in defined ability" do
@ability.can :manage, MongoidProject, :title => 'Sir'
@ability.cannot :destroy, MongoidProject
sir = MongoidProject.create(:title => 'Sir')
lord = MongoidProject.create(:title => 'Lord')
dude = MongoidProject.create(:title => 'Dude')
MongoidProject.accessible_by(@ability, :destroy).entries.should == [sir]
end
it "should be able to mix empty conditions and hashes" do
@ability.can :read, MongoidProject
@ability.can :read, MongoidProject, :title => 'Sir'
@ -180,7 +196,7 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
@ability.can :read, MongoidProject, :foo => {:bar => 1}
MongoidProject.accessible_by(@ability, :read).entries.first.should == obj
end
it "should exclude from the result if set to cannot" do
obj = MongoidProject.create(:bar => 1)
obj2 = MongoidProject.create(:bar => 2)
@ -197,7 +213,7 @@ if ENV["MODEL_ADAPTER"] == "mongoid"
@ability.can :read, MongoidProject, :bar => 2
MongoidProject.accessible_by(@ability, :read).entries.should =~ [obj, obj2]
end
it "should not allow to fetch records when ability with just block present" do
@ability.can :read, MongoidProject do
false

View File

@ -1,4 +1,5 @@
require "spec_helper"
require "ostruct" # for OpenStruct below
# Most of Rule functionality is tested in Ability specs
describe CanCan::Rule do
@ -36,4 +37,16 @@ describe CanCan::Rule do
rule = CanCan::Rule.new(true, :read, Integer, nil, nil)
rule.associations_hash.should == {}
end
it "should not be mergeable if conditions are not simple hashes" do
meta_where = OpenStruct.new(:name => 'metawhere', :column => 'test')
@conditions[meta_where] = :bar
@rule.should be_unmergeable
end
it "should be mergeable if conditions is an empty hash" do
@conditions = {}
@rule.should_not be_unmergeable
end
end

View File

@ -9,11 +9,27 @@ require 'matchers'
require 'cancan/matchers'
RSpec.configure do |config|
config.treat_symbols_as_metadata_keys_with_true_values = true
config.filter_run :focus => true
config.run_all_when_everything_filtered = true
config.mock_with :rr
config.before(:each) do
Project.delete_all
Category.delete_all
end
config.extend WithModel if ENV["MODEL_ADAPTER"].nil? || ENV["MODEL_ADAPTER"] == "active_record"
end
# Working around CVE-2012-5664 requires us to convert all ID params
# to strings. Let's switch to using string IDs in tests, otherwise
# SuperModel and/or RR will fail (as strings are not fixnums).
module SuperModel
class Base
def generate_id
object_id.to_s
end
end
end
class Ability
@ -27,7 +43,30 @@ class Category < SuperModel::Base
has_many :projects
end
module Sub
class Project < SuperModel::Base
belongs_to :category
attr_accessor :category # why doesn't SuperModel do this automatically?
def self.respond_to?(method, include_private = false)
if method.to_s == "find_by_name!" # hack to simulate ActiveRecord
true
else
super
end
end
end
end
class Project < SuperModel::Base
belongs_to :category
attr_accessor :category # why doesn't SuperModel do this automatically?
def self.respond_to?(method, include_private = false)
if method.to_s == "find_by_name!" # hack to simulate ActiveRecord
true
else
super
end
end
end