#968 ✓not-applicable
Martin Gamsjaeger (snusnu)

property :length => (1..x) should implicitly set :nullable => false

Reported by Martin Gamsjaeger (snusnu) | July 11th, 2009 @ 07:03 PM | in 0.10.0

This is a follow up to #853 which is not applicable itself but lead to the discovery of this issue.

Sorry for the bad title, I tried to edit it after discovering what the (hopefully) real issue is, but I didn't find out how. A better title would probably be

:length autovalidator doesn't set :nullable option on property

I think I read somewhere that specifying :length => (1..20) on a property would implicitly set :nullable => false on that property too. The reasoning behind that being that when range.min > 0, it assumes that the attribute must be at least "of length 1" and thus NOT NULL.

If DM would allow persisting a nil value in such a situation, then when reading it back, the requirement that the attribute is at least of length 1 cannot be fulfilled anymore since the value is nil. Thus we just loaded an invalid object from the datastore, which is not what DM wants to achieve. DM's opinion is that once persistence was successful, the resource can be considered valid when loading it back from the datastore.

The workaround is obvious. Explicitly specifying :nullable => false on that property in addition to :length => (1..20) does the trick, but since not doing that can result in broken behavior, I consider this a bug.

Additionally, I think that the documentation for validates_length is rather weird. It only has examples of Integer properties, whereas I think validates_is_number would be better suited for Integers. It even reads strange since imho the options don't really fit the intentions. Instead, I see validates_length mainly for validating Strings.

require "rubygems"
require "dm-core"
require "dm-validations"
require "spec"

DataMapper::Logger.new(STDOUT, :debug)
DataMapper.setup(:default, "sqlite3::memory:")

class Contact
  include DataMapper::Resource
  property :id,      Serial
  property :zip,     String
  property :address, String, :length => (1..100)

describe "auto validations" do
  before(:all) do
  it "should return :key => ['error message'] when validation fails" do
    contact = Contact.new
    contact.should_not be_valid # <-- FAILS
    contact.errors.on(:address).respond_to?(:each).should be_true
    contact.errors.on(:address).should_not be_empty

# mungo:snippets snusnu$ spec -cfs 968.rb 
# auto validations
#  ~ (0.000159) SELECT sqlite_version(*)
#  ~ (0.000117) DROP TABLE IF EXISTS "contacts"
#  ~ (0.000022) PRAGMA table_info("contacts")
#  ~ (0.000372) CREATE TABLE "contacts" ("id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, "zip" VARCHAR(50), "address" VARCHAR(100))
# - should return :key => ['error message'] when validation fails (FAILED - 1)
# 1)
# 'auto validations should return :key => ['error message'] when validation fails' FAILED
# expected valid? to return false, got true
# ./968.rb:22:
# Finished in 0.00581 seconds
# 1 example, 1 failure

Comments and changes to this ticket

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.

New-ticket Create new ticket

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

People watching this ticket

Referenced by