0

I'm somewhat new to Rails and I'm trying to learn about custom validations.

One common requirement in Brazil are CPF/CNPJ/RG fields. They are a type of identification number and follow a specific format.

For example:

CPFs are 11 digit numbers. They follow this pattern: xxx.xxx.xxx-xx

I'm trying to store them in an Integer field but I'm getting (Using Postgres):

PG::Error: ERROR: value "xxxxxxxxxxx" is out of range for type integer

What is the proper way to store this? Bigint (How?)? A string?

My second question is:

How can I specify a custom validation (a method) for this field that could be called somewhat like this:

class User < AR::Base

   validates :cpf, presence: true, unique: true, cpf: true
4

3 回答 3

2

假设性能不重要,字符串就可以了。这样你就可以保留点和破折号。正如该线程中的其他人所提到的,bigint或者numeric如果这是一个问题,可能会表现得更好。

如果您将字段保留为字符串,则可以使用正则表达式轻松验证它:

validates_format_of :cpf, with: /^[0-9]{3}\.[0-9]{3}\.[0-9]{3}\-[0-9]{2}$/
于 2013-06-10T23:29:00.983 回答
1

对于小表,只需存储为text以保留格式。

对于大表,性能和存储大小可能是一个问题。如果您的模式得到保证,您可以很好地将数字存储为bigint并在检索时将其格式化to_char()

写:

SELECT translate('111.222.333-55', '.-', '')::bigint

这也可以作为部分验证。只有数字,.并且-允许在您的字符串中。该模式可能仍然被违反,您必须使用@Michael 提供的内容进行明确检查。

读:

SELECT to_char(11122233355, 'FM000"."000"."000"-"00')

回报:

111.222.333-55

不要忘记FM模式中的前导以删除前导空格(负号可能用于数字)。

A在磁盘上bigint占用8 个字节,可以轻松存储 11 位数字。
text(或varchar)需要 1 个字节加上实际字符串,在您的情况下相当于15 个字节
另外,处理bigint通常比text相同长度的处理快一点。

于 2013-06-10T23:44:26.483 回答
0

就我个人而言,我总是将这些值存储为bigint输入/输出(正如 Erwin 建议的那样)或应用程序中的格式。

主要原因是存储效率(正如 Erwin 提到的)和比较效率。当您与as进行比较11111111112时,PostgreSQL 将使用对文本正确的特定于语言的排序规则,但对于数字可能不是您想要的。他们也很慢;最近关于 SO 的一个问题报告了通过使用强制纯 POSIX 排序规则的选项,文本比较速度提高了五倍;数字排序再次更快。11111111113textCOLLATE "C"

这些标准数字中的大多数都有自己的内部校验和,通常是Luhn 算法的变体。在约束中验证这些CHECK可能是一个好主意。您可以在 PL/PgSQL 或普通 SQL 中轻松实现 Luhn 算法检查整数;我在 PostgreSQL wiki 上写了一些示例

无论您做什么,请确保您CHECK对验证存储数字的列有一个约束,这样您就不会存储无效和无意义的值。

于 2013-06-11T02:16:03.823 回答