Código Ruby para cálculo de validação de CPF

Dicas - 16/Fev/2020 - por Henrique Morato

No artigo O cálculo do dígito verificador do CPF e do CNPJ falamos sobre como funcionam as validações de alguns documentos oficiais mas não entramos em detalhes no código em si. Baseados no artigo, trazemos um pequeno método customizado de validação para você usar em Rails.

Você só precisa colocar o código abaixo no arquivo: app/validators/cpf_validator.rb.

class CpfValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    return if value.blank?
    return if cpf_valid?(value)

    record.errors.add(
      attribute,
      :invalid_cpf,
      message: options[:message] || 'is not valid',
      value: value
    )
  end

  private

  DENY_LIST = %w[
    00000000000
    11111111111
    22222222222
    33333333333
    44444444444
    55555555555
    66666666666
    77777777777
    88888888888
    99999999999
    12345678909
    01234567890
  ].freeze

  SIZE_VALIDATION = /^[0-9]{11}$/

  def cpf_valid?(cpf)
    cpf.gsub!(/[^\d]/, '')
    return unless cpf =~ SIZE_VALIDATION
    return if DENY_LIST.include?(cpf)

    cpf_numbers = cpf.chars.map(&:to_i)
    first_digit_valid?(cpf_numbers) && second_digit_valid?(cpf_numbers)
  end

  def first_digit_valid?(cpf_numbers)
    first_digits = cpf_numbers[0..9]
    multiplied = first_digits.map.with_index do |number, index|
      number * (10 - index)
    end

    mod = multiplied.reduce(:+) % 11

    fst_verifier_digit = 11 - mod > 9 ? 0 : mod
    fst_verifier_digit == cpf_numbers[10]
  end

  def second_digit_valid?(cpf_numbers)
    second_digits = cpf_numbers[0..10]
    multiplied = second_digits.map.with_index do |number, index|
      number * (11 - index)
    end

    mod = multiplied.reduce(:+) % 11

    snd_verifier_digit = 11 - mod > 9 ? 0 : mod
    snd_verifier_digit == cpf_numbers[11]
  end
end

Agora no arquivo do model User você pode usar o código da seguinte forma:

class User < ApplicationRecord
  validates :cpf, cpf: { message: 'Sua mensagem de validação }
end

É claro que esse código apresenta algumas repetições e tem como objetivo facilitar a compreensão dos conceitos. Mas se você quer ver como isso pode ser implementado com uma qualidade maior, recomendo ler o código da gem cpf_cnpj do Nando Vieira.

Foto de perfil do autor
Henrique Morato

Dev