cancan_edit 0.0.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/VERSION +1 -0
- data/cancan_edit.gemspec +12 -0
- data/lib/cancan_edit.rb +5 -0
- data/lib/cancan_edit/controller_additions.rb +22 -0
- data/lib/cancan_edit/edit_ability.rb +55 -0
- data/lib/cancan_edit/edit_additions.rb +38 -0
- data/lib/cancan_edit/edit_rule.rb +113 -0
- data/readme.markdown +59 -0
- metadata +103 -0
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/cancan_edit.gemspec
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'cancan_edit'
|
3
|
+
s.version = File.read "VERSION"
|
4
|
+
s.summary = "cancan ability for views"
|
5
|
+
s.authors = "Serkan Gonuler"
|
6
|
+
s.email = "serkangonuler@gmail.com"
|
7
|
+
s.homepage = 'http://github.com/lisica/cancan_edit'
|
8
|
+
s.files = Dir["lib/**/*"] << "VERSION" << "readme.markdown" << "cancan_edit.gemspec"
|
9
|
+
|
10
|
+
s.add_development_dependency 'rspec', '~> 2.6.0'
|
11
|
+
s.add_dependency "cancan", '~> 1.6.7'
|
12
|
+
end
|
data/lib/cancan_edit.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
module CanCan
|
2
|
+
module ControllerAdditions
|
3
|
+
def self.included(base)
|
4
|
+
base.helper_method :can_edit?, :cannot_edit?
|
5
|
+
end
|
6
|
+
|
7
|
+
def can_edit?(*args)
|
8
|
+
current_ability.can_edit?(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def cannot_edit?(*args)
|
12
|
+
current_ability.cannot_edit?(*args)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
if defined? ActionController
|
18
|
+
ActionController::Base.class_eval do
|
19
|
+
include CanCan::ControllerAdditions
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module CanCan
|
2
|
+
|
3
|
+
module EditAbility
|
4
|
+
|
5
|
+
def can_edit?(field, subject, *extra_args)
|
6
|
+
match = relevant_edit_rules_for_match(field, subject).detect do |rule|
|
7
|
+
rule.matches_conditions?(field, subject, extra_args)
|
8
|
+
end
|
9
|
+
match ? match.base_behavior : false
|
10
|
+
end
|
11
|
+
|
12
|
+
def cannot_edit?(*args)
|
13
|
+
!can_edit?(*args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def can_edit(field = nil, subject = nil, conditions = nil, &block)
|
17
|
+
edit_rules << EditRule.new(true, field, subject, conditions, block)
|
18
|
+
end
|
19
|
+
|
20
|
+
def cannot_edit(field = nil, subject = nil, conditions = nil, &block)
|
21
|
+
edit_rules << EditRule.new(false, field, subject, conditions, block)
|
22
|
+
end
|
23
|
+
|
24
|
+
def has_block?(field, subject)
|
25
|
+
relevant_rules(field, subject).any?(&:only_block?)
|
26
|
+
end
|
27
|
+
|
28
|
+
def has_raw_sql?(field, subject)
|
29
|
+
relevant_rules(field, subject).any?(&:only_raw_sql?)
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def edit_rules
|
35
|
+
@edit_rules ||= []
|
36
|
+
end
|
37
|
+
|
38
|
+
def relevant_edit_rules(field, subject)
|
39
|
+
edit_rules.reverse.select do |edit_rule|
|
40
|
+
edit_rule.expanded_fields = edit_rule.fields
|
41
|
+
edit_rule.relevant? field, subject
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
|
46
|
+
def relevant_edit_rules_for_match(field, subject)
|
47
|
+
relevant_edit_rules(field, subject).each do |rule|
|
48
|
+
if rule.only_raw_sql?
|
49
|
+
raise Error, "The can? and cannot? call cannot be used with a raw sql 'can' definition. The checking code cannot be determined for #{field.inspect} #{subject.inspect}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
class ActionView::Helpers::FormBuilder
|
2
|
+
(field_helpers - %w(label check_box radio_button fields_for hidden_field apply_form_for_options!)).each do |selector|
|
3
|
+
class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
|
4
|
+
def #{selector}_with_cancan(method, options = {})
|
5
|
+
options.merge!({:disabled => true}) unless (@template.can_edit? method.to_sym, @object)
|
6
|
+
#{selector}_without_cancan(method, options)
|
7
|
+
end
|
8
|
+
RUBY_EVAL
|
9
|
+
alias_method_chain selector.to_sym, :cancan
|
10
|
+
end
|
11
|
+
|
12
|
+
def check_box_with_cancan(method, options = {}, checked_value = "1", unchecked_value = "0")
|
13
|
+
options.merge!({:disabled => true}) unless (@template.can_edit? method.to_sym, @object)
|
14
|
+
check_box_without_cancan(method, options, checked_value = "1", unchecked_value = "0")
|
15
|
+
end
|
16
|
+
alias_method_chain :check_box, :cancan
|
17
|
+
|
18
|
+
def radio_button_with_cancan(method, tag_value, options = {})
|
19
|
+
options.merge!({:disabled => true}) unless (@template.can_edit? method.to_sym, @object)
|
20
|
+
radio_button_without_cancan(method, tag_value, options)
|
21
|
+
end
|
22
|
+
alias_method_chain :radio_button, :cancan
|
23
|
+
end
|
24
|
+
|
25
|
+
# password_field
|
26
|
+
# file_field
|
27
|
+
# number_field
|
28
|
+
# text_field
|
29
|
+
# text_area
|
30
|
+
# telephone_field
|
31
|
+
# email_field
|
32
|
+
# search_field
|
33
|
+
# range_field
|
34
|
+
# url_field
|
35
|
+
# phone_field
|
36
|
+
# check_box
|
37
|
+
# radio_button
|
38
|
+
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module CanCan
|
2
|
+
class EditRule
|
3
|
+
attr_reader :base_behavior, :subjects, :fields, :conditions
|
4
|
+
attr_writer :expanded_fields
|
5
|
+
|
6
|
+
def initialize(base_behavior, field, subject, conditions, block)
|
7
|
+
raise Error, "You are not able to supply a block with a hash of conditions in #{field} #{subject} ability. Use either one." if conditions.kind_of?(Hash) && !block.nil?
|
8
|
+
@match_all = field.nil? && subject.nil?
|
9
|
+
@base_behavior = base_behavior
|
10
|
+
@fields = [field].flatten
|
11
|
+
@subjects = [subject].flatten
|
12
|
+
@conditions = conditions || {}
|
13
|
+
@block = block
|
14
|
+
end
|
15
|
+
|
16
|
+
def relevant?(field, subject)
|
17
|
+
subject = subject.values.first if subject.class == Hash
|
18
|
+
@match_all || (matches_field?(field) && matches_subject?(subject))
|
19
|
+
end
|
20
|
+
|
21
|
+
def matches_conditions?(field, subject, extra_args)
|
22
|
+
if @match_all
|
23
|
+
call_block_with_all(field, subject, extra_args)
|
24
|
+
elsif @block && !subject_class?(subject)
|
25
|
+
@block.call(subject, *extra_args)
|
26
|
+
elsif @conditions.kind_of?(Hash) && subject.class == Hash
|
27
|
+
nested_subject_matches_conditions?(subject)
|
28
|
+
elsif @conditions.kind_of?(Hash) && !subject_class?(subject)
|
29
|
+
matches_conditions_hash?(subject)
|
30
|
+
else
|
31
|
+
@conditions.empty? ? true : @base_behavior
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def only_block?
|
36
|
+
conditions_empty? && !@block.nil?
|
37
|
+
end
|
38
|
+
|
39
|
+
def only_raw_sql?
|
40
|
+
@block.nil? && !conditions_empty? && !@conditions.kind_of?(Hash)
|
41
|
+
end
|
42
|
+
|
43
|
+
def conditions_empty?
|
44
|
+
@conditions == {} || @conditions.nil?
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def subject_class?(subject)
|
50
|
+
klass = (subject.kind_of?(Hash) ? subject.values.first : subject).class
|
51
|
+
klass == Class || klass == Module
|
52
|
+
end
|
53
|
+
|
54
|
+
def matches_field?(field)
|
55
|
+
@expanded_fields.include?(:manage) || @expanded_fields.include?(field)
|
56
|
+
end
|
57
|
+
|
58
|
+
def matches_subject?(subject)
|
59
|
+
@subjects.include?(:all) || @subjects.include?(subject) || matches_subject_class?(subject)
|
60
|
+
end
|
61
|
+
|
62
|
+
def matches_subject_class?(subject)
|
63
|
+
@subjects.any? { |sub| sub.kind_of?(Module) && (subject.kind_of?(sub) || subject.class.to_s == sub.to_s || subject.kind_of?(Module) && subject.ancestors.include?(sub)) }
|
64
|
+
end
|
65
|
+
|
66
|
+
def matches_conditions_hash?(subject, conditions = @conditions)
|
67
|
+
if conditions.empty?
|
68
|
+
true
|
69
|
+
else
|
70
|
+
if model_adapter(subject).override_conditions_hash_matching? subject, conditions
|
71
|
+
model_adapter(subject).matches_conditions_hash? subject, conditions
|
72
|
+
else
|
73
|
+
conditions.all? do |name, value|
|
74
|
+
if model_adapter(subject).override_condition_matching? subject, name, value
|
75
|
+
model_adapter(subject).matches_condition? subject, name, value
|
76
|
+
else
|
77
|
+
attribute = subject.send(name)
|
78
|
+
if value.kind_of?(Hash)
|
79
|
+
if attribute.kind_of? Array
|
80
|
+
attribute.any? { |element| matches_conditions_hash? element, value }
|
81
|
+
else
|
82
|
+
!attribute.nil? && matches_conditions_hash?(attribute, value)
|
83
|
+
end
|
84
|
+
elsif value.kind_of?(Array) || value.kind_of?(Range)
|
85
|
+
value.include? attribute
|
86
|
+
else
|
87
|
+
attribute == value
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def nested_subject_matches_conditions?(subject_hash)
|
96
|
+
parent, child = subject_hash.shift
|
97
|
+
matches_conditions_hash?(parent, @conditions[parent.class.name.downcase.to_sym] || {})
|
98
|
+
end
|
99
|
+
|
100
|
+
def call_block_with_all(field, subject, extra_args)
|
101
|
+
if subject.class == Class
|
102
|
+
@block.call(field, subject, nil, *extra_args)
|
103
|
+
else
|
104
|
+
@block.call(field, subject.class, subject, *extra_args)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def model_adapter(subject)
|
109
|
+
ModelAdapters::AbstractAdapter.adapter_class(subject_class?(subject) ? subject : subject.class)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
data/readme.markdown
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
#cancan_edit
|
2
|
+
`cancan_edit` is a gem for your views, in which you can disable and/or
|
3
|
+
enable fields based on permissions.
|
4
|
+
|
5
|
+
##Installation
|
6
|
+
|
7
|
+
```sh
|
8
|
+
$ gem install cancan_edit
|
9
|
+
```
|
10
|
+
|
11
|
+
|
12
|
+
##How to use?
|
13
|
+
|
14
|
+
let's assume you have Person model with
|
15
|
+
|
16
|
+
first_name, text_field,
|
17
|
+
last_name, text_field,
|
18
|
+
address, textarea,
|
19
|
+
is_admin, checkbox
|
20
|
+
|
21
|
+
and you are using cancan for authorization with
|
22
|
+
admin
|
23
|
+
photo_editor
|
24
|
+
groups.
|
25
|
+
|
26
|
+
|
27
|
+
you want an admin group to be able to edit all fields and all models.
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
can_edit :manage, :all
|
31
|
+
```
|
32
|
+
|
33
|
+
you want an admin group to be able to change "is_admin" checkbox but
|
34
|
+
not photo_editor.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
class Ability
|
38
|
+
include CanCan::Ability
|
39
|
+
include CanCan::EditAbility
|
40
|
+
|
41
|
+
def initialize(user)
|
42
|
+
if user.is?("admin")
|
43
|
+
can_edit :manage, Person
|
44
|
+
elsif user.is?("photo_editor")
|
45
|
+
can_edit :manage, Person
|
46
|
+
cannot_edit [:is_admin] , Person
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
you can also
|
53
|
+
```ruby
|
54
|
+
can_edit [:first_name, :last_name ], [Person]
|
55
|
+
```
|
56
|
+
or
|
57
|
+
```
|
58
|
+
cannot_edit [:is_admin ], [Person]
|
59
|
+
```
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cancan_edit
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Serkan Gonuler
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-10-25 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ~>
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 23
|
29
|
+
segments:
|
30
|
+
- 2
|
31
|
+
- 6
|
32
|
+
- 0
|
33
|
+
version: 2.6.0
|
34
|
+
type: :development
|
35
|
+
version_requirements: *id001
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: cancan
|
38
|
+
prerelease: false
|
39
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
40
|
+
none: false
|
41
|
+
requirements:
|
42
|
+
- - ~>
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
hash: 1
|
45
|
+
segments:
|
46
|
+
- 1
|
47
|
+
- 6
|
48
|
+
- 7
|
49
|
+
version: 1.6.7
|
50
|
+
type: :runtime
|
51
|
+
version_requirements: *id002
|
52
|
+
description:
|
53
|
+
email: serkangonuler@gmail.com
|
54
|
+
executables: []
|
55
|
+
|
56
|
+
extensions: []
|
57
|
+
|
58
|
+
extra_rdoc_files: []
|
59
|
+
|
60
|
+
files:
|
61
|
+
- lib/cancan_edit/controller_additions.rb
|
62
|
+
- lib/cancan_edit/edit_ability.rb
|
63
|
+
- lib/cancan_edit/edit_additions.rb
|
64
|
+
- lib/cancan_edit/edit_rule.rb
|
65
|
+
- lib/cancan_edit.rb
|
66
|
+
- VERSION
|
67
|
+
- readme.markdown
|
68
|
+
- cancan_edit.gemspec
|
69
|
+
homepage: http://github.com/lisica/cancan_edit
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.8.10
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: cancan ability for views
|
102
|
+
test_files: []
|
103
|
+
|