rails-canhaz 0.0.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README.md +74 -0
- data/Rakefile +8 -0
- data/lib/rails-canhaz/canhaz_permission.rb +27 -0
- data/lib/rails-canhaz/exceptions.rb +6 -0
- data/lib/rails-canhaz/extensions_all.rb +21 -0
- data/lib/rails-canhaz/extensions_object.rb +33 -0
- data/lib/rails-canhaz/extensions_subject.rb +71 -0
- data/lib/rails-canhaz/model_extensions.rb +30 -0
- data/lib/rails-canhaz.rb +6 -4
- data/rails-canhaz.gemspec +13 -0
- data/test/.gitkeep +0 -0
- data/test/init_tests.rb +6 -0
- data/test/models/foo_model.rb +5 -0
- data/test/models/object_model.rb +8 -0
- data/test/models/subject_model.rb +8 -0
- data/test/schema.rb +33 -0
- data/test/test_canhaz.rb +155 -0
- metadata +23 -4
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Rails-Canhaz
|
2
|
+
|
3
|
+
This gem is a simple activerecord extention that allows any application using activerecord to manage permissions based roles.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Standard gem installation :
|
8
|
+
|
9
|
+
```
|
10
|
+
gem install rails-canhaz
|
11
|
+
```
|
12
|
+
|
13
|
+
Or in your Gemfile if you use bundler
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
gem 'rails-canhaz'
|
17
|
+
```
|
18
|
+
|
19
|
+
You then need to create a single table in order to make this gem to work
|
20
|
+
|
21
|
+
Here is the schema of this table, if you're using ruby on rails, you should create a migration :
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
create_table :can_haz_permissions do |t|
|
25
|
+
t.integer :csubject_id
|
26
|
+
t.string :csubject_type
|
27
|
+
|
28
|
+
t.integer :cobject_id
|
29
|
+
t.string :cobject_type
|
30
|
+
|
31
|
+
t.string :permission_name
|
32
|
+
end
|
33
|
+
|
34
|
+
add_index :can_haz_permissions, :csubject_id, :name => 'subject_id_ix'
|
35
|
+
add_index :can_haz_permissions, :cobject_id, :name => 'object_id_ix'
|
36
|
+
```
|
37
|
+
|
38
|
+
## How to use it ?
|
39
|
+
|
40
|
+
The rails-canhaz gem defines two static functions for ActiveRecord models which allow them to act as a subject or an object.
|
41
|
+
|
42
|
+
A subject has roles on objects.
|
43
|
+
|
44
|
+
Here is an example
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
class User < ActiveRecord::Base
|
48
|
+
acts_as_canhaz_subject
|
49
|
+
end
|
50
|
+
|
51
|
+
class Article < ActiveRecord::Base
|
52
|
+
acts_as_canhaz_object
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
Now our models are marked as canhaz subjects and objects, we have access to some handy functions :
|
57
|
+
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
user = User.find(42)
|
61
|
+
article = Article.find(1337)
|
62
|
+
|
63
|
+
user.can?(:read, article) # Can the user read this article? false for now
|
64
|
+
|
65
|
+
user.can(:read, article) # Ok, so the user can read this article
|
66
|
+
|
67
|
+
user.can?(:read, article) # Will be true
|
68
|
+
|
69
|
+
user.objects_with_permission(Article, :read) # Will return all the articles w/ read permissions for this user
|
70
|
+
|
71
|
+
artice.subjects_with_permission(User, :read) # Will return all the users hat are able to read this article
|
72
|
+
```
|
73
|
+
|
74
|
+
More coming soon ...
|
data/Rakefile
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
class CanHazPermission < ActiveRecord::Base
|
4
|
+
|
5
|
+
validates :cobject_id, :uniqueness => {:scope => [:permission_name, :csubject_id]}
|
6
|
+
|
7
|
+
# Gets the permission row between two objects
|
8
|
+
#
|
9
|
+
# @param subject [ActiveRecord::Base] The subject
|
10
|
+
# @param object [ActiveRecord::Base] The object
|
11
|
+
# @param permission [String, Symbol] The permission identifier
|
12
|
+
# @return [CanHazPermission, nil] The corresponding permission if found or nil
|
13
|
+
def self.find_permission(subject, object, permission)
|
14
|
+
raise NotACanHazSubject unless subject.canhaz_subject?
|
15
|
+
raise NotACanHazObject unless object.canhaz_object?
|
16
|
+
|
17
|
+
results = CanHazPermission.where(
|
18
|
+
:csubject_id => subject.id,
|
19
|
+
:csubject_type => subject.class.to_s,
|
20
|
+
:cobject_id => object.id,
|
21
|
+
:cobject_type => object.class.to_s,
|
22
|
+
:permission_name => permission
|
23
|
+
)
|
24
|
+
results.first
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CanHaz
|
2
|
+
module ModelExtensions
|
3
|
+
module All
|
4
|
+
|
5
|
+
# Returns if a model is registered as a canhaz subject
|
6
|
+
#
|
7
|
+
# @return [Bool] Whether or not the model is a canhaz subject
|
8
|
+
def canhaz_subject?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
# Returns if a model is registered as a canhaz object
|
13
|
+
#
|
14
|
+
# @return [Bool] Whether or not the model is a canhaz object
|
15
|
+
def canhaz_object?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module CanHaz
|
2
|
+
module ModelExtensions
|
3
|
+
module Object
|
4
|
+
|
5
|
+
# Checks if the model is accessible by a given subject and a given permission
|
6
|
+
# This is a proxy to subject.can?(permission, subject)
|
7
|
+
#
|
8
|
+
# @param subject [ActiveRecord::Base] The subject we are testing
|
9
|
+
# @param permission [String, Symbol] The permission we want to test the subject on
|
10
|
+
# @return [Boolean] True if the subject has the permission on this object, false otherwise
|
11
|
+
def accessible_by?(subject, permission)
|
12
|
+
subject.can?(permission, self)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Gets the subjects that have the corresponding permission and type on this model
|
16
|
+
#
|
17
|
+
# @param type [Class] The type of the subjects we're looking for
|
18
|
+
# @param permission [String, Symbol] The permission
|
19
|
+
def subjects_with_permission(type, permission)
|
20
|
+
results = CanHazPermission.where('cobject_id = ? AND cobject_type = ?', self.id, self.class.to_s).where('csubject_type = ?', type.to_s).where('permission_name = ?', permission)
|
21
|
+
|
22
|
+
ids = results.collect { |r| r.csubject_id }
|
23
|
+
|
24
|
+
type.where('id IN (?)', ids)
|
25
|
+
end
|
26
|
+
|
27
|
+
def canhaz_object?
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module CanHaz
|
2
|
+
module ModelExtensions
|
3
|
+
module Subject
|
4
|
+
|
5
|
+
# Creates a permission on a given object
|
6
|
+
#
|
7
|
+
# @param permission [String, Symbol] The identifier of the permission
|
8
|
+
# @param object [ActiveRecord::Base] The model on which the permission is effective
|
9
|
+
# @return [Bool] True if the role was successfully created, false if it was already present
|
10
|
+
def can(permission, object)
|
11
|
+
raise Exceptions::NotACanHazObject unless object.canhaz_object?
|
12
|
+
CanHazPermission.new({
|
13
|
+
:csubject_id => self.id,
|
14
|
+
:csubject_type => self.class.to_s,
|
15
|
+
:cobject_type => object.class.to_s,
|
16
|
+
:cobject_id => object.id,
|
17
|
+
:permission_name => permission
|
18
|
+
}).save
|
19
|
+
end
|
20
|
+
|
21
|
+
# Checks if the subject has a given permission on a given object
|
22
|
+
#
|
23
|
+
# @param permission [String, Symbol] The identifier of the permission
|
24
|
+
# @param object [ActiveRecord::Base] The model we are testing the permission on
|
25
|
+
# @return [Bool] True if the user has the given permission, false otherwise
|
26
|
+
def can?(permission, object)
|
27
|
+
raise Exceptions::NotACanHazObject unless object.canhaz_object?
|
28
|
+
CanHazPermission.find_permission(self, object, permission) != nil
|
29
|
+
end
|
30
|
+
|
31
|
+
# Removes a permission on a given object
|
32
|
+
#
|
33
|
+
# @param permission [String, Symbol] The identifier of the permission
|
34
|
+
# @param object [ActiveRecord::Base] The model on which the permission is effective
|
35
|
+
# @return [Bool] True if the role was successfully removed, false if it did not exist
|
36
|
+
def cannot(permission, object)
|
37
|
+
permission = CanHazPermission.find_permission(self, object, permission)
|
38
|
+
return false if permission.nil?
|
39
|
+
permission.destroy and return true
|
40
|
+
end
|
41
|
+
|
42
|
+
# Checks if the subject does not have a given permission on a given object
|
43
|
+
# Acts as a proxy of !subject.can?(permission, object)
|
44
|
+
#
|
45
|
+
# @param permission [String, Symbol] The identifier of the permission
|
46
|
+
# @param object [ActiveRecord::Base] The model we are testing the permission on
|
47
|
+
# @return [Bool] True if the user has not the given permission, false otherwise
|
48
|
+
def cannot?(permission, object)
|
49
|
+
!self.can?(permission, object)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Gets All objects that match a given type and permission
|
53
|
+
#
|
54
|
+
# @param type [Class] The type of the objects
|
55
|
+
# @param permission [String, Symbol] The name of the permission
|
56
|
+
# @return The macthing objects in an array
|
57
|
+
def objects_with_permission(type, permission = nil)
|
58
|
+
results = CanHazPermission.where('csubject_id = ? AND csubject_type = ?', self.id, self.class.to_s).where('cobject_type = ?', type.to_s).where('permission_name = ?', permission)
|
59
|
+
|
60
|
+
ids = results.collect { |r| r.cobject_id }
|
61
|
+
|
62
|
+
type.where('id IN (?)', ids)
|
63
|
+
end
|
64
|
+
|
65
|
+
def canhaz_subject?
|
66
|
+
true
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rails-canhaz/extensions_subject'
|
2
|
+
require 'rails-canhaz/extensions_object'
|
3
|
+
require 'rails-canhaz/extensions_all'
|
4
|
+
|
5
|
+
module CanHaz
|
6
|
+
module ModelExtensions
|
7
|
+
def self.included(base)
|
8
|
+
base.send(:extend, ClassMethods)
|
9
|
+
base.send(:include, CanHaz::ModelExtensions::All)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
|
15
|
+
##
|
16
|
+
# Marks the current model as a canhaz object for authorizations
|
17
|
+
#
|
18
|
+
def acts_as_canhaz_object
|
19
|
+
include CanHaz::ModelExtensions::Object
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Marks the current model as a canhaz subject for authorizations
|
24
|
+
#
|
25
|
+
def acts_as_canhaz_subject
|
26
|
+
include CanHaz::ModelExtensions::Subject
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
data/lib/rails-canhaz.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
require 'rails-canhaz/exceptions'
|
2
|
+
require 'rails-canhaz/model_extensions'
|
3
|
+
require 'rails-canhaz/canhaz_permission'
|
4
|
+
|
5
|
+
if defined? ActiveRecord::Base
|
6
|
+
ActiveRecord::Base.send(:include, CanHaz::ModelExtensions)
|
5
7
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'rails-canhaz'
|
3
|
+
s.version = '0.1.1'
|
4
|
+
s.date = '2012-04-16'
|
5
|
+
s.summary = "A simple gem for managing permissions between rails models"
|
6
|
+
s.description = "A simple gem for managing permissions between rails models"
|
7
|
+
s.authors = ["Adrien Siami (Intrepidd)"]
|
8
|
+
s.email = 'adrien@siami.fr'
|
9
|
+
s.files = `git ls-files`.split("\n")
|
10
|
+
|
11
|
+
s.homepage =
|
12
|
+
'http://github.com/Intrepidd/rails-canhaz'
|
13
|
+
end
|
data/test/.gitkeep
ADDED
File without changes
|
data/test/init_tests.rb
ADDED
data/test/schema.rb
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
|
2
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'object_models'")
|
3
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'subject_models'")
|
4
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'can_haz_permissions'")
|
5
|
+
ActiveRecord::Base.connection.execute("DROP TABLE IF EXISTS 'foo_models'")
|
6
|
+
|
7
|
+
ActiveRecord::Schema.define(:version => 0) do
|
8
|
+
|
9
|
+
create_table :object_models do |t|
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
create_table :subject_models do |t|
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
create_table :can_haz_permissions do |t|
|
18
|
+
t.integer :csubject_id
|
19
|
+
t.string :csubject_type
|
20
|
+
|
21
|
+
t.integer :cobject_id
|
22
|
+
t.string :cobject_type
|
23
|
+
|
24
|
+
t.string :permission_name
|
25
|
+
end
|
26
|
+
|
27
|
+
add_index :can_haz_permissions, :csubject_id, :name => 'subject_id_ix'
|
28
|
+
add_index :can_haz_permissions, :cobject_id, :name => 'object_id_ix'
|
29
|
+
|
30
|
+
create_table :foo_models do |t|
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/test/test_canhaz.rb
ADDED
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'init_tests'
|
2
|
+
require 'rails-canhaz'
|
3
|
+
require 'test/unit'
|
4
|
+
require 'models/object_model'
|
5
|
+
require 'models/subject_model'
|
6
|
+
require 'models/foo_model'
|
7
|
+
|
8
|
+
load 'schema.rb'
|
9
|
+
|
10
|
+
class CanHazTest < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def test_methods
|
13
|
+
assert ActiveRecord::Base.respond_to? :acts_as_canhaz_object
|
14
|
+
assert ActiveRecord::Base.respond_to? :acts_as_canhaz_subject
|
15
|
+
|
16
|
+
|
17
|
+
foo = FooModel.new
|
18
|
+
|
19
|
+
assert foo.canhaz_object? == false
|
20
|
+
assert foo.canhaz_subject? == false
|
21
|
+
|
22
|
+
object = ObjectModel.new
|
23
|
+
|
24
|
+
assert object.canhaz_object?
|
25
|
+
assert object.canhaz_subject? == false
|
26
|
+
|
27
|
+
subject = SubjectModel.new
|
28
|
+
|
29
|
+
assert subject.canhaz_subject?
|
30
|
+
assert subject.canhaz_object? == false
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_exceptions
|
35
|
+
foo = FooModel.new
|
36
|
+
|
37
|
+
subject = SubjectModel.new
|
38
|
+
|
39
|
+
object = ObjectModel.new
|
40
|
+
|
41
|
+
assert_raise CanHaz::Exceptions::NotACanHazObject do
|
42
|
+
subject.can(:whatever, foo)
|
43
|
+
end
|
44
|
+
|
45
|
+
assert_nothing_raised RuntimeError do
|
46
|
+
subject.can(:whatever, object)
|
47
|
+
end
|
48
|
+
|
49
|
+
assert_raise CanHaz::Exceptions::NotACanHazObject do
|
50
|
+
subject.can?(:whatever, foo)
|
51
|
+
end
|
52
|
+
|
53
|
+
assert_nothing_raised RuntimeError do
|
54
|
+
subject.can?(:whatever, object)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_can
|
60
|
+
subject = SubjectModel.new
|
61
|
+
subject.save
|
62
|
+
|
63
|
+
object = ObjectModel.new
|
64
|
+
object.save
|
65
|
+
|
66
|
+
assert subject.can?(:foo, object) == false
|
67
|
+
assert subject.can?(:bar, object) == false
|
68
|
+
|
69
|
+
assert object.accessible_by?(subject, :foo) == false
|
70
|
+
assert object.accessible_by?(subject, :bar) == false
|
71
|
+
|
72
|
+
assert subject.can(:foo, object)
|
73
|
+
assert subject.can(:bar, object)
|
74
|
+
|
75
|
+
assert subject.can(:foo, object) == false
|
76
|
+
assert subject.can(:bar, object) == false
|
77
|
+
|
78
|
+
assert subject.can?(:foo, object)
|
79
|
+
assert subject.can?(:bar, object)
|
80
|
+
|
81
|
+
assert object.accessible_by?(subject, :foo)
|
82
|
+
assert object.accessible_by?(subject, :bar)
|
83
|
+
|
84
|
+
assert subject.objects_with_permission(ObjectModel, :foo).count == 1
|
85
|
+
assert subject.objects_with_permission(ObjectModel, :foo).first == object
|
86
|
+
|
87
|
+
assert subject.objects_with_permission(ObjectModel, :bar).count == 1
|
88
|
+
assert subject.objects_with_permission(ObjectModel, :bar).first == object
|
89
|
+
|
90
|
+
assert subject.objects_with_permission(ObjectModel, :foobar).count == 0
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_can_cannot
|
95
|
+
subject = SubjectModel.new
|
96
|
+
subject.save
|
97
|
+
|
98
|
+
object = ObjectModel.new
|
99
|
+
object.save
|
100
|
+
|
101
|
+
assert subject.can?(:foo, object) == false
|
102
|
+
assert subject.cannot(:foo, object) == false
|
103
|
+
|
104
|
+
subject.can(:foo, object)
|
105
|
+
subject.can(:bar, object)
|
106
|
+
|
107
|
+
assert subject.can?(:foo, object)
|
108
|
+
assert subject.can?(:bar, object)
|
109
|
+
|
110
|
+
assert subject.cannot(:foo, object) == true
|
111
|
+
|
112
|
+
assert subject.can?(:foo, object) == false
|
113
|
+
assert subject.can?(:bar, object) == true
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_subjects_from_object
|
117
|
+
object = ObjectModel.new
|
118
|
+
object.save
|
119
|
+
|
120
|
+
s1 = SubjectModel.new
|
121
|
+
s2 = SubjectModel.new
|
122
|
+
s3 = SubjectModel.new
|
123
|
+
|
124
|
+
s1.save
|
125
|
+
s2.save
|
126
|
+
s3.save
|
127
|
+
|
128
|
+
s1.can(:foo, object)
|
129
|
+
s2.can(:bar, object)
|
130
|
+
s3.can(:foo, object)
|
131
|
+
|
132
|
+
foo = object.subjects_with_permission(SubjectModel, :foo)
|
133
|
+
|
134
|
+
assert foo.include?(s1) == true
|
135
|
+
assert foo.include?(s2) == false
|
136
|
+
assert foo.include?(s3) == true
|
137
|
+
|
138
|
+
s3.cannot(:foo, object)
|
139
|
+
|
140
|
+
foo = object.subjects_with_permission(SubjectModel, :foo)
|
141
|
+
|
142
|
+
assert foo.include?(s1) == true
|
143
|
+
assert foo.include?(s2) == false
|
144
|
+
assert foo.include?(s3) == false
|
145
|
+
|
146
|
+
bar = object.subjects_with_permission(SubjectModel, :bar)
|
147
|
+
|
148
|
+
assert bar.include?(s1) == false
|
149
|
+
assert bar.include?(s2) == true
|
150
|
+
assert bar.include?(s3) == false
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails-canhaz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-04-16 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: A simple gem for managing permissions between rails models
|
15
15
|
email: adrien@siami.fr
|
@@ -17,8 +17,26 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
+
- .gitignore
|
21
|
+
- Gemfile
|
22
|
+
- README.md
|
23
|
+
- Rakefile
|
20
24
|
- lib/rails-canhaz.rb
|
21
|
-
|
25
|
+
- lib/rails-canhaz/canhaz_permission.rb
|
26
|
+
- lib/rails-canhaz/exceptions.rb
|
27
|
+
- lib/rails-canhaz/extensions_all.rb
|
28
|
+
- lib/rails-canhaz/extensions_object.rb
|
29
|
+
- lib/rails-canhaz/extensions_subject.rb
|
30
|
+
- lib/rails-canhaz/model_extensions.rb
|
31
|
+
- rails-canhaz.gemspec
|
32
|
+
- test/.gitkeep
|
33
|
+
- test/init_tests.rb
|
34
|
+
- test/models/foo_model.rb
|
35
|
+
- test/models/object_model.rb
|
36
|
+
- test/models/subject_model.rb
|
37
|
+
- test/schema.rb
|
38
|
+
- test/test_canhaz.rb
|
39
|
+
homepage: http://github.com/Intrepidd/rails-canhaz
|
22
40
|
licenses: []
|
23
41
|
post_install_message:
|
24
42
|
rdoc_options: []
|
@@ -38,8 +56,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
38
56
|
version: '0'
|
39
57
|
requirements: []
|
40
58
|
rubyforge_project:
|
41
|
-
rubygems_version: 1.8.
|
59
|
+
rubygems_version: 1.8.21
|
42
60
|
signing_key:
|
43
61
|
specification_version: 3
|
44
62
|
summary: A simple gem for managing permissions between rails models
|
45
63
|
test_files: []
|
64
|
+
has_rdoc:
|