views:

103

answers:

1

Hi

I have a rails model that I am adding validations to and I seem to have run into a bit of weirdness from one of the validators.

So here is the table I am working with (From schema.rb):

  create_table "clients", :force => true do |t|
    t.string   "name"
    t.string   "last_contact"
    t.integer  "contacting_agent"
    t.date     "last_payment_date"
    t.float    "last_payment_amt"
    t.datetime "created_at"
    t.datetime "updated_at"
    t.string   "office"
    t.integer  "client_id"
  end

I have a normal view, with:

<%= error_messages_for 'client' %>
<h1>New Client</h1>
<% form_for @client do |new| %>

<table id='newform'>
 <tr>
  <th>Field</th>
  <th>Value</th>
 </tr>
 <tr>
  <td>
   ID
  </td>
  <td>
   <%= new.text_field :client_id %>
  </td>
 </tr>
 <tr>
  <td>
   Name
  </td>
  <td>
   <%= new.text_field :name %>
  </td>
 </tr>
 <tr>
  <td>
   Office
  </td> 
  <td>
   <%= new.select :office, $offices %>
  </td>
 </tr>
 <tfoot>
  <tr>
   <td>
    <%= image_submit_tag "/images/icons/save_32.png" %>
    <a href="/clients/new" title="Clear"><%= image_tag "/images/icons/close_32.png" %></a>
   </td>
   <td>
    &nbsp;
   </td>
  </tr>
 </tfoot>
</table>

<% end %>

and my humble model

class Client < ActiveRecord::Base
  validates_length_of :client_id, :in => 5..7
  validates_uniqueness_of :client_id
  validates_presence_of :name, :client_id
end

So the part that is kicking my butt is the first validation in the model.

validates_length_of :client_id, :in => 5..7

If I head off to the browser and load the view (/clients/new), I enter a client_id and a name, select an office, then hit submit. The validator is not picking up the :client_id correctly, as it will always fail with "too short" or "too long" error messages.

The kicker is that it will give me the "too short" error up until I try about 11 characters, then at 12 characters, I get the "too long". So 11 is the threshold of "too short", even tho the range is supposed to be "5..7" - but sometimes instead of the "too long" message, it will actually validate and insert the record, but the record it inserts has a completely different number for "client_id", and it's always the same, despite the validates_uniqueness_of.

What I think is happening is that :client_id, instead of validating the actual field, client_id, it's trying to pick up the objects id, and validate that. At least, this is the only thing I can think of.

  Parameters: {"x"=>"13", "y"=>"14", "authenticity_token"=>"removed", "client"=>{"name"=>"test345", "client_id"=>"12345678", "office"=>"US10"}}

Above, from the server logs, validates as "too short" for :client_id

So please, is there any way to correct this weirdness? (Note: I tried validates_length_of "client_id", :in => 5..7 but got absolutely no validation)

A: 

client_id column is integer. validates_length_of uses size method to find out length of the field, and for the integer it just gives you size of the variable in bytes, which is probably 4 for first 11 "characters" and 8 for 12+.

If you really need client_id to be integer and validate length, you can probably use:

validates_inclusion_of :client_id, :in => 10000..9999999, :message => "should be between 5 and 7 characters"
Voyta
Thanks for pointing that out to me. Seems clear as day now lol.I'll just switch to `validates_format_of :client_id, :with => /\A\d{5,7}\z/` and use regex.
Chris Allison
If it's an Integer column in the database, `validates_inclusion_of` won't work because the value from the form is a String. You want `validates_numericality_of` with `:greater_than_or_equal_to` and `:less_than_or_equal_to` options.
James A. Rosen
Actually, it will, because value is transformed to integer when the field is assigned. `>> c = Client.new(:client_id => "22222")`; `>> c.client_id`; `=> 22222`
Voyta
Oh, you're right Voyta. The numericality problem is a different one: it turns into 0 (or the default value from the DB) if a non-numeric value is passed. That can generate odd messages.
James A. Rosen