yssk22-couch_resource 0.1.0
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/LICENSE +2 -0
- data/MIT_LICENSE +8 -0
- data/README.rdoc +7 -0
- data/lib/couch_resource.rb +25 -0
- data/lib/couch_resource/base.rb +705 -0
- data/lib/couch_resource/callbacks.rb +103 -0
- data/lib/couch_resource/connection.rb +194 -0
- data/lib/couch_resource/error.rb +3 -0
- data/lib/couch_resource/struct.rb +340 -0
- data/lib/couch_resource/validations.rb +520 -0
- data/lib/couch_resource/view.rb +228 -0
- data/test/test_base.rb +384 -0
- data/test/test_callbacks.rb +115 -0
- data/test/test_connection.rb +39 -0
- data/test/test_struct.rb +332 -0
- data/test/test_validations.rb +186 -0
- metadata +70 -0
@@ -0,0 +1,520 @@
|
|
1
|
+
#
|
2
|
+
# This file is based on active_record/validations.rb (ActiveRecord 2.1.0)
|
3
|
+
# and customize some sentences to work as CouchResource validations.
|
4
|
+
#
|
5
|
+
require File.join(File.dirname(__FILE__), "struct")
|
6
|
+
require File.join(File.dirname(__FILE__), "error")
|
7
|
+
|
8
|
+
module CouchResource
|
9
|
+
|
10
|
+
# Raised by save! and create! when the record is invalid.
|
11
|
+
# Use the record method to retrieve the record which did not validate.
|
12
|
+
class RecordInvalid < CouchResourceError
|
13
|
+
attr_reader :record
|
14
|
+
def initialize(record)
|
15
|
+
@record = record
|
16
|
+
super("Validation failed: #{@record.errors.full_messages.join(", ")}")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# CouchResource::Errors is the completely same as ActiveRecord::Errors
|
21
|
+
class Errors
|
22
|
+
include Enumerable
|
23
|
+
|
24
|
+
def initialize(base) # :nodoc:
|
25
|
+
@base, @errors = base, {}
|
26
|
+
end
|
27
|
+
|
28
|
+
@@default_error_messages = {
|
29
|
+
:inclusion => "is not included in the list",
|
30
|
+
:exclusion => "is reserved",
|
31
|
+
:invalid => "is invalid",
|
32
|
+
:confirmation => "doesn't match confirmation",
|
33
|
+
:accepted => "must be accepted",
|
34
|
+
:empty => "can't be empty",
|
35
|
+
:blank => "can't be blank",
|
36
|
+
:too_long => "is too long (maximum is %d characters)",
|
37
|
+
:too_short => "is too short (minimum is %d characters)",
|
38
|
+
:wrong_length => "is the wrong length (should be %d characters)",
|
39
|
+
:taken => "has already been taken",
|
40
|
+
:not_a_number => "is not a number",
|
41
|
+
:greater_than => "must be greater than %d",
|
42
|
+
:greater_than_or_equal_to => "must be greater than or equal to %d",
|
43
|
+
:equal_to => "must be equal to %d",
|
44
|
+
:less_than => "must be less than %d",
|
45
|
+
:less_than_or_equal_to => "must be less than or equal to %d",
|
46
|
+
:odd => "must be odd",
|
47
|
+
:even => "must be even",
|
48
|
+
:children => "is not valid" # append for object or array
|
49
|
+
}
|
50
|
+
|
51
|
+
cattr_accessor :default_error_messages
|
52
|
+
|
53
|
+
def add_to_base(msg)
|
54
|
+
add(:base, msg)
|
55
|
+
end
|
56
|
+
|
57
|
+
def add(attribute, msg = @@default_error_messages[:invalid])
|
58
|
+
@errors[attribute.to_s] = [] if @errors[attribute.to_s].nil?
|
59
|
+
@errors[attribute.to_s] << msg
|
60
|
+
end
|
61
|
+
|
62
|
+
def add_on_empty(attributes, msg = @@default_error_messages[:empty])
|
63
|
+
for attr in [attributes].flatten
|
64
|
+
value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
|
65
|
+
is_empty = value.respond_to?("empty?") ? value.empty? : false
|
66
|
+
add(attr, msg) unless !value.nil? && !is_empty
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def add_on_blank(attributes, msg = @@default_error_messages[:blank])
|
71
|
+
for attr in [attributes].flatten
|
72
|
+
value = @base.respond_to?(attr.to_s) ? @base.send(attr.to_s) : @base[attr.to_s]
|
73
|
+
add(attr, msg) if value.blank?
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def invalid?(attribute)
|
78
|
+
!@errors[attribute.to_s].nil?
|
79
|
+
end
|
80
|
+
|
81
|
+
def on(attribute)
|
82
|
+
errors = @errors[attribute.to_s]
|
83
|
+
return nil if errors.nil?
|
84
|
+
errors.size == 1 ? errors.first : errors
|
85
|
+
end
|
86
|
+
|
87
|
+
alias :[] :on
|
88
|
+
|
89
|
+
def on_base
|
90
|
+
on(:base)
|
91
|
+
end
|
92
|
+
|
93
|
+
def each
|
94
|
+
@errors.each_key { |attr| @errors[attr].each { |msg| yield attr, msg } }
|
95
|
+
end
|
96
|
+
|
97
|
+
def each_full
|
98
|
+
full_messages.each { |msg| yield msg }
|
99
|
+
end
|
100
|
+
|
101
|
+
def full_messages
|
102
|
+
full_messages = []
|
103
|
+
|
104
|
+
@errors.each_key do |attr|
|
105
|
+
@errors[attr].each do |msg|
|
106
|
+
next if msg.nil?
|
107
|
+
if attr == "base"
|
108
|
+
full_messages << msg
|
109
|
+
else
|
110
|
+
full_messages << @base.class.human_attribute_name(attr) + " " + msg
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
full_messages
|
115
|
+
end
|
116
|
+
|
117
|
+
def empty?
|
118
|
+
@errors.empty?
|
119
|
+
end
|
120
|
+
|
121
|
+
def clear
|
122
|
+
@errors = {}
|
123
|
+
end
|
124
|
+
|
125
|
+
def size
|
126
|
+
@errors.values.inject(0) { |error_count, attribute| error_count + attribute.size }
|
127
|
+
end
|
128
|
+
|
129
|
+
alias_method :count, :size
|
130
|
+
alias_method :length, :size
|
131
|
+
|
132
|
+
def to_xml(options={})
|
133
|
+
options[:root] ||= "errors"
|
134
|
+
options[:indent] ||= 2
|
135
|
+
options[:builder] ||= Builder::XmlMarkup.new(:indent => options[:indent])
|
136
|
+
|
137
|
+
options[:builder].instruct! unless options.delete(:skip_instruct)
|
138
|
+
options[:builder].errors do |e|
|
139
|
+
|
140
|
+
full_messages.each { |msg| e.error(msg) }
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def to_json
|
145
|
+
self.to_hash.to_json
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_hash
|
149
|
+
array = []
|
150
|
+
@errors.each_key do |attr|
|
151
|
+
@errors[attr].each do |msg|
|
152
|
+
next if msg.nil?
|
153
|
+
if attr == "base"
|
154
|
+
array << { :message => msg }
|
155
|
+
else
|
156
|
+
array << {
|
157
|
+
:message => @base.class.human_attribute_name(attr) + " " + msg,
|
158
|
+
:attr => attr
|
159
|
+
}
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
{ :errors => array }
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
module Validations
|
168
|
+
VALIDATIONS = %w( validate validate_on_create validate_on_update )
|
169
|
+
|
170
|
+
def self.included(base)
|
171
|
+
base.send(:extend, ClassMethods)
|
172
|
+
base.send(:include, InstanceMethods)
|
173
|
+
base.send(:include, ActiveSupport::Callbacks)
|
174
|
+
base.define_callbacks *VALIDATIONS
|
175
|
+
end
|
176
|
+
|
177
|
+
module ClassMethods
|
178
|
+
DEFAULT_VALIDATION_OPTIONS = {
|
179
|
+
:on => :save,
|
180
|
+
:allow_nil => false,
|
181
|
+
:allow_blank => false,
|
182
|
+
:message => nil
|
183
|
+
}.freeze
|
184
|
+
|
185
|
+
ALL_RANGE_OPTIONS = [ :is, :within, :in, :minimum, :maximum ].freeze
|
186
|
+
ALL_NUMERICALITY_CHECKS = {
|
187
|
+
:greater_than => '>', :greater_than_or_equal_to => '>=',
|
188
|
+
:equal_to => '==', :less_than => '<', :less_than_or_equal_to => '<=',
|
189
|
+
:odd => 'odd?', :even => 'even?' }.freeze
|
190
|
+
|
191
|
+
# This method is the same as ActiveRecord::Validations.validates_each(*attr)
|
192
|
+
#
|
193
|
+
# class Person
|
194
|
+
# string :first_name, :validates => {
|
195
|
+
# [:each,{
|
196
|
+
# :proc => Proc.new do |record, attr, value|
|
197
|
+
# record.errors.add attr, "starts with z." if value[0] == ?z
|
198
|
+
# end
|
199
|
+
# }]
|
200
|
+
# end
|
201
|
+
#
|
202
|
+
# or
|
203
|
+
#
|
204
|
+
# class Person
|
205
|
+
# string :first_name
|
206
|
+
# validates_each :first_name do |record, attr, value|
|
207
|
+
# record.errors.add attr, "starts with z." if value[0] == ?z
|
208
|
+
# end
|
209
|
+
# end
|
210
|
+
def validates_each(*attrs)
|
211
|
+
options = attrs.extract_options!.symbolize_keys
|
212
|
+
attrs = attrs.flatten
|
213
|
+
|
214
|
+
send(validation_method(options[:on] || :save), options) do |record|
|
215
|
+
attrs.each do |attr|
|
216
|
+
value = record.get_attribute(attr)
|
217
|
+
next if (value.nil? && options[:allow_nil]) || (value.blank? && options[:allow_blank])
|
218
|
+
yield record, attr, value
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# This method is the same as ActiveRecord::Validations.vaildates_confirmation_of(*attr_names)
|
224
|
+
#
|
225
|
+
# class Person
|
226
|
+
# string :password, :validates => [:confirmation_of]
|
227
|
+
# end
|
228
|
+
#
|
229
|
+
# or
|
230
|
+
#
|
231
|
+
# class Person
|
232
|
+
# string :password
|
233
|
+
# validates_confirmation_of :password
|
234
|
+
# end
|
235
|
+
def validates_confirmation_of(*attr_names)
|
236
|
+
configuration = {
|
237
|
+
:message => CouchResource::Errors.default_error_messages[:confirmation],
|
238
|
+
:on => :save
|
239
|
+
}
|
240
|
+
configuration.update(attr_names.extract_options!)
|
241
|
+
|
242
|
+
attr_accessor(*(attr_names.map { |n| "#{n}_confirmation" }))
|
243
|
+
|
244
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
245
|
+
unless record.send("#{attr_name}_confirmation").nil? or value == record.send("#{attr_name}_confirmation")
|
246
|
+
record.errors.add(attr_name, configuration[:message])
|
247
|
+
end
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
# This method is the same as ActiveRecord::Validations.vaildates_confirmation_of(*attr_names)
|
252
|
+
# This method is not implemented because the validator works for only virtual attributes.
|
253
|
+
def validates_acceptance_of
|
254
|
+
raise "Not Implemented"
|
255
|
+
end
|
256
|
+
|
257
|
+
# This method is the same as ActiveRecord::Validations.vaildates_presense_of(*attr_names)
|
258
|
+
#
|
259
|
+
# class Person
|
260
|
+
# string :first_name, :validates => [:presense_of]
|
261
|
+
# end
|
262
|
+
#
|
263
|
+
# or
|
264
|
+
#
|
265
|
+
# class Person
|
266
|
+
# string :first_name
|
267
|
+
# validates_presense_of :first_name
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
def validates_presense_of(*attr_names)
|
271
|
+
configuration = { :message => CouchResource::Errors.default_error_messages[:blank], :on => :save }
|
272
|
+
configuration.update(attr_names.extract_options!)
|
273
|
+
|
274
|
+
# can't use validates_each here, because it cannot cope with nonexistent attributes,
|
275
|
+
# while errors.add_on_empty can
|
276
|
+
send(validation_method(configuration[:on]), configuration) do |record|
|
277
|
+
record.errors.add_on_blank(attr_names, configuration[:message])
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
|
282
|
+
# This method is the same as ActiveRecord::Validations.vaildates_length_of(*attrs)
|
283
|
+
# class Person
|
284
|
+
# string :first_name, :validates => [
|
285
|
+
# [:lenfth_of, {:minimum => 1, :maximum => 16}]
|
286
|
+
# ]
|
287
|
+
# end
|
288
|
+
#
|
289
|
+
# or
|
290
|
+
#
|
291
|
+
# class Person
|
292
|
+
# string :first_name
|
293
|
+
# validates_presense_of :first_name, :minumum => 1, :maximum => 16
|
294
|
+
# end
|
295
|
+
def validates_length_of(*attrs)
|
296
|
+
# Merge given options with defaults.
|
297
|
+
options = {
|
298
|
+
:too_long => CouchResource::Errors.default_error_messages[:too_long],
|
299
|
+
:too_short => CouchResource::Errors.default_error_messages[:too_short],
|
300
|
+
:wrong_length => CouchResource::Errors.default_error_messages[:wrong_length]
|
301
|
+
}.merge(DEFAULT_VALIDATION_OPTIONS)
|
302
|
+
options.update(attrs.extract_options!.symbolize_keys)
|
303
|
+
|
304
|
+
# Ensure that one and only one range option is specified.
|
305
|
+
range_options = ALL_RANGE_OPTIONS & options.keys
|
306
|
+
case range_options.size
|
307
|
+
when 0
|
308
|
+
raise ArgumentError, 'Range unspecified. Specify the :within, :maximum, :minimum, or :is option.'
|
309
|
+
when 1
|
310
|
+
# Valid number of options; do nothing.
|
311
|
+
else
|
312
|
+
raise ArgumentError, 'Too many range options specified. Choose only one.'
|
313
|
+
end
|
314
|
+
|
315
|
+
# Get range option and value.
|
316
|
+
option = range_options.first
|
317
|
+
option_value = options[range_options.first]
|
318
|
+
|
319
|
+
case option
|
320
|
+
when :within, :in
|
321
|
+
raise ArgumentError, ":#{option} must be a Range" unless option_value.is_a?(Range)
|
322
|
+
|
323
|
+
too_short = options[:too_short] % option_value.begin
|
324
|
+
too_long = options[:too_long] % option_value.end
|
325
|
+
|
326
|
+
validates_each(attrs, options) do |record, attr, value|
|
327
|
+
value = value.split(//) if value.kind_of?(String)
|
328
|
+
if value.nil? or value.size < option_value.begin
|
329
|
+
record.errors.add(attr, too_short)
|
330
|
+
elsif value.size > option_value.end
|
331
|
+
record.errors.add(attr, too_long)
|
332
|
+
end
|
333
|
+
end
|
334
|
+
when :is, :minimum, :maximum
|
335
|
+
raise ArgumentError, ":#{option} must be a nonnegative Integer" unless option_value.is_a?(Integer) and option_value >= 0
|
336
|
+
|
337
|
+
# Declare different validations per option.
|
338
|
+
validity_checks = { :is => "==", :minimum => ">=", :maximum => "<=" }
|
339
|
+
message_options = { :is => :wrong_length, :minimum => :too_short, :maximum => :too_long }
|
340
|
+
|
341
|
+
message = (options[:message] || options[message_options[option]]) % option_value
|
342
|
+
|
343
|
+
validates_each(attrs, options) do |record, attr, value|
|
344
|
+
value = value.split(//) if value.kind_of?(String)
|
345
|
+
record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]
|
346
|
+
end
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
alias_method :validates_size_of, :validates_length_of
|
351
|
+
|
352
|
+
# This method is the same as ActiveRecord::Validations.vaildates_uniqueness_of(*attr_names)
|
353
|
+
# This method is not implemented because you should define a new design document for validation of uniqueness to validate.
|
354
|
+
def validates_uniqueness_of
|
355
|
+
raise "Not Implemented"
|
356
|
+
end
|
357
|
+
|
358
|
+
# This method is the same as ActiveRecord::Validations.vaildates_format_of(*attr_names)
|
359
|
+
def validates_format_of(*attr_names)
|
360
|
+
configuration = { :message => CouchResource::Errors.default_error_messages[:invalid], :on => :save, :with => nil }
|
361
|
+
configuration.update(attr_names.extract_options!)
|
362
|
+
|
363
|
+
raise(ArgumentError, "A regular expression must be supplied as the :with option of the configuration hash") unless configuration[:with].is_a?(Regexp)
|
364
|
+
|
365
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
366
|
+
record.errors.add(attr_name, configuration[:message] % value) unless value.to_s =~ configuration[:with]
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
# This method is the same as ActiveRecord::Validations.vaildates_inclusion_of(*attr_names)
|
371
|
+
def validates_inclusion_of(*attr_names)
|
372
|
+
configuration = { :message => CouchResource::Errors.default_error_messages[:inclusion], :on => :save }
|
373
|
+
configuration.update(attr_names.extract_options!)
|
374
|
+
|
375
|
+
enum = configuration[:in] || configuration[:within]
|
376
|
+
|
377
|
+
raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?")
|
378
|
+
|
379
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
380
|
+
record.errors.add(attr_name, configuration[:message] % value) unless enum.include?(value)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
# This method is the same as ActiveRecord::Validations.vaildates_exclusion_of(*attr_names)
|
385
|
+
def validates_exclusion_of(*attr_names)
|
386
|
+
configuration = { :message => CouchResource::Errors.default_error_messages[:exclusion], :on => :save }
|
387
|
+
configuration.update(attr_names.extract_options!)
|
388
|
+
|
389
|
+
enum = configuration[:in] || configuration[:within]
|
390
|
+
|
391
|
+
raise(ArgumentError, "An object with the method include? is required must be supplied as the :in option of the configuration hash") unless enum.respond_to?("include?")
|
392
|
+
|
393
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
394
|
+
record.errors.add(attr_name, configuration[:message] % value) if enum.include?(value)
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
# This method is the same as ActiveRecord::Validations.vaildates_numericality_of(*attr_names)
|
399
|
+
def validates_numericality_of(*attr_names)
|
400
|
+
configuration = { :on => :save, :only_integer => false, :allow_nil => false }
|
401
|
+
configuration.update(attr_names.extract_options!)
|
402
|
+
|
403
|
+
|
404
|
+
numericality_options = ALL_NUMERICALITY_CHECKS.keys & configuration.keys
|
405
|
+
|
406
|
+
(numericality_options - [ :odd, :even ]).each do |option|
|
407
|
+
raise ArgumentError, ":#{option} must be a number" unless configuration[option].is_a?(Numeric)
|
408
|
+
end
|
409
|
+
|
410
|
+
validates_each(attr_names,configuration) do |record, attr_name, value|
|
411
|
+
raw_value = record.send("#{attr_name}_before_type_cast") || value
|
412
|
+
|
413
|
+
next if configuration[:allow_nil] and raw_value.nil?
|
414
|
+
|
415
|
+
if configuration[:only_integer]
|
416
|
+
unless raw_value.to_s =~ /\A[+-]?\d+\Z/
|
417
|
+
record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number])
|
418
|
+
next
|
419
|
+
end
|
420
|
+
raw_value = raw_value.to_i
|
421
|
+
else
|
422
|
+
begin
|
423
|
+
raw_value = Kernel.Float(raw_value.to_s)
|
424
|
+
rescue ArgumentError, TypeError
|
425
|
+
record.errors.add(attr_name, configuration[:message] || ActiveRecord::Errors.default_error_messages[:not_a_number])
|
426
|
+
next
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
numericality_options.each do |option|
|
431
|
+
case option
|
432
|
+
when :odd, :even
|
433
|
+
record.errors.add(attr_name, configuration[:message] || CouchResource::Errors.default_error_messages[option]) unless raw_value.to_i.method(ALL_NUMERICALITY_CHECKS[option])[]
|
434
|
+
else
|
435
|
+
message = configuration[:message] || CouchResource::Errors.default_error_messages[option]
|
436
|
+
message = message % configuration[option] if configuration[option]
|
437
|
+
record.errors.add(attr_name, message) unless raw_value.method(ALL_NUMERICALITY_CHECKS[option])[configuration[option]]
|
438
|
+
end
|
439
|
+
end
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
# This method is original for CouchResource validation to validate child object in this class.
|
444
|
+
# class Person
|
445
|
+
# object :children, :is_a => Children, :validates => [
|
446
|
+
# [:children_of, {:on => :create, :allow_nil => true }]
|
447
|
+
# ]
|
448
|
+
# end
|
449
|
+
def validates_children_of(*attr_names)
|
450
|
+
configuration = { :message => CouchResource::Errors.default_error_messages[:children], :on => :save }
|
451
|
+
configuration.update(attr_names.extract_options!)
|
452
|
+
validates_each(attr_names, configuration) do |record, attr_name, value|
|
453
|
+
if value.respond_to?(:valid?)
|
454
|
+
record.errors.add(attr_name, configuration[:message] % value) unless value.valid?
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
private
|
460
|
+
def validation_method(on)
|
461
|
+
case on
|
462
|
+
when :save then :validate
|
463
|
+
when :create then :validate_on_create
|
464
|
+
when :update then :validate_on_update
|
465
|
+
end
|
466
|
+
end
|
467
|
+
end
|
468
|
+
|
469
|
+
module InstanceMethods
|
470
|
+
def errors
|
471
|
+
@errors ||= Errors.new(self)
|
472
|
+
end
|
473
|
+
|
474
|
+
def valid?
|
475
|
+
errors.clear
|
476
|
+
|
477
|
+
run_callbacks(:validate)
|
478
|
+
validate
|
479
|
+
# validate the object only which has #new? method.
|
480
|
+
if respond_to?(:new?)
|
481
|
+
if new?
|
482
|
+
run_callbacks(:validate_on_create)
|
483
|
+
validate_on_create
|
484
|
+
else
|
485
|
+
run_callbacks(:validate_on_update)
|
486
|
+
validate_on_update
|
487
|
+
end
|
488
|
+
end
|
489
|
+
|
490
|
+
errors.empty?
|
491
|
+
end
|
492
|
+
|
493
|
+
def save_with_validation(perform_validation=true)
|
494
|
+
if perform_validation && valid? || !perform_validation
|
495
|
+
save_without_validation
|
496
|
+
else
|
497
|
+
false
|
498
|
+
end
|
499
|
+
end
|
500
|
+
|
501
|
+
def save_with_validation!
|
502
|
+
if valid?
|
503
|
+
save_without_validation!
|
504
|
+
else
|
505
|
+
raise RecordInvalid.new(self)
|
506
|
+
end
|
507
|
+
end
|
508
|
+
|
509
|
+
protected
|
510
|
+
def validate
|
511
|
+
end
|
512
|
+
|
513
|
+
def validate_on_create
|
514
|
+
end
|
515
|
+
|
516
|
+
def validate_on_update
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|