0

I am having a weird error in a Rails 3 form

I have a field called "nif" which has to comply with a rule. A "nif" is 8 numbers plus a single control letter:

class User < ActiveRecord::Base
  ...
  validates :nif, presence: true
  validate :nif_must_be_valid
  ...

  def nif_must_be_valid
    if !validate_nif self.nif
      errors.add(:nif, :invalid)
    end
  end
end

Where validate_nif is in my application helper:

def validate_nif(value)
  if value.match(/[0-9]{8}[a-z]/i)
    letters = "TRWAGMYFPDXBNJZSQVHLCKE"
    check = value.slice!(value.length - 1..value.length - 1).upcase
    calculated_letter = letters[value.to_i % 23].chr
    return check === calculated_letter
  else
    false
  end
end

The thing is, if "nif" is invalid and I try to save the form, everything works as expected: the error appears and the wrong value is preserved. However, if the nif is correct but some other field is incorrect, when the form is reloaded the nif value (which was correct) doesn't have the final letter anymore, that is, if the value was "87613686Q" the value gets changed to "87613686". Finally, if all the form is correct (and thus gets saved) the nif is saved without the last char.

I have verified this in rails console:

user = User.new
user.nif='87613686Q'
  => "87613686Q"
user.save
  (0.1ms)  begin transaction
    [deprecated] I18n.enforce_available_locales will default to true in the future. If you really want to skip validation of your locale you can set I18n.enforce_available_locales = false to avoid this message.
    (0.1ms)  rollback transaction
     => false
user.nif
  => "87613686"

I just don't get it. Why would the value be striped of that single last char?

My Rails version is '3.2.16', by the way.

Thanks a lot, regards

(edited#2). Added output asket by Richards (thanks)

I had to add every other required value to get the output:

user = User.new(:nombre=>'dasdsasdasso',:primer_apellido => 'sadsada',:segundo_apellido
  => 'asdsadsas', :nif => '87613686Q',:grupo_seguridad => 'sadasncia',
    :categoria => 'asafrio',:telefono => '9287',:accion => 'alta')

  => #<User id: nil, accion: "alta", prioridad: nil, fecha_prevista: nil, nombre: "dasdsasdasso", primer_apellido: "sadsada", segundo_apellido: "asdsadsas", nif: "87613686Q", categoria: "asafrio", nivel: nil, telefono: "9287", movil_corporativo: nil, tarjetas_visita: nil, ubicacion: nil, grupo_seguridad: "sadasncia", carpeta_comun_unidad: nil, requiere_ordenador: nil, comentarios: nil, created_at: nil, updated_at: nil, solicitante: nil, solicitante_nombre: nil, solicitante_apellido: nil, solicitante_email: nil> 

user.save!

  (0.1ms)  begin transaction SQL (0.3ms)  INSERT INTO "users" ("accion", "carpeta_comun_unidad", "categoria", "comentarios", "created_at", "fecha_prevista", "grupo_seguridad", "movil_corporativo", "nif", "nivel", "nombre", "primer_apellido", "prioridad", "requiere_ordenador", "segundo_apellido", "solicitante", "solicitante_apellido", "solicitante_email", "solicitante_nombre", "tarjetas_visita", "telefono", "ubicacion", "updated_at") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)  [["accion", "alta"], ["carpeta_comun_unidad", nil], ["categoria", "asafrio"], ["comentarios", nil], ["created_at", Thu, 13 Feb 2014 12:26:09 UTC +00:00], ["fecha_prevista", nil], ["grupo_seguridad", "sadasncia"], ["movil_corporativo", nil], ["nif", "87613686"], ["nivel", nil], ["nombre", "dasdsasdasso"], ["primer_apellido", "sadsada"], ["prioridad", nil], ["requiere_ordenador", nil], ["segundo_apellido", "asdsadsas"], ["solicitante", nil], ["solicitante_apellido", nil], ["solicitante_email", nil], ["solicitante_nombre", nil], ["tarjetas_visita", nil], ["telefono", "9287"], ["ubicacion", nil], ["updated_at", Thu, 13 Feb 2014 12:26:09 UTC +00:00]]

(6.7ms) commit transaction => true

arg
  • 187
  • 1
  • 12

1 Answers1

0

I think the reason is in your validate_nif method.

You are using the slice method with the bang (!) which will apply the slicing directly on the variable (read more about the Bang here or here)

That's why when it takes the leter to compare with your allowed list of letters, it takes it for good (That's why the bang is also called “dangerous” method)

Try to remove that bang and see how it works !!

Community
  • 1
  • 1
Nimir
  • 5,727
  • 1
  • 26
  • 34
  • It was exactly that. I took that validator from someone's blog, I'll notify him. Thanks a lot! – arg Feb 13 '14 at 12:50