mass_assignment_with_multiple_roles 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/.gitignore ADDED
@@ -0,0 +1,19 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ bin/
11
+ doc/
12
+ lib/bundler/man
13
+ pkg
14
+ rdoc
15
+ spec/reports
16
+ test/tmp
17
+ test/version_tmp
18
+ tags
19
+ tmp
data/.rvmrc ADDED
@@ -0,0 +1,2 @@
1
+ # setup gemset
2
+ rvm use ruby-1.9.3@mass_assignment_with_multiple_roles
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.2
4
+ - 1.9.3
5
+ - jruby-19mode # JRuby in 1.9 mode
6
+ - rbx-19mode
7
+ script: bundle exec rake test
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in mass_assignment_with_multiple_roles.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 saksmlz
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # MassAssignmentWithMultipleRoles [![Build Status](https://secure.travis-ci.org/saks/mass_assignment_with_multiple_roles.png)](http://travis-ci.org/#!/saks/mass_assignment_with_multiple_roles)
2
+
3
+ Quite often your user can have multiple roles at the same time. `ActiveModel` does not provide the ability to sanitize attributes using intersection of `attr_accessible` for several role names at the same time.
4
+
5
+ This gem is all about to solve this problem.
6
+
7
+ ## Example of usage
8
+
9
+ Consider we have the following model code:
10
+
11
+ ```ruby
12
+ class Student < ActiveRecord::Base
13
+
14
+ attr_accessible :phone_number
15
+ attr_accessible :name, as: :admin
16
+ attr_accessible :email, as: :user
17
+ end
18
+ ```
19
+
20
+
21
+ Now, while updating in controller we can write:
22
+
23
+ ```ruby
24
+ student = Student.find(params[:id])
25
+ if student.update_attributes(params[:student], :as => [:admin, :teacher])
26
+ ```
27
+
28
+ Role names can be passed in `ActiveModel` style:
29
+ ```ruby
30
+ student.update_attributes(params[:student], :as => :admin)
31
+ ```
32
+
33
+ all it's functionality is fully supported.
34
+
35
+ Several roles can be passed as an array symbols:
36
+ ```ruby
37
+ student.update_attributes(params[:student], :as => [:admin, :teacher])
38
+ ```
39
+
40
+ But in most cases, role names can be obtained from user model. If your user
41
+ model provides method called `role_names`, which returns as array of role
42
+ names, you can write code which is quite easy to understand.
43
+
44
+ In model:
45
+ ```ruby
46
+ class User < ActiveRecord::Base
47
+ has_many :roles
48
+
49
+ def role_names
50
+ roles.map &:name
51
+ end
52
+
53
+ end
54
+ ```
55
+
56
+ In controller:
57
+ ```ruby
58
+ student.update_attributes(params[:student], :as => current_user)
59
+ ```
60
+
61
+
62
+ ## Installation
63
+
64
+ Add this line to your application's Gemfile:
65
+
66
+ gem 'mass_assignment_with_multiple_roles'
67
+
68
+ And then execute:
69
+
70
+ $ bundle
71
+
72
+ Or install it yourself as:
73
+
74
+ $ gem install mass_assignment_with_multiple_roles
75
+
76
+ ## Contributing
77
+
78
+ 1. Fork it
79
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
80
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
81
+ 4. Push to the branch (`git push origin my-new-feature`)
82
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
3
+
4
+ dir = File.dirname(__FILE__)
5
+
6
+ require 'rake/testtask'
7
+
8
+ task :default => :test
9
+
10
+ Rake::TestTask.new do |t|
11
+ t.libs << "test"
12
+ t.test_files = Dir.glob("#{dir}/test/cases/**/*_test.rb").sort
13
+ t.warning = true
14
+ end
15
+
16
+ namespace :test do
17
+ task :isolated do
18
+ ruby = File.join(*RbConfig::CONFIG.values_at('bindir', 'RUBY_INSTALL_NAME'))
19
+ Dir.glob("#{dir}/test/**/*_test.rb").all? do |file|
20
+ sh(ruby, '-w', "-I#{dir}/lib", "-I#{dir}/test", file)
21
+ end or raise "Failures"
22
+ end
23
+ end
@@ -0,0 +1,65 @@
1
+ require 'active_model'
2
+ require 'mass_assignment_with_multiple_roles/version'
3
+
4
+ module MassAssignmentWithMultipleRoles
5
+ ROLE_NAMES_METHOD = :role_names
6
+
7
+ def compile_role_name(roles, active_authorizer)
8
+ roles_array = if roles.is_a? Array
9
+ roles
10
+ elsif roles.respond_to? ROLE_NAMES_METHOD
11
+ [roles.send(ROLE_NAMES_METHOD)].flatten
12
+ else
13
+ [roles]
14
+ end
15
+
16
+ roles_array = roles_array.find_all { |role| active_authorizer.has_key? role }
17
+
18
+ if roles_array.any?
19
+ [ roles_array.map(&:to_s).join('_').to_sym, roles_array ]
20
+ else
21
+ [ nil, roles_array ]
22
+ end
23
+ end
24
+
25
+ def build_new_attrs_config(roles_array, new_role_name, klass)
26
+ fields = roles_array.inject([]) do |result, role_name|
27
+ result += klass.active_authorizer[role_name].to_a
28
+ end
29
+
30
+ method_name = if klass.active_authorizer[ roles_array[0] ].is_a? ActiveModel::MassAssignmentSecurity::WhiteList
31
+ :attr_accessible
32
+ else
33
+ :attr_protected
34
+ end
35
+
36
+ klass.send method_name, *fields, :as => new_role_name
37
+ end
38
+
39
+ extend self
40
+ end
41
+
42
+ module ActiveModel
43
+ module MassAssignmentSecurity
44
+
45
+ protected
46
+
47
+ def mass_assignment_authorizer(roles)
48
+ active_authorizer = self.class.active_authorizer
49
+
50
+ composite_role_name, roles_array = MassAssignmentWithMultipleRoles::compile_role_name roles, active_authorizer
51
+
52
+ if !composite_role_name
53
+ active_authorizer[:default]
54
+
55
+ elsif active_authorizer.has_key? composite_role_name
56
+ active_authorizer[composite_role_name]
57
+
58
+ else
59
+ MassAssignmentWithMultipleRoles::build_new_attrs_config roles_array, composite_role_name, self.class
60
+ self.class.active_authorizer[composite_role_name]
61
+ end
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,57 @@
1
+ module ActiveModel
2
+ module MassAssignmentSecurity
3
+
4
+ protected
5
+
6
+ def mass_assignment_authorizer(roles)
7
+ active_authorizer = self.class.active_authorizer
8
+
9
+ composite_role_name, roles_array = compile_role_name roles, active_authorizer
10
+
11
+ if !composite_role_name
12
+ active_authorizer[:default]
13
+
14
+ elsif active_authorizer.has_key? composite_role_name
15
+ active_authorizer[composite_role_name]
16
+
17
+ else
18
+ build_new_attrs_config roles_array, composite_role_name
19
+ self.class.active_authorizer[composite_role_name]
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def compile_role_name(roles, active_authorizer)
26
+ roles_array = if roles.is_a? Array
27
+ roles
28
+ elsif roles.respond_to? :roles
29
+ [roles.send(:roles)].flatten
30
+ else
31
+ [roles]
32
+ end
33
+
34
+ roles_array = roles_array.find_all { |role| active_authorizer.has_key? role }
35
+
36
+ if roles_array.any?
37
+ [ roles_array.map(&:to_s).join('_').to_sym, roles_array ]
38
+ else
39
+ [ nil, roles_array ]
40
+ end
41
+ end
42
+
43
+ def build_new_attrs_config(roles_array, new_role_name)
44
+ fields = roles_array.inject([]) do |result, role_name|
45
+ result += self.class.active_authorizer[role_name].to_a
46
+ end
47
+
48
+ method_name = if self.class.active_authorizer[ roles_array[0] ].is_a? ActiveModel::MassAssignmentSecurity::WhiteList
49
+ :attr_accessible
50
+ else
51
+ :attr_protected
52
+ end
53
+
54
+ self.class.send method_name, *fields, :as => new_role_name
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,3 @@
1
+ module MassAssignmentWithMultipleRoles
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('../lib/mass_assignment_with_multiple_roles/version', __FILE__)
3
+
4
+ Gem::Specification.new do |gem|
5
+ gem.authors = ["saksmlz"]
6
+ gem.email = ["saksmlz@gmail.com"]
7
+ gem.description = %q{This gem allows you to pass multiple roles into methods like save and update_attributes}
8
+ gem.summary = %q{Allows to use intersection of attr_accessible if passing multiple role names on save}
9
+ gem.homepage = "http://github.com/saks/mass_assignment_with_multiple_roles"
10
+
11
+ gem.files = `git ls-files`.split($\)
12
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
13
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
14
+ gem.name = "mass_assignment_with_multiple_roles"
15
+ gem.require_paths = ["lib"]
16
+ gem.version = MassAssignmentWithMultipleRoles::VERSION
17
+
18
+ gem.add_development_dependency 'activesupport', '~> 3.2.3'
19
+ gem.add_development_dependency 'mocha', '> 0'
20
+ gem.add_development_dependency 'rake', '> 0'
21
+ gem.add_dependency 'activemodel', '~> 3.2.3'
22
+ end
@@ -0,0 +1,16 @@
1
+ # require File.expand_path('../../../../load_paths', __FILE__)
2
+
3
+ lib = File.expand_path("#{File.dirname(__FILE__)}/../../lib")
4
+ $:.unshift(lib) unless $:.include?('lib') || $:.include?(lib)
5
+
6
+ require 'config'
7
+ require 'active_model'
8
+ require 'active_support/core_ext/string/access'
9
+ require 'mass_assignment_with_multiple_roles'
10
+ require 'active_model/mass_assignment_security/permission_set'
11
+ require 'active_model/mass_assignment_security/sanitizer'
12
+
13
+ # Show backtraces for deprecated behavior for quicker cleanup.
14
+ ActiveSupport::Deprecation.debug = true
15
+
16
+ require 'test/unit'
@@ -0,0 +1,120 @@
1
+ require "cases/helper"
2
+ require 'models/mass_assignment_specific'
3
+
4
+
5
+ class CustomSanitizer < ActiveModel::MassAssignmentSecurity::Sanitizer
6
+
7
+ def process_removed_attributes(attrs)
8
+ raise StandardError
9
+ end
10
+
11
+ end
12
+
13
+ class MassAssignmentSecurityTest < ActiveModel::TestCase
14
+
15
+ def test_attribute_protection
16
+ user = User.new
17
+ expected = { "name" => "John Smith", "email" => "john@smith.com" }
18
+ sanitized = user.sanitize_for_mass_assignment(expected.merge("admin" => true))
19
+ assert_equal expected, sanitized
20
+ end
21
+
22
+ def test_attribute_protection_when_role_is_nil
23
+ user = User.new
24
+ expected = { "name" => "John Smith", "email" => "john@smith.com" }
25
+ sanitized = user.sanitize_for_mass_assignment(expected.merge("admin" => true), nil)
26
+ assert_equal expected, sanitized
27
+ end
28
+
29
+ def test_only_moderator_role_attribute_accessible
30
+ user = SpecialUser.new
31
+ expected = { "name" => "John Smith", "email" => "john@smith.com" }
32
+ sanitized = user.sanitize_for_mass_assignment(expected.merge("admin" => true), :moderator)
33
+ assert_equal expected, sanitized
34
+
35
+ sanitized = user.sanitize_for_mass_assignment({ "name" => "John Smith", "email" => "john@smith.com", "admin" => true })
36
+ assert_equal({}, sanitized)
37
+ end
38
+
39
+ def test_attributes_accessible
40
+ user = Person.new
41
+ expected = { "name" => "John Smith", "email" => "john@smith.com" }
42
+ sanitized = user.sanitize_for_mass_assignment(expected.merge("admin" => true))
43
+ assert_equal expected, sanitized
44
+ end
45
+
46
+ def test_attributes_accessible_with_admin_role
47
+ user = Person.new
48
+ expected = { "name" => "John Smith", "email" => "john@smith.com", "admin" => true }
49
+ sanitized = user.sanitize_for_mass_assignment(expected.merge("super_powers" => true), :admin)
50
+ assert_equal expected, sanitized
51
+ end
52
+
53
+ def test_attributes_accessible_with_roles_given_as_array
54
+ user = Account.new
55
+ expected = { "name" => "John Smith", "email" => "john@smith.com" }
56
+ sanitized = user.sanitize_for_mass_assignment(expected.merge("admin" => true))
57
+ assert_equal expected, sanitized
58
+ end
59
+
60
+ def test_attributes_accessible_with_admin_role_when_roles_given_as_array
61
+ user = Account.new
62
+ expected = { "name" => "John Smith", "email" => "john@smith.com", "admin" => true }
63
+ sanitized = user.sanitize_for_mass_assignment(expected.merge("super_powers" => true), :admin)
64
+ assert_equal expected, sanitized
65
+ end
66
+
67
+ def test_attributes_protected_by_default
68
+ firm = Firm.new
69
+ expected = { }
70
+ sanitized = firm.sanitize_for_mass_assignment({ "type" => "Client" })
71
+ assert_equal expected, sanitized
72
+ end
73
+
74
+ def test_mass_assignment_protection_inheritance
75
+ assert_blank LoosePerson.accessible_attributes
76
+ assert_equal Set.new(['credit_rating', 'administrator']), LoosePerson.protected_attributes
77
+
78
+ assert_blank LoosePerson.accessible_attributes
79
+ assert_equal Set.new(['credit_rating']), LoosePerson.protected_attributes(:admin)
80
+
81
+ assert_blank LooseDescendant.accessible_attributes
82
+ assert_equal Set.new(['credit_rating', 'administrator', 'phone_number']), LooseDescendant.protected_attributes
83
+
84
+ assert_blank LooseDescendantSecond.accessible_attributes
85
+ assert_equal Set.new(['credit_rating', 'administrator', 'phone_number', 'name']), LooseDescendantSecond.protected_attributes,
86
+ 'Running attr_protected twice in one class should merge the protections'
87
+
88
+ assert_blank TightPerson.protected_attributes - TightPerson.attributes_protected_by_default
89
+ assert_equal Set.new(['name', 'address']), TightPerson.accessible_attributes
90
+
91
+ assert_blank TightPerson.protected_attributes(:admin) - TightPerson.attributes_protected_by_default
92
+ assert_equal Set.new(['name', 'address', 'admin']), TightPerson.accessible_attributes(:admin)
93
+
94
+ assert_blank TightDescendant.protected_attributes - TightDescendant.attributes_protected_by_default
95
+ assert_equal Set.new(['name', 'address', 'phone_number']), TightDescendant.accessible_attributes
96
+
97
+ assert_blank TightDescendant.protected_attributes(:admin) - TightDescendant.attributes_protected_by_default
98
+ assert_equal Set.new(['name', 'address', 'admin', 'super_powers']), TightDescendant.accessible_attributes(:admin)
99
+
100
+ end
101
+
102
+ def test_mass_assignment_multiparameter_protector
103
+ task = Task.new
104
+ attributes = { "starting(1i)" => "2004", "starting(2i)" => "6", "starting(3i)" => "24" }
105
+ sanitized = task.sanitize_for_mass_assignment(attributes)
106
+ assert_equal sanitized, { }
107
+ end
108
+
109
+ def test_custom_sanitizer
110
+ user = User.new
111
+ User.mass_assignment_sanitizer = CustomSanitizer.new
112
+ assert_raise StandardError do
113
+ user.sanitize_for_mass_assignment("admin" => true)
114
+ end
115
+ ensure
116
+ User.mass_assignment_sanitizer = nil
117
+
118
+ end
119
+
120
+ end
@@ -0,0 +1,99 @@
1
+ require "cases/helper"
2
+ require 'models/mass_assignment_specific'
3
+ require 'ostruct'
4
+ require 'mocha'
5
+
6
+ class MassAssignmentSecurityWithMultipleRolesTest < ActiveModel::TestCase
7
+ def setup
8
+ Student.active_authorizer.delete :admin_user
9
+ end
10
+
11
+ def test_attribute_protection_when_role_is_nil
12
+ student = Student.new
13
+ expected = { 'name' => 'buz' }
14
+ sanitized = student.sanitize_for_mass_assignment(expected.merge('email' => 'bar'), [nil, :admin])
15
+ assert_equal expected, sanitized
16
+ end
17
+
18
+ def test_it_falls_to_default_if_no_valid_role_was_passed
19
+ student = Student.new
20
+ expected = { 'phone_number' => 'buz' }
21
+
22
+ sanitized = student.sanitize_for_mass_assignment(expected.merge('email' => 'bar'), [])
23
+ assert_equal expected, sanitized
24
+
25
+ sanitized = student.sanitize_for_mass_assignment(expected.merge('email' => 'bar'), nil)
26
+ assert_equal expected, sanitized
27
+
28
+ sanitized = student.sanitize_for_mass_assignment(expected.merge('email' => 'bar'))
29
+ assert_equal expected, sanitized
30
+
31
+ sanitized = student.sanitize_for_mass_assignment(expected.merge('email' => 'bar'), [Object.new])
32
+ assert_equal expected, sanitized
33
+ end
34
+
35
+ def test_with_an_array_of_roles_for_attr_accesible
36
+ student = Student.new
37
+ expected = { 'name' => 'buz', 'email' => 'foo' }
38
+ sanitized = student.sanitize_for_mass_assignment(expected, [:user, :admin])
39
+ assert_equal expected, sanitized
40
+ end
41
+
42
+ def test_with_an_array_of_roles_for_attr_protected
43
+ student = Teacher.new
44
+ expected = { 'phone_number' => 'bar' }
45
+
46
+ sanitized = student.sanitize_for_mass_assignment(
47
+ expected.merge('name' => 'buz', 'email' => 'foo'),
48
+ [:user, :admin]
49
+ )
50
+
51
+ assert_equal expected, sanitized
52
+ end
53
+
54
+ def test_with_object_that_respond_to_roles_method
55
+ student = Student.new
56
+ user = OpenStruct.new MassAssignmentWithMultipleRoles::ROLE_NAMES_METHOD => [:user, :admin]
57
+
58
+ expected = { 'name' => 'buz', 'email' => 'foo' }
59
+ sanitized = student.sanitize_for_mass_assignment(expected, user)
60
+ assert_equal expected, sanitized
61
+ end
62
+
63
+ def test_that_attributes_are_cached_and_not_created_second_time
64
+ student = Student.new
65
+ expected = { 'name' => 'buz', 'email' => 'foo' }
66
+
67
+ student.sanitize_for_mass_assignment(expected, [:user, :admin])
68
+
69
+ Student.expects(:attr_accessible).never
70
+
71
+ student.sanitize_for_mass_assignment(expected, [:user, :admin])
72
+ end
73
+
74
+ def test_do_not_take_into_account_not_known_roles
75
+ student = Student.new
76
+ expected = { 'name' => 'foo', 'email' => 'bar' }
77
+
78
+ sanitized = student.sanitize_for_mass_assignment(
79
+ expected.merge('phone_number' => 'buz'),
80
+ [:user, :admin, :not_existent]
81
+ )
82
+
83
+ assert_equal expected, sanitized
84
+ end
85
+
86
+ def test_do_not_fail_and_use_DEFAULT_if_wrong_data_type_was_passed_as_role
87
+ student = Student.new
88
+ expected = { 'phone_number' => 'buz' }
89
+ sanitized = student.sanitize_for_mass_assignment(expected.merge('email' => 'bar'), {wrong: 'data type'})
90
+ assert_equal expected, sanitized
91
+ end
92
+
93
+ def test_it_not_fails_if_active_authorizer_is_empty
94
+ blank = Blank.new
95
+ expected = { 'name' => 'buz', 'email' => 'foo' }
96
+ sanitized = blank.sanitize_for_mass_assignment(expected, [:user, :admin])
97
+ assert_equal expected, sanitized
98
+ end
99
+ end
data/test/config.rb ADDED
@@ -0,0 +1,3 @@
1
+ TEST_ROOT = File.expand_path(File.dirname(__FILE__))
2
+ FIXTURES_ROOT = TEST_ROOT + "/fixtures"
3
+ SCHEMA_FILE = TEST_ROOT + "/schema.rb"
@@ -0,0 +1,10 @@
1
+ class Administrator
2
+ include ActiveModel::Validations
3
+ include ActiveModel::SecurePassword
4
+ include ActiveModel::MassAssignmentSecurity
5
+
6
+ attr_accessor :name, :password_digest
7
+ attr_accessible :name
8
+
9
+ has_secure_password
10
+ end
@@ -0,0 +1,12 @@
1
+ class Automobile
2
+ include ActiveModel::Validations
3
+
4
+ validate :validations
5
+
6
+ attr_accessor :make, :model
7
+
8
+ def validations
9
+ validates_presence_of :make
10
+ validates_length_of :model, :within => 2..10
11
+ end
12
+ end
@@ -0,0 +1,9 @@
1
+ module Blog
2
+ def self.use_relative_model_naming?
3
+ true
4
+ end
5
+
6
+ class Post
7
+ extend ActiveModel::Naming
8
+ end
9
+ end
@@ -0,0 +1,26 @@
1
+ class Contact
2
+ extend ActiveModel::Naming
3
+ include ActiveModel::Conversion
4
+
5
+ attr_accessor :id, :name, :age, :created_at, :awesome, :preferences
6
+
7
+ def social
8
+ %w(twitter github)
9
+ end
10
+
11
+ def network
12
+ {:git => :github}
13
+ end
14
+
15
+ def initialize(options = {})
16
+ options.each { |name, value| send("#{name}=", value) }
17
+ end
18
+
19
+ def pseudonyms
20
+ nil
21
+ end
22
+
23
+ def persisted?
24
+ id
25
+ end
26
+ end
@@ -0,0 +1,15 @@
1
+ class CustomReader
2
+ include ActiveModel::Validations
3
+
4
+ def initialize(data = {})
5
+ @data = data
6
+ end
7
+
8
+ def []=(key, value)
9
+ @data[key] = value
10
+ end
11
+
12
+ def read_attribute_for_validation(key)
13
+ @data[key]
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ class Helicopter
2
+ include ActiveModel::Conversion
3
+ end
@@ -0,0 +1,102 @@
1
+ class User
2
+ include ActiveModel::MassAssignmentSecurity
3
+ attr_protected :admin
4
+
5
+ public :sanitize_for_mass_assignment
6
+ end
7
+
8
+ class SpecialUser
9
+ include ActiveModel::MassAssignmentSecurity
10
+ attr_accessible :name, :email, :as => :moderator
11
+
12
+ public :sanitize_for_mass_assignment
13
+ end
14
+
15
+ class Person
16
+ include ActiveModel::MassAssignmentSecurity
17
+ attr_accessible :name, :email
18
+ attr_accessible :name, :email, :admin, :as => :admin
19
+
20
+ public :sanitize_for_mass_assignment
21
+ end
22
+
23
+ class Account
24
+ include ActiveModel::MassAssignmentSecurity
25
+ attr_accessible :name, :email, :as => [:default, :admin]
26
+ attr_accessible :admin, :as => :admin
27
+
28
+ public :sanitize_for_mass_assignment
29
+ end
30
+
31
+ class Firm
32
+ include ActiveModel::MassAssignmentSecurity
33
+
34
+ public :sanitize_for_mass_assignment
35
+
36
+ def self.attributes_protected_by_default
37
+ ["type"]
38
+ end
39
+ end
40
+
41
+ class Task
42
+ include ActiveModel::MassAssignmentSecurity
43
+ attr_protected :starting
44
+
45
+ public :sanitize_for_mass_assignment
46
+ end
47
+
48
+ class LoosePerson
49
+ include ActiveModel::MassAssignmentSecurity
50
+ attr_protected :credit_rating, :administrator
51
+ attr_protected :credit_rating, :as => :admin
52
+ end
53
+
54
+ class LooseDescendant < LoosePerson
55
+ attr_protected :phone_number
56
+ end
57
+
58
+ class LooseDescendantSecond< LoosePerson
59
+ attr_protected :phone_number
60
+ attr_protected :name
61
+ end
62
+
63
+ class TightPerson
64
+ include ActiveModel::MassAssignmentSecurity
65
+ attr_accessible :name, :address
66
+ attr_accessible :name, :address, :admin, :as => :admin
67
+
68
+ def self.attributes_protected_by_default
69
+ ["mobile_number"]
70
+ end
71
+ end
72
+
73
+ class TightDescendant < TightPerson
74
+ attr_accessible :phone_number
75
+ attr_accessible :super_powers, :as => :admin
76
+ end
77
+
78
+ class Student
79
+ include ActiveModel::MassAssignmentSecurity
80
+
81
+ attr_accessible :phone_number
82
+ attr_accessible :name, as: :admin
83
+ attr_accessible :email, as: :user
84
+
85
+ public :sanitize_for_mass_assignment
86
+ end
87
+
88
+ class Teacher
89
+ include ActiveModel::MassAssignmentSecurity
90
+
91
+ attr_protected :phone_number
92
+ attr_protected :name, as: :admin
93
+ attr_protected :email, as: :user
94
+
95
+ public :sanitize_for_mass_assignment
96
+ end
97
+
98
+ class Blank
99
+ include ActiveModel::MassAssignmentSecurity
100
+
101
+ public :sanitize_for_mass_assignment
102
+ end
@@ -0,0 +1,27 @@
1
+ class ORM
2
+ include ActiveModel::Observing
3
+
4
+ def save
5
+ notify_observers :before_save
6
+ end
7
+
8
+ class Observer < ActiveModel::Observer
9
+ def before_save_invocations
10
+ @before_save_invocations ||= []
11
+ end
12
+
13
+ def before_save(record)
14
+ before_save_invocations << record
15
+ end
16
+ end
17
+ end
18
+
19
+ class Widget < ORM; end
20
+ class Budget < ORM; end
21
+ class WidgetObserver < ORM::Observer; end
22
+ class BudgetObserver < ORM::Observer; end
23
+ class AuditTrail < ORM::Observer
24
+ observe :widget, :budget
25
+ end
26
+
27
+ ORM.instantiate_observers
@@ -0,0 +1,17 @@
1
+ class Person
2
+ include ActiveModel::Validations
3
+ extend ActiveModel::Translation
4
+
5
+ attr_accessor :title, :karma, :salary, :gender
6
+
7
+ def condition_is_true
8
+ true
9
+ end
10
+ end
11
+
12
+ class Person::Gender
13
+ extend ActiveModel::Translation
14
+ end
15
+
16
+ class Child < Person
17
+ end
@@ -0,0 +1,24 @@
1
+ class PersonWithValidator
2
+ include ActiveModel::Validations
3
+
4
+ class PresenceValidator < ActiveModel::EachValidator
5
+ def validate_each(record, attribute, value)
6
+ record.errors[attribute] << "Local validator#{options[:custom]}" if value.blank?
7
+ end
8
+ end
9
+
10
+ class LikeValidator < ActiveModel::EachValidator
11
+ def initialize(options)
12
+ @with = options[:with]
13
+ super
14
+ end
15
+
16
+ def validate_each(record, attribute, value)
17
+ unless value[@with]
18
+ record.errors.add attribute, "does not appear to be like #{@with}"
19
+ end
20
+ end
21
+ end
22
+
23
+ attr_accessor :title, :karma
24
+ end
@@ -0,0 +1,32 @@
1
+ require 'models/topic'
2
+
3
+ class Reply < Topic
4
+ validate :errors_on_empty_content
5
+ validate :title_is_wrong_create, :on => :create
6
+
7
+ validate :check_empty_title
8
+ validate :check_content_mismatch, :on => :create
9
+ validate :check_wrong_update, :on => :update
10
+
11
+ def check_empty_title
12
+ errors[:title] << "is Empty" unless title && title.size > 0
13
+ end
14
+
15
+ def errors_on_empty_content
16
+ errors[:content] << "is Empty" unless content && content.size > 0
17
+ end
18
+
19
+ def check_content_mismatch
20
+ if title && content && content == "Mismatch"
21
+ errors[:title] << "is Content Mismatch"
22
+ end
23
+ end
24
+
25
+ def title_is_wrong_create
26
+ errors[:title] << "is Wrong Create" if title && title == "Wrong Create"
27
+ end
28
+
29
+ def check_wrong_update
30
+ errors[:title] << "is Wrong Update" if title && title == "Wrong Update"
31
+ end
32
+ end
@@ -0,0 +1,3 @@
1
+ class Sheep
2
+ extend ActiveModel::Naming
3
+ end
@@ -0,0 +1,40 @@
1
+ class Topic
2
+ include ActiveModel::Validations
3
+ include ActiveModel::Validations::Callbacks
4
+
5
+ def self._validates_default_keys
6
+ super | [ :message ]
7
+ end
8
+
9
+ attr_accessor :title, :author_name, :content, :approved
10
+ attr_accessor :after_validation_performed
11
+
12
+ after_validation :perform_after_validation
13
+
14
+ def initialize(attributes = {})
15
+ attributes.each do |key, value|
16
+ send "#{key}=", value
17
+ end
18
+ end
19
+
20
+ def condition_is_true
21
+ true
22
+ end
23
+
24
+ def condition_is_true_but_its_not
25
+ false
26
+ end
27
+
28
+ def perform_after_validation
29
+ self.after_validation_performed = true
30
+ end
31
+
32
+ def my_validation
33
+ errors.add :title, "is missing" unless title
34
+ end
35
+
36
+ def my_validation_with_arg(attr)
37
+ errors.add attr, "is missing" unless send(attr)
38
+ end
39
+
40
+ end
@@ -0,0 +1,11 @@
1
+ class Post
2
+ class TrackBack
3
+ def to_model
4
+ NamedTrackBack.new
5
+ end
6
+ end
7
+
8
+ class NamedTrackBack
9
+ extend ActiveModel::Naming
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ class User
2
+ include ActiveModel::Validations
3
+ include ActiveModel::SecurePassword
4
+
5
+ has_secure_password
6
+
7
+ attr_accessor :password_digest, :password_salt
8
+ end
@@ -0,0 +1,9 @@
1
+ class Visitor
2
+ include ActiveModel::Validations
3
+ include ActiveModel::SecurePassword
4
+ include ActiveModel::MassAssignmentSecurity
5
+
6
+ has_secure_password
7
+
8
+ attr_accessor :password_digest
9
+ end
metadata ADDED
@@ -0,0 +1,168 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mass_assignment_with_multiple_roles
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - saksmlz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-06-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 3.2.3
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 3.2.3
30
+ - !ruby/object:Gem::Dependency
31
+ name: mocha
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>'
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>'
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: rake
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>'
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>'
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: activemodel
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 3.2.3
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 3.2.3
78
+ description: This gem allows you to pass multiple roles into methods like save and
79
+ update_attributes
80
+ email:
81
+ - saksmlz@gmail.com
82
+ executables: []
83
+ extensions: []
84
+ extra_rdoc_files: []
85
+ files:
86
+ - .gitignore
87
+ - .rvmrc
88
+ - .travis.yml
89
+ - Gemfile
90
+ - LICENSE
91
+ - README.md
92
+ - Rakefile
93
+ - lib/mass_assignment_with_multiple_roles.rb
94
+ - lib/mass_assignment_with_multiple_roles/mass_assignment_security.rb
95
+ - lib/mass_assignment_with_multiple_roles/version.rb
96
+ - mass_assignment_with_multiple_roles.gemspec
97
+ - test/cases/helper.rb
98
+ - test/cases/mass_assignment_security_test.rb
99
+ - test/cases/mass_assignment_security_with_multiple_roles_test.rb
100
+ - test/config.rb
101
+ - test/models/administrator.rb
102
+ - test/models/automobile.rb
103
+ - test/models/blog_post.rb
104
+ - test/models/contact.rb
105
+ - test/models/custom_reader.rb
106
+ - test/models/helicopter.rb
107
+ - test/models/mass_assignment_specific.rb
108
+ - test/models/observers.rb
109
+ - test/models/person.rb
110
+ - test/models/person_with_validator.rb
111
+ - test/models/reply.rb
112
+ - test/models/sheep.rb
113
+ - test/models/topic.rb
114
+ - test/models/track_back.rb
115
+ - test/models/user.rb
116
+ - test/models/visitor.rb
117
+ homepage: http://github.com/saks/mass_assignment_with_multiple_roles
118
+ licenses: []
119
+ post_install_message:
120
+ rdoc_options: []
121
+ require_paths:
122
+ - lib
123
+ required_ruby_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ! '>='
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ segments:
130
+ - 0
131
+ hash: -188045199
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ none: false
134
+ requirements:
135
+ - - ! '>='
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ segments:
139
+ - 0
140
+ hash: -188045199
141
+ requirements: []
142
+ rubyforge_project:
143
+ rubygems_version: 1.8.24
144
+ signing_key:
145
+ specification_version: 3
146
+ summary: Allows to use intersection of attr_accessible if passing multiple role names
147
+ on save
148
+ test_files:
149
+ - test/cases/helper.rb
150
+ - test/cases/mass_assignment_security_test.rb
151
+ - test/cases/mass_assignment_security_with_multiple_roles_test.rb
152
+ - test/config.rb
153
+ - test/models/administrator.rb
154
+ - test/models/automobile.rb
155
+ - test/models/blog_post.rb
156
+ - test/models/contact.rb
157
+ - test/models/custom_reader.rb
158
+ - test/models/helicopter.rb
159
+ - test/models/mass_assignment_specific.rb
160
+ - test/models/observers.rb
161
+ - test/models/person.rb
162
+ - test/models/person_with_validator.rb
163
+ - test/models/reply.rb
164
+ - test/models/sheep.rb
165
+ - test/models/topic.rb
166
+ - test/models/track_back.rb
167
+ - test/models/user.rb
168
+ - test/models/visitor.rb