ezframe 0.1.1 → 0.2.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.
- 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
|