activemodel 3.2.22.5 → 4.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +85 -64
- data/MIT-LICENSE +1 -1
- data/README.rdoc +61 -24
- data/lib/active_model.rb +21 -11
- data/lib/active_model/attribute_methods.rb +150 -125
- data/lib/active_model/callbacks.rb +49 -34
- data/lib/active_model/conversion.rb +39 -19
- data/lib/active_model/deprecated_mass_assignment_security.rb +21 -0
- data/lib/active_model/dirty.rb +48 -32
- data/lib/active_model/errors.rb +176 -88
- data/lib/active_model/forbidden_attributes_protection.rb +27 -0
- data/lib/active_model/lint.rb +42 -55
- data/lib/active_model/locale/en.yml +3 -1
- data/lib/active_model/model.rb +97 -0
- data/lib/active_model/naming.rb +191 -51
- data/lib/active_model/railtie.rb +11 -1
- data/lib/active_model/secure_password.rb +55 -25
- data/lib/active_model/serialization.rb +51 -27
- data/lib/active_model/serializers/json.rb +83 -46
- data/lib/active_model/serializers/xml.rb +46 -12
- data/lib/active_model/test_case.rb +0 -12
- data/lib/active_model/translation.rb +9 -10
- data/lib/active_model/validations.rb +154 -52
- data/lib/active_model/validations/absence.rb +31 -0
- data/lib/active_model/validations/acceptance.rb +10 -22
- data/lib/active_model/validations/callbacks.rb +78 -25
- data/lib/active_model/validations/clusivity.rb +41 -0
- data/lib/active_model/validations/confirmation.rb +13 -23
- data/lib/active_model/validations/exclusion.rb +26 -55
- data/lib/active_model/validations/format.rb +44 -34
- data/lib/active_model/validations/inclusion.rb +22 -52
- data/lib/active_model/validations/length.rb +48 -49
- data/lib/active_model/validations/numericality.rb +30 -32
- data/lib/active_model/validations/presence.rb +12 -22
- data/lib/active_model/validations/validates.rb +68 -36
- data/lib/active_model/validations/with.rb +28 -23
- data/lib/active_model/validator.rb +22 -22
- data/lib/active_model/version.rb +4 -4
- metadata +23 -24
- data/lib/active_model/mass_assignment_security.rb +0 -237
- data/lib/active_model/mass_assignment_security/permission_set.rb +0 -40
- data/lib/active_model/mass_assignment_security/sanitizer.rb +0 -59
- data/lib/active_model/observer_array.rb +0 -147
- data/lib/active_model/observing.rb +0 -252
@@ -3,12 +3,14 @@ module ActiveModel
|
|
3
3
|
module HelperMethods
|
4
4
|
private
|
5
5
|
def _merge_attributes(attr_names)
|
6
|
-
options = attr_names.extract_options
|
7
|
-
|
6
|
+
options = attr_names.extract_options!.symbolize_keys
|
7
|
+
attr_names.flatten!
|
8
|
+
options[:attributes] = attr_names
|
9
|
+
options
|
8
10
|
end
|
9
11
|
end
|
10
12
|
|
11
|
-
class WithValidator < EachValidator
|
13
|
+
class WithValidator < EachValidator # :nodoc:
|
12
14
|
def validate_each(record, attr, val)
|
13
15
|
method_name = options[:with]
|
14
16
|
|
@@ -32,7 +34,7 @@ module ActiveModel
|
|
32
34
|
# class MyValidator < ActiveModel::Validator
|
33
35
|
# def validate(record)
|
34
36
|
# if some_complex_logic
|
35
|
-
# record.errors.add :base,
|
37
|
+
# record.errors.add :base, 'This record is invalid'
|
36
38
|
# end
|
37
39
|
# end
|
38
40
|
#
|
@@ -46,29 +48,32 @@ module ActiveModel
|
|
46
48
|
#
|
47
49
|
# class Person
|
48
50
|
# include ActiveModel::Validations
|
49
|
-
# validates_with MyValidator, MyOtherValidator, :
|
51
|
+
# validates_with MyValidator, MyOtherValidator, on: :create
|
50
52
|
# end
|
51
53
|
#
|
52
54
|
# Configuration options:
|
53
55
|
# * <tt>:on</tt> - Specifies when this validation is active
|
54
|
-
# (<tt>:create</tt> or <tt>:update</tt
|
56
|
+
# (<tt>:create</tt> or <tt>:update</tt>.
|
55
57
|
# * <tt>:if</tt> - Specifies a method, proc or string to call to determine
|
56
|
-
# if the validation should occur (e.g. <tt
|
57
|
-
# or <tt
|
58
|
-
# proc or string should return or evaluate to a true or
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
58
|
+
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
59
|
+
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>).
|
60
|
+
# The method, proc or string should return or evaluate to a +true+ or
|
61
|
+
# +false+ value.
|
62
|
+
# * <tt>:unless</tt> - Specifies a method, proc or string to call to
|
63
|
+
# determine if the validation should not occur
|
64
|
+
# (e.g. <tt>unless: :skip_validation</tt>, or
|
65
|
+
# <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>).
|
66
|
+
# The method, proc or string should return or evaluate to a +true+ or
|
67
|
+
# +false+ value.
|
68
|
+
# * <tt>:strict</tt> - Specifies whether validation should be strict.
|
64
69
|
# See <tt>ActiveModel::Validation#validates!</tt> for more information.
|
65
|
-
|
70
|
+
#
|
66
71
|
# If you pass any additional configuration options, they will be passed
|
67
|
-
# to the class and available as
|
72
|
+
# to the class and available as +options+:
|
68
73
|
#
|
69
74
|
# class Person
|
70
75
|
# include ActiveModel::Validations
|
71
|
-
# validates_with MyValidator, :
|
76
|
+
# validates_with MyValidator, my_custom_key: 'my custom value'
|
72
77
|
# end
|
73
78
|
#
|
74
79
|
# class MyValidator < ActiveModel::Validator
|
@@ -116,20 +121,20 @@ module ActiveModel
|
|
116
121
|
# class Person
|
117
122
|
# include ActiveModel::Validations
|
118
123
|
#
|
119
|
-
# validate :instance_validations, :
|
124
|
+
# validate :instance_validations, on: :create
|
120
125
|
#
|
121
126
|
# def instance_validations
|
122
127
|
# validates_with MyValidator, MyOtherValidator
|
123
128
|
# end
|
124
129
|
# end
|
125
130
|
#
|
126
|
-
# Standard configuration options (
|
127
|
-
# available on the class version of
|
128
|
-
# placed on the
|
129
|
-
# in the callback.
|
131
|
+
# Standard configuration options (<tt>:on</tt>, <tt>:if</tt> and
|
132
|
+
# <tt>:unless</tt>), which are available on the class version of
|
133
|
+
# +validates_with+, should instead be placed on the +validates+ method
|
134
|
+
# as these are applied and tested in the callback.
|
130
135
|
#
|
131
136
|
# If you pass any additional configuration options, they will be passed
|
132
|
-
# to the class and available as
|
137
|
+
# to the class and available as +options+, please refer to the
|
133
138
|
# class version of this method for more information.
|
134
139
|
def validates_with(*args, &block)
|
135
140
|
options = args.extract_options!
|
@@ -1,11 +1,8 @@
|
|
1
|
-
require 'active_support/core_ext/array/wrap'
|
2
1
|
require "active_support/core_ext/module/anonymous"
|
3
|
-
require 'active_support/core_ext/object/blank'
|
4
|
-
require 'active_support/core_ext/object/inclusion'
|
5
2
|
|
6
|
-
module ActiveModel
|
3
|
+
module ActiveModel
|
7
4
|
|
8
|
-
# == Active Model Validator
|
5
|
+
# == Active \Model \Validator
|
9
6
|
#
|
10
7
|
# A simple base class that can be used along with
|
11
8
|
# ActiveModel::Validations::ClassMethods.validates_with
|
@@ -29,7 +26,7 @@ module ActiveModel #:nodoc:
|
|
29
26
|
# end
|
30
27
|
#
|
31
28
|
# Any class that inherits from ActiveModel::Validator must implement a method
|
32
|
-
# called
|
29
|
+
# called +validate+ which accepts a +record+.
|
33
30
|
#
|
34
31
|
# class Person
|
35
32
|
# include ActiveModel::Validations
|
@@ -43,8 +40,8 @@ module ActiveModel #:nodoc:
|
|
43
40
|
# end
|
44
41
|
# end
|
45
42
|
#
|
46
|
-
# To cause a validation error, you must add to the
|
47
|
-
# from within the validators message
|
43
|
+
# To cause a validation error, you must add to the +record+'s errors directly
|
44
|
+
# from within the validators message.
|
48
45
|
#
|
49
46
|
# class MyValidator < ActiveModel::Validator
|
50
47
|
# def validate(record)
|
@@ -63,29 +60,31 @@ module ActiveModel #:nodoc:
|
|
63
60
|
# end
|
64
61
|
# end
|
65
62
|
#
|
63
|
+
# Note that the validator is initialized only once for the whole application
|
64
|
+
# lifecycle, and not on each validation run.
|
65
|
+
#
|
66
66
|
# The easiest way to add custom validators for validating individual attributes
|
67
|
-
# is with the convenient <tt>ActiveModel::EachValidator</tt>.
|
67
|
+
# is with the convenient <tt>ActiveModel::EachValidator</tt>.
|
68
68
|
#
|
69
69
|
# class TitleValidator < ActiveModel::EachValidator
|
70
70
|
# def validate_each(record, attribute, value)
|
71
|
-
# record.errors.add attribute, 'must be Mr
|
71
|
+
# record.errors.add attribute, 'must be Mr., Mrs., or Dr.' unless %w(Mr. Mrs. Dr.).include?(value)
|
72
72
|
# end
|
73
73
|
# end
|
74
74
|
#
|
75
75
|
# This can now be used in combination with the +validates+ method
|
76
|
-
# (see <tt>ActiveModel::Validations::ClassMethods.validates</tt> for more on this)
|
76
|
+
# (see <tt>ActiveModel::Validations::ClassMethods.validates</tt> for more on this).
|
77
77
|
#
|
78
78
|
# class Person
|
79
79
|
# include ActiveModel::Validations
|
80
80
|
# attr_accessor :title
|
81
81
|
#
|
82
|
-
# validates :title, :
|
82
|
+
# validates :title, presence: true
|
83
83
|
# end
|
84
84
|
#
|
85
85
|
# Validator may also define a +setup+ instance method which will get called
|
86
86
|
# with the class that using that validator as its argument. This can be
|
87
|
-
# useful when there are prerequisites such as an +attr_accessor+ being present
|
88
|
-
# for example:
|
87
|
+
# useful when there are prerequisites such as an +attr_accessor+ being present.
|
89
88
|
#
|
90
89
|
# class MyValidator < ActiveModel::Validator
|
91
90
|
# def setup(klass)
|
@@ -95,25 +94,26 @@ module ActiveModel #:nodoc:
|
|
95
94
|
#
|
96
95
|
# This setup method is only called when used with validation macros or the
|
97
96
|
# class level <tt>validates_with</tt> method.
|
98
|
-
#
|
99
97
|
class Validator
|
100
98
|
attr_reader :options
|
101
99
|
|
102
|
-
# Returns the kind of the validator.
|
100
|
+
# Returns the kind of the validator.
|
103
101
|
#
|
104
102
|
# PresenceValidator.kind # => :presence
|
105
103
|
# UniquenessValidator.kind # => :uniqueness
|
106
|
-
#
|
107
104
|
def self.kind
|
108
105
|
@kind ||= name.split('::').last.underscore.sub(/_validator$/, '').to_sym unless anonymous?
|
109
106
|
end
|
110
107
|
|
111
108
|
# Accepts options that will be made available through the +options+ reader.
|
112
|
-
def initialize(options)
|
109
|
+
def initialize(options = {})
|
113
110
|
@options = options.freeze
|
114
111
|
end
|
115
112
|
|
116
113
|
# Return the kind for this validator.
|
114
|
+
#
|
115
|
+
# PresenceValidator.new.kind # => :presence
|
116
|
+
# UniquenessValidator.new.kind # => :uniqueness
|
117
117
|
def kind
|
118
118
|
self.class.kind
|
119
119
|
end
|
@@ -130,15 +130,15 @@ module ActiveModel #:nodoc:
|
|
130
130
|
# record, attribute and value.
|
131
131
|
#
|
132
132
|
# All Active Model validations are built on top of this validator.
|
133
|
-
class EachValidator < Validator
|
133
|
+
class EachValidator < Validator #:nodoc:
|
134
134
|
attr_reader :attributes
|
135
135
|
|
136
136
|
# Returns a new validator instance. All options will be available via the
|
137
137
|
# +options+ reader, however the <tt>:attributes</tt> option will be removed
|
138
138
|
# and instead be made available through the +attributes+ reader.
|
139
139
|
def initialize(options)
|
140
|
-
@attributes = Array
|
141
|
-
raise ":attributes cannot be blank" if @attributes.empty?
|
140
|
+
@attributes = Array(options.delete(:attributes))
|
141
|
+
raise ArgumentError, ":attributes cannot be blank" if @attributes.empty?
|
142
142
|
super
|
143
143
|
check_validity!
|
144
144
|
end
|
@@ -169,7 +169,7 @@ module ActiveModel #:nodoc:
|
|
169
169
|
|
170
170
|
# +BlockValidator+ is a special +EachValidator+ which receives a block on initialization
|
171
171
|
# and call this block for each attribute being validated. +validates_each+ uses this validator.
|
172
|
-
class BlockValidator < EachValidator
|
172
|
+
class BlockValidator < EachValidator #:nodoc:
|
173
173
|
def initialize(options, &block)
|
174
174
|
@block = block
|
175
175
|
super
|
data/lib/active_model/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activemodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 4.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2013-02-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,31 +16,31 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 4.0.0.beta1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 4.0.0.beta1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: builder
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 3.
|
33
|
+
version: 3.1.0
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 3.
|
41
|
-
description: A toolkit for building modeling frameworks like Active Record
|
42
|
-
|
43
|
-
|
40
|
+
version: 3.1.0
|
41
|
+
description: A toolkit for building modeling frameworks like Active Record. Rich support
|
42
|
+
for attributes, callbacks, validations, observers, serialization, internationalization,
|
43
|
+
and testing.
|
44
44
|
email: david@loudthinking.com
|
45
45
|
executables: []
|
46
46
|
extensions: []
|
@@ -49,20 +49,17 @@ files:
|
|
49
49
|
- CHANGELOG.md
|
50
50
|
- MIT-LICENSE
|
51
51
|
- README.rdoc
|
52
|
-
- lib/active_model.rb
|
53
52
|
- lib/active_model/attribute_methods.rb
|
54
53
|
- lib/active_model/callbacks.rb
|
55
54
|
- lib/active_model/conversion.rb
|
55
|
+
- lib/active_model/deprecated_mass_assignment_security.rb
|
56
56
|
- lib/active_model/dirty.rb
|
57
57
|
- lib/active_model/errors.rb
|
58
|
+
- lib/active_model/forbidden_attributes_protection.rb
|
58
59
|
- lib/active_model/lint.rb
|
59
60
|
- lib/active_model/locale/en.yml
|
60
|
-
- lib/active_model/
|
61
|
-
- lib/active_model/mass_assignment_security/permission_set.rb
|
62
|
-
- lib/active_model/mass_assignment_security/sanitizer.rb
|
61
|
+
- lib/active_model/model.rb
|
63
62
|
- lib/active_model/naming.rb
|
64
|
-
- lib/active_model/observer_array.rb
|
65
|
-
- lib/active_model/observing.rb
|
66
63
|
- lib/active_model/railtie.rb
|
67
64
|
- lib/active_model/secure_password.rb
|
68
65
|
- lib/active_model/serialization.rb
|
@@ -70,9 +67,10 @@ files:
|
|
70
67
|
- lib/active_model/serializers/xml.rb
|
71
68
|
- lib/active_model/test_case.rb
|
72
69
|
- lib/active_model/translation.rb
|
73
|
-
- lib/active_model/validations.rb
|
70
|
+
- lib/active_model/validations/absence.rb
|
74
71
|
- lib/active_model/validations/acceptance.rb
|
75
72
|
- lib/active_model/validations/callbacks.rb
|
73
|
+
- lib/active_model/validations/clusivity.rb
|
76
74
|
- lib/active_model/validations/confirmation.rb
|
77
75
|
- lib/active_model/validations/exclusion.rb
|
78
76
|
- lib/active_model/validations/format.rb
|
@@ -82,8 +80,10 @@ files:
|
|
82
80
|
- lib/active_model/validations/presence.rb
|
83
81
|
- lib/active_model/validations/validates.rb
|
84
82
|
- lib/active_model/validations/with.rb
|
83
|
+
- lib/active_model/validations.rb
|
85
84
|
- lib/active_model/validator.rb
|
86
85
|
- lib/active_model/version.rb
|
86
|
+
- lib/active_model.rb
|
87
87
|
homepage: http://www.rubyonrails.org
|
88
88
|
licenses:
|
89
89
|
- MIT
|
@@ -94,19 +94,18 @@ require_paths:
|
|
94
94
|
- lib
|
95
95
|
required_ruby_version: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
|
-
- -
|
97
|
+
- - '>='
|
98
98
|
- !ruby/object:Gem::Version
|
99
|
-
version: 1.
|
99
|
+
version: 1.9.3
|
100
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
|
-
- -
|
102
|
+
- - '>'
|
103
103
|
- !ruby/object:Gem::Version
|
104
|
-
version:
|
104
|
+
version: 1.3.1
|
105
105
|
requirements: []
|
106
106
|
rubyforge_project:
|
107
|
-
rubygems_version: 2.
|
107
|
+
rubygems_version: 2.0.0
|
108
108
|
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: A toolkit for building modeling frameworks (part of Rails).
|
111
111
|
test_files: []
|
112
|
-
has_rdoc:
|
@@ -1,237 +0,0 @@
|
|
1
|
-
require 'active_support/core_ext/class/attribute'
|
2
|
-
require 'active_support/core_ext/string/inflections'
|
3
|
-
require 'active_support/core_ext/array/wrap'
|
4
|
-
require 'active_model/mass_assignment_security/permission_set'
|
5
|
-
require 'active_model/mass_assignment_security/sanitizer'
|
6
|
-
|
7
|
-
module ActiveModel
|
8
|
-
# = Active Model Mass-Assignment Security
|
9
|
-
module MassAssignmentSecurity
|
10
|
-
extend ActiveSupport::Concern
|
11
|
-
|
12
|
-
included do
|
13
|
-
class_attribute :_accessible_attributes
|
14
|
-
class_attribute :_protected_attributes
|
15
|
-
class_attribute :_active_authorizer
|
16
|
-
|
17
|
-
class_attribute :_mass_assignment_sanitizer
|
18
|
-
self.mass_assignment_sanitizer = :logger
|
19
|
-
end
|
20
|
-
|
21
|
-
# Mass assignment security provides an interface for protecting attributes
|
22
|
-
# from end-user assignment. For more complex permissions, mass assignment security
|
23
|
-
# may be handled outside the model by extending a non-ActiveRecord class,
|
24
|
-
# such as a controller, with this behavior.
|
25
|
-
#
|
26
|
-
# For example, a logged in user may need to assign additional attributes depending
|
27
|
-
# on their role:
|
28
|
-
#
|
29
|
-
# class AccountsController < ApplicationController
|
30
|
-
# include ActiveModel::MassAssignmentSecurity
|
31
|
-
#
|
32
|
-
# attr_accessible :first_name, :last_name
|
33
|
-
# attr_accessible :first_name, :last_name, :plan_id, :as => :admin
|
34
|
-
#
|
35
|
-
# def update
|
36
|
-
# ...
|
37
|
-
# @account.update_attributes(account_params)
|
38
|
-
# ...
|
39
|
-
# end
|
40
|
-
#
|
41
|
-
# protected
|
42
|
-
#
|
43
|
-
# def account_params
|
44
|
-
# role = admin ? :admin : :default
|
45
|
-
# sanitize_for_mass_assignment(params[:account], role)
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# end
|
49
|
-
#
|
50
|
-
# = Configuration options
|
51
|
-
#
|
52
|
-
# * <tt>mass_assignment_sanitizer</tt> - Defines sanitize method. Possible values are:
|
53
|
-
# * <tt>:logger</tt> (default) - writes filtered attributes to logger
|
54
|
-
# * <tt>:strict</tt> - raise <tt>ActiveModel::MassAssignmentSecurity::Error</tt> on any protected attribute update
|
55
|
-
#
|
56
|
-
# You can specify your own sanitizer object eg. MySanitizer.new.
|
57
|
-
# See <tt>ActiveModel::MassAssignmentSecurity::LoggerSanitizer</tt> for example implementation.
|
58
|
-
#
|
59
|
-
#
|
60
|
-
module ClassMethods
|
61
|
-
# Attributes named in this macro are protected from mass-assignment
|
62
|
-
# whenever attributes are sanitized before assignment. A role for the
|
63
|
-
# attributes is optional, if no role is provided then :default is used.
|
64
|
-
# A role can be defined by using the :as option.
|
65
|
-
#
|
66
|
-
# Mass-assignment to these attributes will simply be ignored, to assign
|
67
|
-
# to them you can use direct writer methods. This is meant to protect
|
68
|
-
# sensitive attributes from being overwritten by malicious users
|
69
|
-
# tampering with URLs or forms. Example:
|
70
|
-
#
|
71
|
-
# class Customer
|
72
|
-
# include ActiveModel::MassAssignmentSecurity
|
73
|
-
#
|
74
|
-
# attr_accessor :name, :credit_rating
|
75
|
-
#
|
76
|
-
# attr_protected :credit_rating, :last_login
|
77
|
-
# attr_protected :last_login, :as => :admin
|
78
|
-
#
|
79
|
-
# def assign_attributes(values, options = {})
|
80
|
-
# sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
|
81
|
-
# send("#{k}=", v)
|
82
|
-
# end
|
83
|
-
# end
|
84
|
-
# end
|
85
|
-
#
|
86
|
-
# When using the :default role:
|
87
|
-
#
|
88
|
-
# customer = Customer.new
|
89
|
-
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default)
|
90
|
-
# customer.name # => "David"
|
91
|
-
# customer.credit_rating # => nil
|
92
|
-
# customer.last_login # => nil
|
93
|
-
#
|
94
|
-
# customer.credit_rating = "Average"
|
95
|
-
# customer.credit_rating # => "Average"
|
96
|
-
#
|
97
|
-
# And using the :admin role:
|
98
|
-
#
|
99
|
-
# customer = Customer.new
|
100
|
-
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin)
|
101
|
-
# customer.name # => "David"
|
102
|
-
# customer.credit_rating # => "Excellent"
|
103
|
-
# customer.last_login # => nil
|
104
|
-
#
|
105
|
-
# To start from an all-closed default and enable attributes as needed,
|
106
|
-
# have a look at +attr_accessible+.
|
107
|
-
#
|
108
|
-
# Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of
|
109
|
-
# +attr_protected+ to sanitize attributes provides basically the same
|
110
|
-
# functionality, but it makes a bit tricky to deal with nested attributes.
|
111
|
-
def attr_protected(*args)
|
112
|
-
options = args.extract_options!
|
113
|
-
role = options[:as] || :default
|
114
|
-
|
115
|
-
self._protected_attributes = protected_attributes_configs.dup
|
116
|
-
|
117
|
-
Array.wrap(role).each do |name|
|
118
|
-
self._protected_attributes[name] = self.protected_attributes(name) + args
|
119
|
-
end
|
120
|
-
|
121
|
-
self._active_authorizer = self._protected_attributes
|
122
|
-
end
|
123
|
-
|
124
|
-
# Specifies a white list of model attributes that can be set via
|
125
|
-
# mass-assignment.
|
126
|
-
#
|
127
|
-
# Like +attr_protected+, a role for the attributes is optional,
|
128
|
-
# if no role is provided then :default is used. A role can be defined by
|
129
|
-
# using the :as option.
|
130
|
-
#
|
131
|
-
# This is the opposite of the +attr_protected+ macro: Mass-assignment
|
132
|
-
# will only set attributes in this list, to assign to the rest of
|
133
|
-
# attributes you can use direct writer methods. This is meant to protect
|
134
|
-
# sensitive attributes from being overwritten by malicious users
|
135
|
-
# tampering with URLs or forms. If you'd rather start from an all-open
|
136
|
-
# default and restrict attributes as needed, have a look at
|
137
|
-
# +attr_protected+.
|
138
|
-
#
|
139
|
-
# class Customer
|
140
|
-
# include ActiveModel::MassAssignmentSecurity
|
141
|
-
#
|
142
|
-
# attr_accessor :name, :credit_rating
|
143
|
-
#
|
144
|
-
# attr_accessible :name
|
145
|
-
# attr_accessible :name, :credit_rating, :as => :admin
|
146
|
-
#
|
147
|
-
# def assign_attributes(values, options = {})
|
148
|
-
# sanitize_for_mass_assignment(values, options[:as]).each do |k, v|
|
149
|
-
# send("#{k}=", v)
|
150
|
-
# end
|
151
|
-
# end
|
152
|
-
# end
|
153
|
-
#
|
154
|
-
# When using the :default role:
|
155
|
-
#
|
156
|
-
# customer = Customer.new
|
157
|
-
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :default)
|
158
|
-
# customer.name # => "David"
|
159
|
-
# customer.credit_rating # => nil
|
160
|
-
#
|
161
|
-
# customer.credit_rating = "Average"
|
162
|
-
# customer.credit_rating # => "Average"
|
163
|
-
#
|
164
|
-
# And using the :admin role:
|
165
|
-
#
|
166
|
-
# customer = Customer.new
|
167
|
-
# customer.assign_attributes({ "name" => "David", "credit_rating" => "Excellent", :last_login => 1.day.ago }, :as => :admin)
|
168
|
-
# customer.name # => "David"
|
169
|
-
# customer.credit_rating # => "Excellent"
|
170
|
-
#
|
171
|
-
# Note that using <tt>Hash#except</tt> or <tt>Hash#slice</tt> in place of
|
172
|
-
# +attr_accessible+ to sanitize attributes provides basically the same
|
173
|
-
# functionality, but it makes a bit tricky to deal with nested attributes.
|
174
|
-
def attr_accessible(*args)
|
175
|
-
options = args.extract_options!
|
176
|
-
role = options[:as] || :default
|
177
|
-
|
178
|
-
self._accessible_attributes = accessible_attributes_configs.dup
|
179
|
-
|
180
|
-
Array.wrap(role).each do |name|
|
181
|
-
self._accessible_attributes[name] = self.accessible_attributes(name) + args
|
182
|
-
end
|
183
|
-
|
184
|
-
self._active_authorizer = self._accessible_attributes
|
185
|
-
end
|
186
|
-
|
187
|
-
def protected_attributes(role = :default)
|
188
|
-
protected_attributes_configs[role]
|
189
|
-
end
|
190
|
-
|
191
|
-
def accessible_attributes(role = :default)
|
192
|
-
accessible_attributes_configs[role]
|
193
|
-
end
|
194
|
-
|
195
|
-
def active_authorizers
|
196
|
-
self._active_authorizer ||= protected_attributes_configs
|
197
|
-
end
|
198
|
-
alias active_authorizer active_authorizers
|
199
|
-
|
200
|
-
def attributes_protected_by_default
|
201
|
-
[]
|
202
|
-
end
|
203
|
-
|
204
|
-
def mass_assignment_sanitizer=(value)
|
205
|
-
self._mass_assignment_sanitizer = if value.is_a?(Symbol)
|
206
|
-
const_get(:"#{value.to_s.camelize}Sanitizer").new(self)
|
207
|
-
else
|
208
|
-
value
|
209
|
-
end
|
210
|
-
end
|
211
|
-
|
212
|
-
private
|
213
|
-
|
214
|
-
def protected_attributes_configs
|
215
|
-
self._protected_attributes ||= begin
|
216
|
-
Hash.new { |h,k| h[k] = BlackList.new(attributes_protected_by_default) }
|
217
|
-
end
|
218
|
-
end
|
219
|
-
|
220
|
-
def accessible_attributes_configs
|
221
|
-
self._accessible_attributes ||= begin
|
222
|
-
Hash.new { |h,k| h[k] = WhiteList.new }
|
223
|
-
end
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
protected
|
228
|
-
|
229
|
-
def sanitize_for_mass_assignment(attributes, role = nil)
|
230
|
-
_mass_assignment_sanitizer.sanitize(attributes, mass_assignment_authorizer(role))
|
231
|
-
end
|
232
|
-
|
233
|
-
def mass_assignment_authorizer(role)
|
234
|
-
self.class.active_authorizer[role || :default]
|
235
|
-
end
|
236
|
-
end
|
237
|
-
end
|