我对Rails有点新鲜,我正在尝试了解自定义验证。
巴西的一个常见要求是CPF / CNPJ / RG字段。它们是一种识别号码,并遵循特定的格式。
例如:
CPF是11位数字。他们遵循以下模式:xxx.xxx.xxx-xx
我正在尝试将它们存储在Integer字段中,但我得到了(使用Postgres):
PG ::错误:错误:值“xxxxxxxxxxx”超出类型范围 整数
存储这个的正确方法是什么? Bigint(如何?)?字符串?
我的第二个问题是:
如何为此字段指定自定义验证(方法),可以像这样调用:
class User < AR::Base
validates :cpf, presence: true, unique: true, cpf: true
答案 0 :(得分:2)
假设性能不重要,字符串就可以了。这样你可以保持点和破折号。正如本主题中其他人所提到的,如果这是一个问题,bigint
或numeric
可能会更高效。
如果您将字段保留为字符串,则可以使用regex轻松验证它:
validates_format_of :cpf, with: /^[0-9]{3}\.[0-9]{3}\.[0-9]{3}\-[0-9]{2}$/
答案 1 :(得分:1)
对于小型表,只需存储为text
以保留格式。
对于大表,性能和存储大小可能是个问题。如果您的模式有保证,您可以将该数字存储为bigint
,并在使用to_char()
检索时对其进行格式化:
写:
SELECT translate('111.222.333-55', '.-', '')::bigint
这也可以作为部分验证。您的字符串中只允许使用数字.
和-
。该模式可能仍然被违反,您必须使用@Michael provided等明确检查。
读:
SELECT to_char(11122233355, 'FM000"."000"."000"-"00')
返回:
111.222.333-55
不要忘记模式中的前导FM
以删除前导空格(负号可能用于数字)。
bigint
在磁盘上占用 8个字节,可以轻松存储11位数字。
text
(或varchar
)需要1个字节加上实际字符串,在您的情况下需要 15个字节。
另外,处理bigint
通常比处理等长的text
快一点。
答案 2 :(得分:0)
我个人总是将这些值存储为bigint
并在输入/输出(如Erwin建议)或应用程序中应用格式。
主要原因是存储效率(如Erwin所述)和比较效率。将11111111112
与11111111113
比较为text
时,PostgreSQL将使用对文本正确的特定于语言的归类规则,但可能不是您想要的数字。他们也慢;最近关于SO的问题报告说,通过使用COLLATE "C"
选项强制进行简单的POSIX排序,文本比较的速度提高了五倍;数字校对再次更快。
这些标准数字中的大多数都有自己的内部校验和,通常是Luhn algorithm的变体。在CHECK
约束中验证这些可能是一个好主意。您可以在PL / PgSQL或纯SQL中轻松实现对整数的Luhn算法检查; I wrote some samples on the PostgreSQL wiki
无论您做什么,请确保在列上验证存储号码的CHECK
约束,这样您就不会存储无效和无意义的值。