Out of the box, ActiveRecord will silently truncate attribute values which exceed their column width.

This is potentially surprising to users. To improve usability, we can set a validation:

Now we have a new problem: duplication of the length cap. The number “10” now appears in both the database migrations, and the model validations.

We could extract it out into a constant, although referencing models can be problematic in migrations. But that still doesn't account for the (many) cases where we don't specify an explicit field limit in the migration, and instead rely on the built-in ActiveRecord defaults for field limits.

Here's a solution that uses database reflection to validate a field is within its DB column size limit:

ActiveRecord provides the columns_hash to get at column metadata gathered from the database backend. In the code above we query it for the limit attribute, and use that as the max field length. By pulling the limit from the DB, we avoid duplication of knowledge.

Published by Avdi Grimm

26 Comments

  1. If only AR automatically did this for all (common) restrictions on columns.

    Reply
  2. Neat tip! I can see myself needing this.

    Reply
  3. Since I first started using Rails, I thought it was odd that it did not use DB introspection to automatically provide these kinds of obvious validations. 

    Reply
  4. Great tip! Too bad Rails doesn’t hold a strong opinion about using conventions…

    Reply
  5. Check out:

    https://github.com/twinge/enforce_schema_rules

    With one macro method it handles:

    • Column length
    • Column¬†null-ability
    • Column uniquness
    • Column integer restrictions

    I use it on almost every project. Used to use¬†schema_validations by the “Red Hill on Rails” folks but that fell into disrepair. Found this plugin and it has been working great.

    Reply
  6. Years ago I wrote a schema_validations plugin which I used on a number of projects. I’ve since stopped supporting it for various reasons – for one thing, at the time the jiggery pokery required to get it to work was cumbersome. Looks like it would be MUCH easier now – but I still have an archived version:

    https://github.com/harukizaemon/redhillonrails/tree/master/schema_validations

    Reply
  7. Doesn’t this introduce an extra database hit to get the schema? And isn’t it considered an ActiveRecord best practice to use validations for limiting length instead of enforcing in the database?

    Reply
      1. No, ActiveRecord pulls in the whole schema and caches it during start-up.
      2. ActiveRecord always puts a limit in the DB even if you don’t explicitly specify it. For instance, by default AR puts a 255-char limit on :string types. So the limit is already there; this is just a way to give the client some decent feedback instead of silently truncating it.
      Reply
  8. I was looking for ways to solve this problem! From your info I coded a method for the model that returns the data. Seems like it should be part of AR. For example:
        Model.column_name.schema_data
    such as:
        Company.contact_name.limit
    returns the limit on the contact_name field. All of the column_hash values can be accessed this way. See: http://stackoverflow.com/questions/11004253/to-be-dry-can-i-access-a-string-column-width-limit-in-activerecord 

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *