ezframe 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/asset/html/index.html +1 -0
- data/asset/js/ezframe.js +49 -20
- data/exe/check_column_yml +64 -0
- data/exe/create_table +7 -4
- data/exe/dbmigrate +65 -14
- data/ezframe.gemspec +10 -11
- data/lib/ezframe.rb +2 -1
- data/lib/ezframe/auth.rb +33 -28
- data/lib/ezframe/column_set.rb +261 -97
- data/lib/ezframe/column_type.rb +207 -63
- data/lib/ezframe/config.rb +20 -3
- data/lib/ezframe/controller.rb +19 -16
- data/lib/ezframe/database.rb +162 -50
- data/lib/ezframe/editor.rb +7 -7
- data/lib/ezframe/ht.rb +21 -16
- data/lib/ezframe/html.rb +20 -19
- data/lib/ezframe/japanese_utils.rb +10 -0
- data/lib/ezframe/jquery-ui.rb +29 -0
- data/lib/ezframe/loader.rb +4 -4
- data/lib/ezframe/logger.rb +39 -0
- data/lib/ezframe/materialize.rb +5 -8
- data/lib/ezframe/message.rb +1 -1
- data/lib/ezframe/page_base.rb +27 -18
- data/lib/ezframe/route.rb +26 -28
- data/lib/ezframe/template.rb +2 -2
- data/lib/ezframe/util.rb +4 -6
- data/lib/ezframe/version.rb +1 -1
- metadata +32 -44
- data/asset/js/materialize.min.js +0 -6
- data/asset/js/mymaterialize.js +0 -38
- data/lib/ezframe/model.rb +0 -52
data/lib/ezframe/column_type.rb
CHANGED
@@ -9,8 +9,6 @@ module Ezframe
|
|
9
9
|
return nil unless key
|
10
10
|
upper = Object.const_get("Ezframe")
|
11
11
|
key_camel = "#{key}_type".to_camel
|
12
|
-
# puts "get_class: #{key_camel}"
|
13
|
-
# puts "const_get: #{upper.const_get(key_camel).inspect}"
|
14
12
|
if upper.const_defined?(key_camel)
|
15
13
|
return upper.const_get(key_camel)
|
16
14
|
end
|
@@ -38,6 +36,10 @@ module Ezframe
|
|
38
36
|
@attribute[:label]
|
39
37
|
end
|
40
38
|
|
39
|
+
def type
|
40
|
+
@attribute[:type]
|
41
|
+
end
|
42
|
+
|
41
43
|
def value(_situation = nil)
|
42
44
|
@value
|
43
45
|
end
|
@@ -58,12 +60,6 @@ module Ezframe
|
|
58
60
|
nil
|
59
61
|
end
|
60
62
|
|
61
|
-
def form_html(opts = {})
|
62
|
-
form_h = form(opts)
|
63
|
-
return nil unless form_h
|
64
|
-
return Html.convert(form_h)
|
65
|
-
end
|
66
|
-
|
67
63
|
def view(opts = {})
|
68
64
|
return nil if no_view?
|
69
65
|
@value
|
@@ -74,7 +70,7 @@ module Ezframe
|
|
74
70
|
end
|
75
71
|
|
76
72
|
def validate(val)
|
77
|
-
if !val || val.empty?
|
73
|
+
if !val || val.to_s.empty?
|
78
74
|
if @attribute[:required] == "true"
|
79
75
|
@error = "required"
|
80
76
|
return @error
|
@@ -88,12 +84,21 @@ module Ezframe
|
|
88
84
|
end
|
89
85
|
|
90
86
|
def no_view?
|
91
|
-
return (@attribute[:hidden] && !@attribute[:force]
|
87
|
+
return (@attribute[:hidden] || @attribute[:no_view]) && !@attribute[:force]
|
92
88
|
end
|
93
89
|
|
90
|
+
# 複数のinputを持っているか?
|
94
91
|
def multi_inputs?
|
95
92
|
nil
|
96
93
|
end
|
94
|
+
|
95
|
+
# 日時をフォーマットに従って表示する
|
96
|
+
def use_view_format(format_a, tm)
|
97
|
+
fmt_a = format_a.clone
|
98
|
+
pattern = fmt_a.shift
|
99
|
+
value_a = fmt_a.map {|key| tm.send(key) }
|
100
|
+
return pattern % value_a
|
101
|
+
end
|
97
102
|
end
|
98
103
|
|
99
104
|
class TextType < TypeBase
|
@@ -101,7 +106,7 @@ module Ezframe
|
|
101
106
|
return nil unless val
|
102
107
|
val = val.dup.to_s
|
103
108
|
val.gsub!(/ /, " ")
|
104
|
-
val.gsub!(/\s+/, " ")
|
109
|
+
# val.gsub!(/\s+/, " ")
|
105
110
|
val.strip!
|
106
111
|
return val
|
107
112
|
end
|
@@ -112,15 +117,8 @@ module Ezframe
|
|
112
117
|
|
113
118
|
def form(opts = {})
|
114
119
|
return nil if no_edit? && !opts[:force]
|
115
|
-
|
116
|
-
|
117
|
-
if val && val.length>0
|
118
|
-
val.gsub!(/\n/, "<br>")
|
119
|
-
end
|
120
|
-
h = Ht.textarea(name: self.key, class: "textarea-size-#{@attribute[:size]}", label: @attribute[:label], child: val)
|
121
|
-
else
|
122
|
-
h = Ht.input(type: "text", name: self.key, label: @attribute[:label], value: @value || "")
|
123
|
-
end
|
120
|
+
h = Ht.input(type: "text", name: self.key, label: @attribute[:label], value: @value || "")
|
121
|
+
h[:class] = @attribute[:class] if @attribute[:class]
|
124
122
|
return h
|
125
123
|
end
|
126
124
|
|
@@ -131,17 +129,13 @@ module Ezframe
|
|
131
129
|
|
132
130
|
class TextareaType < TextType
|
133
131
|
def value=(val)
|
134
|
-
|
135
|
-
val.gsub!(/<br>/, "\n") if val
|
132
|
+
@value = normalize(val)
|
136
133
|
@value = val
|
137
134
|
end
|
138
135
|
|
139
136
|
def form(opts = {})
|
140
137
|
return nil if no_edit? && !opts[:force]
|
141
138
|
val = @value
|
142
|
-
if val && val.length>0
|
143
|
-
val.gsub!(/\n/, "<br>")
|
144
|
-
end
|
145
139
|
h = Ht.textarea(name: self.key, label: @attribute[:label], child: val)
|
146
140
|
h[:class] = @attribute[:class] if @attribute[:class]
|
147
141
|
return h
|
@@ -154,6 +148,13 @@ module Ezframe
|
|
154
148
|
return @value.to_i.add_comma
|
155
149
|
end
|
156
150
|
|
151
|
+
def normalize(val)
|
152
|
+
if val.is_a?(String)
|
153
|
+
val = val.tr("0-9", "0-9").strip
|
154
|
+
end
|
155
|
+
return val
|
156
|
+
end
|
157
|
+
|
157
158
|
def value=(v)
|
158
159
|
if v.nil?
|
159
160
|
default = @attribute[:default]
|
@@ -169,9 +170,7 @@ module Ezframe
|
|
169
170
|
@value = nil
|
170
171
|
return
|
171
172
|
end
|
172
|
-
|
173
|
-
v = v.tr("0-9", "0-9").strip
|
174
|
-
end
|
173
|
+
v = normalize(v)
|
175
174
|
@value = v.to_i
|
176
175
|
end
|
177
176
|
|
@@ -182,6 +181,14 @@ module Ezframe
|
|
182
181
|
return h
|
183
182
|
end
|
184
183
|
|
184
|
+
def validate(val)
|
185
|
+
return nil if !val || val.to_s.strip.empty?
|
186
|
+
unless /^\d+$/ =~ val.to_s
|
187
|
+
return :invalid_value
|
188
|
+
end
|
189
|
+
return nil
|
190
|
+
end
|
191
|
+
|
185
192
|
def db_type
|
186
193
|
return "int"
|
187
194
|
end
|
@@ -190,19 +197,38 @@ module Ezframe
|
|
190
197
|
class ForeignType < IntType
|
191
198
|
def initialize(attr = nil)
|
192
199
|
super
|
193
|
-
|
200
|
+
end
|
201
|
+
|
202
|
+
def target_table
|
203
|
+
table = @attribute[:table]
|
204
|
+
return table if table
|
205
|
+
return self.key
|
194
206
|
end
|
195
207
|
|
196
208
|
def view(opts = {})
|
197
209
|
return nil if no_view? && !opts[:force]
|
210
|
+
colkey = @attribute[:view_column]
|
211
|
+
if @value && colkey
|
212
|
+
data_h = DB::Cache[target_table.to_sym]
|
213
|
+
data = data_h[@value.to_i]
|
214
|
+
return nil unless data
|
215
|
+
return data[colkey.to_sym]
|
216
|
+
end
|
198
217
|
return nil
|
199
|
-
# dataset = @parent.parent.model.db.dataset(self.key)
|
200
|
-
# data = dataset.get(id: @value)
|
201
|
-
# return data[@attribute[:view]]
|
202
218
|
end
|
203
219
|
|
204
|
-
def form
|
205
|
-
return nil
|
220
|
+
def form(opts = {})
|
221
|
+
return nil if no_edit? && !opts[:force]
|
222
|
+
view_key = @attribute[:menu_column] || @attribute[:view_column]
|
223
|
+
data_h = DB::Cache[target_table.to_sym]
|
224
|
+
menu_a = data_h.map do |id, data|
|
225
|
+
[ data[:id], data[view_key&.to_sym] ]
|
226
|
+
end
|
227
|
+
return Ht.select(name: self.key, class: %w[browser-default], item: menu_a, value: @value)
|
228
|
+
end
|
229
|
+
|
230
|
+
def db_type
|
231
|
+
return "int"
|
206
232
|
end
|
207
233
|
end
|
208
234
|
|
@@ -218,15 +244,36 @@ module Ezframe
|
|
218
244
|
end
|
219
245
|
|
220
246
|
class PasswordType < TextType
|
247
|
+
def initialize(attr = nil)
|
248
|
+
super(attr)
|
249
|
+
@attribute[:no_view] = true
|
250
|
+
@encrypt_on_set = true
|
251
|
+
end
|
252
|
+
|
253
|
+
def form_to_value(val)
|
254
|
+
return encrypt_value(val)
|
255
|
+
end
|
256
|
+
|
257
|
+
def encrypt_value(val)
|
258
|
+
crypt = BCrypt::Password.create(val)
|
259
|
+
return crypt.to_s
|
260
|
+
end
|
261
|
+
|
262
|
+
def value_equal?(value_from_db, new_value)
|
263
|
+
@crypt = Bcrypt::Password.new(value_from_db)
|
264
|
+
return @crypt == new_value
|
265
|
+
end
|
266
|
+
|
221
267
|
def form(opts = {})
|
222
268
|
return nil if no_edit? && !opts[:force]
|
223
|
-
h = { tag: "input", type: "password", name: self.key, label: @attribute[:label], value:
|
269
|
+
h = { tag: "input", type: "password", name: self.key, label: @attribute[:label], value: "" }
|
224
270
|
h[:class] = @attribute[:class] if @attribute[:class]
|
225
271
|
return h
|
226
272
|
end
|
227
273
|
|
228
274
|
def db_value
|
229
|
-
|
275
|
+
crypt = BCrypt::Password.create(@value)
|
276
|
+
return crypt.to_s
|
230
277
|
end
|
231
278
|
end
|
232
279
|
|
@@ -234,7 +281,7 @@ module Ezframe
|
|
234
281
|
def form(opts = {})
|
235
282
|
return nil if no_edit? && !opts[:force]
|
236
283
|
# puts "selectType: #{@attribute[:item].inspect}"
|
237
|
-
h = { tag: "select", name: self.key, label: @attribute[:label], item: @attribute[:item], value: @value }
|
284
|
+
h = { tag: "select", class: %w[browser-default], name: self.key, label: @attribute[:label], item: @attribute[:item], value: @value }
|
238
285
|
h[:class] = @attribute[:class] if @attribute[:class]
|
239
286
|
return h
|
240
287
|
end
|
@@ -246,7 +293,13 @@ module Ezframe
|
|
246
293
|
def view(opts = {})
|
247
294
|
return nil if no_view? && !opts[:force]
|
248
295
|
item = @attribute[:item]
|
249
|
-
|
296
|
+
# Logger.debug("select.view: @value=#{@value}, #{@value.class}, item=#{item}, result=#{item[@value]}")
|
297
|
+
return nil unless @value
|
298
|
+
return item[@value.to_s.to_sym]
|
299
|
+
end
|
300
|
+
|
301
|
+
def validate(val)
|
302
|
+
return nil
|
250
303
|
end
|
251
304
|
end
|
252
305
|
|
@@ -272,7 +325,7 @@ module Ezframe
|
|
272
325
|
h[:type] = "text"
|
273
326
|
h[:value] = @value || ""
|
274
327
|
h[:class] = [ "datepicker" ]
|
275
|
-
h[:class].push@attribute[:class] if @attribute[:class]
|
328
|
+
h[:class].push(@attribute[:class]) if @attribute[:class]
|
276
329
|
end
|
277
330
|
return h
|
278
331
|
end
|
@@ -282,6 +335,7 @@ module Ezframe
|
|
282
335
|
end
|
283
336
|
|
284
337
|
def value
|
338
|
+
return nil if @value.nil? || (@value.is_a?(String) && @value.strip.empty?)
|
285
339
|
if @value.is_a?(Date) || @value.is_a?(Time)
|
286
340
|
return "%d-%02d-%02d" % [@value.year, @value.mon, @value.mday]
|
287
341
|
end
|
@@ -310,14 +364,18 @@ module Ezframe
|
|
310
364
|
if v.is_a?(Date) || v.is_a?(Time)
|
311
365
|
@value = v
|
312
366
|
else
|
313
|
-
|
367
|
+
Logger.info "[WARN] illegal value for date type: #{v.inspect}"
|
314
368
|
end
|
315
369
|
end
|
316
370
|
|
317
371
|
def view(opts = {})
|
318
372
|
return nil if no_view? && !opts[:force]
|
319
373
|
if @value.is_a?(Time) || @value.is_a?(Date)
|
320
|
-
|
374
|
+
if @attribute[:view_format]
|
375
|
+
return use_view_format(@attribute[:view_format], @value)
|
376
|
+
else
|
377
|
+
return "%d-%02d-%02d" % [@value.year, @value.mon, @value.mday]
|
378
|
+
end
|
321
379
|
else
|
322
380
|
return @value
|
323
381
|
end
|
@@ -325,12 +383,85 @@ module Ezframe
|
|
325
383
|
end
|
326
384
|
|
327
385
|
class TimeType < TextType
|
386
|
+
def db_value
|
387
|
+
return nil if @value.nil? || @value.strip.empty?
|
388
|
+
return @value
|
389
|
+
end
|
328
390
|
end
|
329
391
|
|
330
|
-
class DatetimeType <
|
392
|
+
class DatetimeType < TextType
|
393
|
+
def initialize(attr = nil)
|
394
|
+
super(attr)
|
395
|
+
@attribute[:class] = "datetimepicker"
|
396
|
+
end
|
397
|
+
|
398
|
+
def value=(v)
|
399
|
+
if v.nil?
|
400
|
+
default = @attribute[:default]
|
401
|
+
if default
|
402
|
+
@value = default
|
403
|
+
else
|
404
|
+
@value = nil
|
405
|
+
end
|
406
|
+
return
|
407
|
+
end
|
408
|
+
if v.is_a?(String)
|
409
|
+
if v.strip.empty?
|
410
|
+
@value = nil
|
411
|
+
return
|
412
|
+
end
|
413
|
+
begin
|
414
|
+
@value = DateTime.parse(v)
|
415
|
+
rescue
|
416
|
+
Logger.warn("date format error: #{self.key}=#{v}")
|
417
|
+
@value = nil
|
418
|
+
end
|
419
|
+
return
|
420
|
+
end
|
421
|
+
if v.is_a?(Date) || v.is_a?(Time) || v.is_a?(DateTime)
|
422
|
+
@value = v
|
423
|
+
else
|
424
|
+
Logger.info "[WARN] illegal value for date type: #{v.inspect}"
|
425
|
+
end
|
426
|
+
end
|
427
|
+
|
428
|
+
def view(opts = {})
|
429
|
+
return nil if no_view? && !opts[:force]
|
430
|
+
if @value.is_a?(Time) || @value.is_a?(Date)
|
431
|
+
if @attribute[:view_format]
|
432
|
+
return use_view_format(@attribute[:view_format], @value)
|
433
|
+
else
|
434
|
+
return "%d/%02d/%02d %02d:%02d:%02d"%[@value.year, @value.mon, @value.mday, @value.hour, @value.min, @value.sec]
|
435
|
+
end
|
436
|
+
else
|
437
|
+
return @value
|
438
|
+
end
|
439
|
+
end
|
440
|
+
|
441
|
+
def form(opts = {})
|
442
|
+
Logger.debug("DatetimeType: key=#{self.key}, opts=#{opts}")
|
443
|
+
return nil if no_edit? && !opts[:force]
|
444
|
+
h = super
|
445
|
+
if h
|
446
|
+
# h[:type] = 'date'
|
447
|
+
h[:type] = "text"
|
448
|
+
h[:value] = @value || ""
|
449
|
+
h[:class] = [ "datepicker" ]
|
450
|
+
h[:class].push(@attribute[:class]) if @attribute[:class]
|
451
|
+
end
|
452
|
+
Logger.debug("DatetimeType: res=#{h}")
|
453
|
+
return h
|
454
|
+
end
|
455
|
+
|
331
456
|
def db_type
|
332
457
|
"timestamp"
|
333
458
|
end
|
459
|
+
|
460
|
+
def value
|
461
|
+
return nil if @value.nil? || (@value.is_a?(String) && @value.strip.empty?)
|
462
|
+
return @value if @value.is_a?(Date) || @value.is_a?(Time)
|
463
|
+
return DateTime.parse(@value) if @value.is_a?(String)
|
464
|
+
end
|
334
465
|
end
|
335
466
|
|
336
467
|
class BirthdayType < TextType
|
@@ -341,26 +472,32 @@ module Ezframe
|
|
341
472
|
year_list = []
|
342
473
|
110.times do |y|
|
343
474
|
year = now.year - y - 10
|
344
|
-
year_list.push [year, "#{year}
|
475
|
+
year_list.push [year, "#{year}(#{Japanese.convert_wareki(year)})"]
|
345
476
|
end
|
477
|
+
year_list.unshift([ 0, "(年)" ])
|
346
478
|
|
347
479
|
year, mon, mday = parse_date(@value)
|
348
|
-
mon_list = (1..12).map { |m| [m, "#{m}
|
480
|
+
mon_list = (1..12).map { |m| [m, "#{m}"] }
|
349
481
|
mon_list.unshift([0, "(月)"])
|
350
|
-
mday_list = (1..31).map { |d| [d, "#{d}
|
482
|
+
mday_list = (1..31).map { |d| [d, "#{d}"] }
|
351
483
|
mday_list.unshift([0, "(日)"])
|
352
|
-
return [Ht.select(name: "#{prefix}_year", item: year_list, value: year),
|
353
|
-
Ht.
|
354
|
-
Ht.select(name: "#{prefix}
|
484
|
+
return [Ht.div([Ht.select(name: "#{prefix}_year", class: %w[browser-default], item: year_list, value: year),
|
485
|
+
Ht.small("年")]),
|
486
|
+
Ht.select(name: "#{prefix}_mon", class: %w[browser-default], item: mon_list, value: mon),
|
487
|
+
Ht.small("月"),
|
488
|
+
Ht.select(name: "#{prefix}_mday", class: %w[browser-default], item: mday_list, value: mday),
|
489
|
+
Ht.small("日")
|
490
|
+
]
|
355
491
|
end
|
356
492
|
|
357
493
|
def view(opts = {})
|
358
494
|
return nil if no_view? && !opts[:force]
|
359
495
|
return nil unless @value
|
360
496
|
year, mon, mday = parse_date(@value)
|
361
|
-
|
362
|
-
|
363
|
-
|
497
|
+
year_s = if year.to_i == 0 then "?" else "%d" % [year]; end
|
498
|
+
mon_s = if mon.to_i == 0 then "?" else "%2d" % [mon]; end
|
499
|
+
mday_s = if mday.to_i == 0 then "?" else "%2d" % [mday]; end
|
500
|
+
return "#{year_s}<small>年</small>#{mon_s}<small>月</small>#{mday_s}<small>日</small>"
|
364
501
|
end
|
365
502
|
|
366
503
|
def parse_date(date)
|
@@ -376,7 +513,7 @@ module Ezframe
|
|
376
513
|
|
377
514
|
def form_to_value(form)
|
378
515
|
y, m, d = form["#{self.key}_year".to_sym], form["#{self.key}_mon".to_sym], form["#{self.key}_mday".to_sym]
|
379
|
-
return "
|
516
|
+
return "%d-%02d-%02d"%[y.to_i, m.to_i, d.to_i]
|
380
517
|
end
|
381
518
|
end
|
382
519
|
|
@@ -397,7 +534,8 @@ module Ezframe
|
|
397
534
|
def validate(val)
|
398
535
|
super(val)
|
399
536
|
return @error if @error
|
400
|
-
if
|
537
|
+
return nil if !val || val.strip.empty?
|
538
|
+
unless email_format?(val)
|
401
539
|
@error = :invalid_value
|
402
540
|
return @error
|
403
541
|
end
|
@@ -405,29 +543,29 @@ module Ezframe
|
|
405
543
|
end
|
406
544
|
|
407
545
|
def email_format?(val)
|
408
|
-
return nil unless val
|
409
546
|
return val.to_s =~ /^[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
|
410
547
|
end
|
411
548
|
end
|
412
549
|
|
413
550
|
class TelType < TextType
|
551
|
+
def normalize(val)
|
552
|
+
return nil unless val
|
553
|
+
val = super(val)
|
554
|
+
val = val.tr("0-9", "0-9")
|
555
|
+
# val = val.gsub(/\D+/, "")
|
556
|
+
return val
|
557
|
+
end
|
558
|
+
|
414
559
|
def validate(val)
|
415
560
|
super(val)
|
416
561
|
return @error if @error
|
562
|
+
return nil if !val || val.strip.empty?
|
417
563
|
unless /^0\d{9,10}$/ =~ val.to_s
|
418
564
|
@error = :invalid_value
|
419
565
|
return @error
|
420
566
|
end
|
421
567
|
return nil
|
422
568
|
end
|
423
|
-
|
424
|
-
def normalize(val)
|
425
|
-
return nil unless val
|
426
|
-
val = super(val)
|
427
|
-
val = val.tr("0-9", "0-9")
|
428
|
-
val = val.gsub(/\D+/, "")
|
429
|
-
return val
|
430
|
-
end
|
431
569
|
end
|
432
570
|
|
433
571
|
class JpnameType < TextType
|
@@ -442,6 +580,7 @@ module Ezframe
|
|
442
580
|
def validate(val)
|
443
581
|
super(val)
|
444
582
|
return @error if @error
|
583
|
+
return nil if !val || val.strip.empty?
|
445
584
|
unless /^[ぁ-ん ]+$/ =~ val.to_s
|
446
585
|
@error = :hiragana_only
|
447
586
|
return @error
|
@@ -460,6 +599,7 @@ module Ezframe
|
|
460
599
|
def validate(val)
|
461
600
|
super(val)
|
462
601
|
return @error if @error
|
602
|
+
return nil if !val || val.strip.empty?
|
463
603
|
unless /^[ァ-ン ]+$/ =~ val
|
464
604
|
@error = :katakana_only
|
465
605
|
return @error
|
@@ -469,6 +609,8 @@ module Ezframe
|
|
469
609
|
end
|
470
610
|
|
471
611
|
class PrefectureType < SelectType
|
612
|
+
attr_accessor :pref_h
|
613
|
+
|
472
614
|
def initialize(attr)
|
473
615
|
super(attr)
|
474
616
|
@pref_a = %w[() 北海道 青森県 岩手県 宮城県 秋田県 山形県 福島県
|
@@ -505,7 +647,7 @@ module Ezframe
|
|
505
647
|
|
506
648
|
def normalize(val)
|
507
649
|
val = super(val)
|
508
|
-
return nil
|
650
|
+
return nil if !val || val.strip.empty?
|
509
651
|
val = val.tr("0-9", "0-9")
|
510
652
|
return val
|
511
653
|
end
|
@@ -513,6 +655,8 @@ module Ezframe
|
|
513
655
|
def validate(val)
|
514
656
|
super(val)
|
515
657
|
return @error if @error
|
658
|
+
return nil if !val || val.to_s.strip.empty?
|
659
|
+
|
516
660
|
unless /^\d{7}$/ =~ val.to_s
|
517
661
|
@error = :invalid_value
|
518
662
|
return @error
|