cancan_edit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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
+