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 ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -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
@@ -0,0 +1,5 @@
1
+ require "cancan"
2
+ require "cancan_edit/edit_ability"
3
+ require "cancan_edit/edit_additions"
4
+ require "cancan_edit/edit_rule"
5
+ require "cancan_edit/controller_additions"
@@ -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
+
@@ -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
+