activemodel 3.2.22.5 → 4.0.0.beta1
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.
- 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
data/lib/active_model/errors.rb
CHANGED
@@ -1,16 +1,12 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
|
3
|
-
require 'active_support/core_ext/array/wrap'
|
4
3
|
require 'active_support/core_ext/array/conversions'
|
5
4
|
require 'active_support/core_ext/string/inflections'
|
6
|
-
require 'active_support/core_ext/object/blank'
|
7
|
-
require 'active_support/core_ext/hash/reverse_merge'
|
8
|
-
require 'active_support/ordered_hash'
|
9
5
|
|
10
6
|
module ActiveModel
|
11
|
-
# == Active Model Errors
|
7
|
+
# == Active \Model \Errors
|
12
8
|
#
|
13
|
-
# Provides a modified +
|
9
|
+
# Provides a modified +Hash+ that you can include in your object
|
14
10
|
# for handling error messages and interacting with Action Pack helpers.
|
15
11
|
#
|
16
12
|
# A minimal implementation could be:
|
@@ -57,8 +53,8 @@ module ActiveModel
|
|
57
53
|
# The above allows you to do:
|
58
54
|
#
|
59
55
|
# p = Person.new
|
60
|
-
#
|
61
|
-
#
|
56
|
+
# person.validate! # => ["can not be nil"]
|
57
|
+
# person.errors.full_messages # => ["name can not be nil"]
|
62
58
|
# # etc..
|
63
59
|
class Errors
|
64
60
|
include Enumerable
|
@@ -76,44 +72,58 @@ module ActiveModel
|
|
76
72
|
# end
|
77
73
|
def initialize(base)
|
78
74
|
@base = base
|
79
|
-
@messages =
|
75
|
+
@messages = {}
|
80
76
|
end
|
81
77
|
|
82
|
-
def initialize_dup(other)
|
78
|
+
def initialize_dup(other) # :nodoc:
|
83
79
|
@messages = other.messages.dup
|
80
|
+
super
|
84
81
|
end
|
85
82
|
|
86
|
-
#
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
copy
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# Clear the messages
|
83
|
+
# Clear the error messages.
|
84
|
+
#
|
85
|
+
# person.errors.full_messages # => ["name can not be nil"]
|
86
|
+
# person.errors.clear
|
87
|
+
# person.errors.full_messages # => []
|
96
88
|
def clear
|
97
89
|
messages.clear
|
98
90
|
end
|
99
91
|
|
100
|
-
#
|
101
|
-
|
102
|
-
|
92
|
+
# Returns +true+ if the error messages include an error for the given key
|
93
|
+
# +attribute+, +false+ otherwise.
|
94
|
+
#
|
95
|
+
# person.errors.messages # => {:name=>["can not be nil"]}
|
96
|
+
# person.errors.include?(:name) # => true
|
97
|
+
# person.errors.include?(:age) # => false
|
98
|
+
def include?(attribute)
|
99
|
+
(v = messages[attribute]) && v.any?
|
103
100
|
end
|
101
|
+
# aliases include?
|
104
102
|
alias :has_key? :include?
|
105
103
|
|
106
|
-
# Get messages for +key
|
104
|
+
# Get messages for +key+.
|
105
|
+
#
|
106
|
+
# person.errors.messages # => {:name=>["can not be nil"]}
|
107
|
+
# person.errors.get(:name) # => ["can not be nil"]
|
108
|
+
# person.errors.get(:age) # => nil
|
107
109
|
def get(key)
|
108
110
|
messages[key]
|
109
111
|
end
|
110
112
|
|
111
|
-
# Set messages for +key+ to +value
|
113
|
+
# Set messages for +key+ to +value+.
|
114
|
+
#
|
115
|
+
# person.errors.get(:name) # => ["can not be nil"]
|
116
|
+
# person.errors.set(:name, ["can't be nil"])
|
117
|
+
# person.errors.get(:name) # => ["can't be nil"]
|
112
118
|
def set(key, value)
|
113
119
|
messages[key] = value
|
114
120
|
end
|
115
121
|
|
116
|
-
# Delete messages for +key
|
122
|
+
# Delete messages for +key+. Returns the deleted messages.
|
123
|
+
#
|
124
|
+
# person.errors.get(:name) # => ["can not be nil"]
|
125
|
+
# person.errors.delete(:name) # => ["can not be nil"]
|
126
|
+
# person.errors.get(:name) # => nil
|
117
127
|
def delete(key)
|
118
128
|
messages.delete(key)
|
119
129
|
end
|
@@ -121,16 +131,16 @@ module ActiveModel
|
|
121
131
|
# When passed a symbol or a name of a method, returns an array of errors
|
122
132
|
# for the method.
|
123
133
|
#
|
124
|
-
#
|
125
|
-
#
|
134
|
+
# person.errors[:name] # => ["can not be nil"]
|
135
|
+
# person.errors['name'] # => ["can not be nil"]
|
126
136
|
def [](attribute)
|
127
137
|
get(attribute.to_sym) || set(attribute.to_sym, [])
|
128
138
|
end
|
129
139
|
|
130
140
|
# Adds to the supplied attribute the supplied error message.
|
131
141
|
#
|
132
|
-
#
|
133
|
-
#
|
142
|
+
# person.errors[:name] = "must be set"
|
143
|
+
# person.errors[:name] # => ['must be set']
|
134
144
|
def []=(attribute, error)
|
135
145
|
self[attribute] << error
|
136
146
|
end
|
@@ -139,13 +149,13 @@ module ActiveModel
|
|
139
149
|
# Yields the attribute and the error for that attribute. If the attribute
|
140
150
|
# has more than one error message, yields once for each error message.
|
141
151
|
#
|
142
|
-
#
|
143
|
-
#
|
152
|
+
# person.errors.add(:name, "can't be blank")
|
153
|
+
# person.errors.each do |attribute, error|
|
144
154
|
# # Will yield :name and "can't be blank"
|
145
155
|
# end
|
146
156
|
#
|
147
|
-
#
|
148
|
-
#
|
157
|
+
# person.errors.add(:name, "must be specified")
|
158
|
+
# person.errors.each do |attribute, error|
|
149
159
|
# # Will yield :name and "can't be blank"
|
150
160
|
# # then yield :name and "must be specified"
|
151
161
|
# end
|
@@ -157,54 +167,65 @@ module ActiveModel
|
|
157
167
|
|
158
168
|
# Returns the number of error messages.
|
159
169
|
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
#
|
170
|
+
# person.errors.add(:name, "can't be blank")
|
171
|
+
# person.errors.size # => 1
|
172
|
+
# person.errors.add(:name, "must be specified")
|
173
|
+
# person.errors.size # => 2
|
164
174
|
def size
|
165
175
|
values.flatten.size
|
166
176
|
end
|
167
177
|
|
168
|
-
# Returns all message values
|
178
|
+
# Returns all message values.
|
179
|
+
#
|
180
|
+
# person.errors.messages # => {:name=>["can not be nil", "must be specified"]}
|
181
|
+
# person.errors.values # => [["can not be nil", "must be specified"]]
|
169
182
|
def values
|
170
183
|
messages.values
|
171
184
|
end
|
172
185
|
|
173
|
-
# Returns all message keys
|
186
|
+
# Returns all message keys.
|
187
|
+
#
|
188
|
+
# person.errors.messages # => {:name=>["can not be nil", "must be specified"]}
|
189
|
+
# person.errors.keys # => [:name]
|
174
190
|
def keys
|
175
191
|
messages.keys
|
176
192
|
end
|
177
193
|
|
178
|
-
# Returns an array of error messages, with the attribute name included
|
194
|
+
# Returns an array of error messages, with the attribute name included.
|
179
195
|
#
|
180
|
-
#
|
181
|
-
#
|
182
|
-
#
|
196
|
+
# person.errors.add(:name, "can't be blank")
|
197
|
+
# person.errors.add(:name, "must be specified")
|
198
|
+
# person.errors.to_a # => ["name can't be blank", "name must be specified"]
|
183
199
|
def to_a
|
184
200
|
full_messages
|
185
201
|
end
|
186
202
|
|
187
203
|
# Returns the number of error messages.
|
188
|
-
#
|
189
|
-
#
|
190
|
-
#
|
191
|
-
#
|
204
|
+
#
|
205
|
+
# person.errors.add(:name, "can't be blank")
|
206
|
+
# person.errors.count # => 1
|
207
|
+
# person.errors.add(:name, "must be specified")
|
208
|
+
# person.errors.count # => 2
|
192
209
|
def count
|
193
210
|
to_a.size
|
194
211
|
end
|
195
212
|
|
196
|
-
# Returns true if no errors are found, false otherwise.
|
213
|
+
# Returns +true+ if no errors are found, +false+ otherwise.
|
197
214
|
# If the error message is a string it can be empty.
|
215
|
+
#
|
216
|
+
# person.errors.full_messages # => ["name can not be nil"]
|
217
|
+
# person.errors.empty? # => false
|
198
218
|
def empty?
|
199
219
|
all? { |k, v| v && v.empty? && !v.is_a?(String) }
|
200
220
|
end
|
221
|
+
# aliases empty?
|
201
222
|
alias_method :blank?, :empty?
|
202
223
|
|
203
224
|
# Returns an xml formatted representation of the Errors hash.
|
204
225
|
#
|
205
|
-
#
|
206
|
-
#
|
207
|
-
#
|
226
|
+
# person.errors.add(:name, "can't be blank")
|
227
|
+
# person.errors.add(:name, "must be specified")
|
228
|
+
# person.errors.to_xml
|
208
229
|
# # =>
|
209
230
|
# # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
|
210
231
|
# # <errors>
|
@@ -212,54 +233,106 @@ module ActiveModel
|
|
212
233
|
# # <error>name must be specified</error>
|
213
234
|
# # </errors>
|
214
235
|
def to_xml(options={})
|
215
|
-
to_a.to_xml
|
236
|
+
to_a.to_xml({ :root => "errors", :skip_types => true }.merge!(options))
|
216
237
|
end
|
217
238
|
|
218
|
-
# Returns
|
239
|
+
# Returns a Hash that can be used as the JSON representation for this
|
240
|
+
# object. You can pass the <tt>:full_messages</tt> option. This determines
|
241
|
+
# if the json object should contain full messages or not (false by default).
|
242
|
+
#
|
243
|
+
# person.as_json # => {:name=>["can not be nil"]}
|
244
|
+
# person.as_json(full_messages: true) # => {:name=>["name can not be nil"]}
|
219
245
|
def as_json(options=nil)
|
220
|
-
to_hash
|
246
|
+
to_hash(options && options[:full_messages])
|
221
247
|
end
|
222
248
|
|
223
|
-
|
224
|
-
|
249
|
+
# Returns a Hash of attributes with their error messages. If +full_messages+
|
250
|
+
# is +true+, it will contain full messages (see +full_message+).
|
251
|
+
#
|
252
|
+
# person.to_hash # => {:name=>["can not be nil"]}
|
253
|
+
# person.to_hash(true) # => {:name=>["name can not be nil"]}
|
254
|
+
def to_hash(full_messages = false)
|
255
|
+
if full_messages
|
256
|
+
messages = {}
|
257
|
+
self.messages.each do |attribute, array|
|
258
|
+
messages[attribute] = array.map { |message| full_message(attribute, message) }
|
259
|
+
end
|
260
|
+
messages
|
261
|
+
else
|
262
|
+
self.messages.dup
|
263
|
+
end
|
225
264
|
end
|
226
265
|
|
227
|
-
# Adds +message+ to the error messages on +attribute+. More than one error
|
228
|
-
# +attribute+.
|
229
|
-
#
|
266
|
+
# Adds +message+ to the error messages on +attribute+. More than one error
|
267
|
+
# can be added to the same +attribute+. If no +message+ is supplied,
|
268
|
+
# <tt>:invalid</tt> is assumed.
|
269
|
+
#
|
270
|
+
# person.errors.add(:name)
|
271
|
+
# # => ["is invalid"]
|
272
|
+
# person.errors.add(:name, 'must be implemented')
|
273
|
+
# # => ["is invalid", "must be implemented"]
|
230
274
|
#
|
231
|
-
#
|
232
|
-
#
|
275
|
+
# person.errors.messages
|
276
|
+
# # => {:name=>["must be implemented", "is invalid"]}
|
277
|
+
#
|
278
|
+
# If +message+ is a symbol, it will be translated using the appropriate
|
279
|
+
# scope (see +generate_message+).
|
280
|
+
#
|
281
|
+
# If +message+ is a proc, it will be called, allowing for things like
|
282
|
+
# <tt>Time.now</tt> to be used within an error.
|
283
|
+
#
|
284
|
+
# If the <tt>:strict</tt> option is set to true will raise
|
285
|
+
# ActiveModel::StrictValidationFailed instead of adding the error.
|
286
|
+
# <tt>:strict</tt> option can also be set to any other exception.
|
287
|
+
#
|
288
|
+
# person.errors.add(:name, nil, strict: true)
|
289
|
+
# # => ActiveModel::StrictValidationFailed: name is invalid
|
290
|
+
# person.errors.add(:name, nil, strict: NameIsInvalid)
|
291
|
+
# # => NameIsInvalid: name is invalid
|
292
|
+
#
|
293
|
+
# person.errors.messages # => {}
|
233
294
|
def add(attribute, message = nil, options = {})
|
234
295
|
message = normalize_message(attribute, message, options)
|
235
|
-
if options[:strict]
|
236
|
-
|
296
|
+
if exception = options[:strict]
|
297
|
+
exception = ActiveModel::StrictValidationFailed if exception == true
|
298
|
+
raise exception, full_message(attribute, message)
|
237
299
|
end
|
238
300
|
|
239
301
|
self[attribute] << message
|
240
302
|
end
|
241
303
|
|
242
|
-
# Will add an error message to each of the attributes in +attributes+
|
304
|
+
# Will add an error message to each of the attributes in +attributes+
|
305
|
+
# that is empty.
|
306
|
+
#
|
307
|
+
# person.errors.add_on_empty(:name)
|
308
|
+
# person.errors.messages
|
309
|
+
# # => {:name=>["can't be empty"]}
|
243
310
|
def add_on_empty(attributes, options = {})
|
244
|
-
|
311
|
+
Array(attributes).each do |attribute|
|
245
312
|
value = @base.send(:read_attribute_for_validation, attribute)
|
246
313
|
is_empty = value.respond_to?(:empty?) ? value.empty? : false
|
247
314
|
add(attribute, :empty, options) if value.nil? || is_empty
|
248
315
|
end
|
249
316
|
end
|
250
317
|
|
251
|
-
# Will add an error message to each of the attributes in +attributes+ that
|
318
|
+
# Will add an error message to each of the attributes in +attributes+ that
|
319
|
+
# is blank (using Object#blank?).
|
320
|
+
#
|
321
|
+
# person.errors.add_on_blank(:name)
|
322
|
+
# person.errors.messages
|
323
|
+
# # => {:name=>["can't be blank"]}
|
252
324
|
def add_on_blank(attributes, options = {})
|
253
|
-
|
325
|
+
Array(attributes).each do |attribute|
|
254
326
|
value = @base.send(:read_attribute_for_validation, attribute)
|
255
327
|
add(attribute, :blank, options) if value.blank?
|
256
328
|
end
|
257
329
|
end
|
258
330
|
|
259
|
-
# Returns true if an error on the attribute with the given message is
|
260
|
-
# +message+ is treated the same as for +add+.
|
261
|
-
#
|
262
|
-
#
|
331
|
+
# Returns +true+ if an error on the attribute with the given message is
|
332
|
+
# present, +false+ otherwise. +message+ is treated the same as for +add+.
|
333
|
+
#
|
334
|
+
# person.errors.add :name, :blank
|
335
|
+
# person.errors.added? :name, :blank # => true
|
263
336
|
def added?(attribute, message = nil, options = {})
|
264
337
|
message = normalize_message(attribute, message, options)
|
265
338
|
self[attribute].include? message
|
@@ -267,25 +340,24 @@ module ActiveModel
|
|
267
340
|
|
268
341
|
# Returns all the full error messages in an array.
|
269
342
|
#
|
270
|
-
# class
|
343
|
+
# class Person
|
271
344
|
# validates_presence_of :name, :address, :email
|
272
|
-
# validates_length_of :name, :
|
345
|
+
# validates_length_of :name, in: 5..30
|
273
346
|
# end
|
274
347
|
#
|
275
|
-
#
|
276
|
-
#
|
277
|
-
#
|
348
|
+
# person = Person.create(address: '123 First St.')
|
349
|
+
# person.errors.full_messages
|
350
|
+
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
|
278
351
|
def full_messages
|
279
352
|
map { |attribute, message| full_message(attribute, message) }
|
280
353
|
end
|
281
354
|
|
282
355
|
# Returns a full message for a given attribute.
|
283
356
|
#
|
284
|
-
#
|
285
|
-
# "Name is invalid"
|
357
|
+
# person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
|
286
358
|
def full_message(attribute, message)
|
287
359
|
return message if attribute == :base
|
288
|
-
attr_name = attribute.to_s.
|
360
|
+
attr_name = attribute.to_s.tr('.', '_').humanize
|
289
361
|
attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
|
290
362
|
I18n.t(:"errors.format", {
|
291
363
|
:default => "%{attribute} %{message}",
|
@@ -298,10 +370,11 @@ module ActiveModel
|
|
298
370
|
# (<tt>activemodel.errors.messages</tt>).
|
299
371
|
#
|
300
372
|
# Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
|
301
|
-
# if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if
|
302
|
-
# there also, it returns the translation of the default message
|
303
|
-
# (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model
|
304
|
-
# translated attribute name and the value are available for
|
373
|
+
# if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if
|
374
|
+
# that is not there also, it returns the translation of the default message
|
375
|
+
# (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model
|
376
|
+
# name, translated attribute name and the value are available for
|
377
|
+
# interpolation.
|
305
378
|
#
|
306
379
|
# When using inheritance in your models, it will check all the inherited
|
307
380
|
# models too, but only if the model itself hasn't been found. Say you have
|
@@ -317,7 +390,6 @@ module ActiveModel
|
|
317
390
|
# * <tt>activemodel.errors.messages.blank</tt>
|
318
391
|
# * <tt>errors.attributes.title.blank</tt>
|
319
392
|
# * <tt>errors.messages.blank</tt>
|
320
|
-
#
|
321
393
|
def generate_message(attribute, type = :invalid, options = {})
|
322
394
|
type = options.delete(:message) if options[:message].is_a?(Symbol)
|
323
395
|
|
@@ -346,7 +418,7 @@ module ActiveModel
|
|
346
418
|
:model => @base.class.model_name.human,
|
347
419
|
:attribute => @base.class.human_attribute_name(attribute),
|
348
420
|
:value => value
|
349
|
-
}.merge(options)
|
421
|
+
}.merge!(options)
|
350
422
|
|
351
423
|
I18n.translate(key, options)
|
352
424
|
end
|
@@ -355,9 +427,10 @@ module ActiveModel
|
|
355
427
|
def normalize_message(attribute, message, options)
|
356
428
|
message ||= :invalid
|
357
429
|
|
358
|
-
|
430
|
+
case message
|
431
|
+
when Symbol
|
359
432
|
generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
|
360
|
-
|
433
|
+
when Proc
|
361
434
|
message.call
|
362
435
|
else
|
363
436
|
message
|
@@ -365,6 +438,21 @@ module ActiveModel
|
|
365
438
|
end
|
366
439
|
end
|
367
440
|
|
441
|
+
# Raised when a validation cannot be corrected by end users and are considered
|
442
|
+
# exceptional.
|
443
|
+
#
|
444
|
+
# class Person
|
445
|
+
# include ActiveModel::Validations
|
446
|
+
#
|
447
|
+
# attr_accessor :name
|
448
|
+
#
|
449
|
+
# validates_presence_of :name, strict: true
|
450
|
+
# end
|
451
|
+
#
|
452
|
+
# person = Person.new
|
453
|
+
# person.name = nil
|
454
|
+
# person.valid?
|
455
|
+
# # => ActiveModel::StrictValidationFailed: Name can't be blank
|
368
456
|
class StrictValidationFailed < StandardError
|
369
457
|
end
|
370
458
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module ActiveModel
|
2
|
+
# Raised when forbidden attributes are used for mass assignment.
|
3
|
+
#
|
4
|
+
# class Person < ActiveRecord::Base
|
5
|
+
# end
|
6
|
+
#
|
7
|
+
# params = ActionController::Parameters.new(name: 'Bob')
|
8
|
+
# Person.new(params)
|
9
|
+
# # => ActiveModel::ForbiddenAttributesError
|
10
|
+
#
|
11
|
+
# params.permit!
|
12
|
+
# Person.new(params)
|
13
|
+
# # => #<Person id: nil, name: "Bob">
|
14
|
+
class ForbiddenAttributesError < StandardError
|
15
|
+
end
|
16
|
+
|
17
|
+
module ForbiddenAttributesProtection # :nodoc:
|
18
|
+
protected
|
19
|
+
def sanitize_for_mass_assignment(attributes)
|
20
|
+
if attributes.respond_to?(:permitted?) && !attributes.permitted?
|
21
|
+
raise ActiveModel::ForbiddenAttributesError
|
22
|
+
else
|
23
|
+
attributes
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|