Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Maybe a problem of validates :format #14040

Closed
kkzhang opened this Issue · 3 comments

2 participants

@kkzhang

I posted on http://stackoverflow.com/q/21750581/1575400 , but didn't resolved. I think it maybe a bug or something:

In my activerecord model:

  validates :achieve_points, :format => { :with=> /\A\d{1,10}\z/, :message => "Only allow 1-10 digits integers"}

In rspec:

r = build(:achieve, :achieve_type_id=>1, :achieve_points => 'a'*5)
expect(r.valid?).to eq(false)

Test not passed,

expected: false
got: true

But other cases is all valid, which means the regualr express is in its position,

it "is invalid when not provided" do
    r = build(:achieve, :achieve_type_id=>1, :achieve_points => nil)
    expect(r.valid?).to eq(false)
end

it "is invalid when empty" do
    r = build(:achieve, :achieve_type_id=>1, :achieve_points => '')
    expect(r.valid?).to eq(false)
end

it "is invalid when out of range" do
    r = build(:achieve, :achieve_type_id=>1, :achieve_points => '5'*11)
    expect(r.valid?).to eq(false)
end

it "is valid when integer in range" do
    r = build(:achieve, :achieve_type_id=>1, :achieve_points => '5'*10)
    expect(r.valid?).to eq(true)
end

But WHY? Something may be wrnong, but i stuck for a long time.

PS: Rails 4.02, ruby 2.1.0p0, Mac os 10.9

UPDATE:

I'm trying change to ruby2.0, rails4.01, but not works at all. Finally i abandon :format, user other validator instead.

validates :achieve_points, :presence=>true,
                          :numericality => {:only_integer => true, :greater_than => 0},
                          :length => {:maximum => 10}
@senny
Owner

@kkzhang please attach an executable test-case to reproduce the problem. You can use this script as a foundation.

@kkzhang
    unless File.exist?('Gemfile')
      File.write('Gemfile', <<-GEMFILE)
        source 'http://ruby.taobao.org'
        gem 'rails', "4.0.2"
        # gem 'arel'
        gem 'sqlite3'
      GEMFILE

      system 'bundle'
    end

    require 'bundler'
    Bundler.setup(:default)

    require 'active_record'
    require 'minitest/autorun'
    require 'logger'

    # This connection will do for database-independent bug reports.
    ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
    ActiveRecord::Base.logger = Logger.new(STDOUT)

    ActiveRecord::Schema.define do

      create_table :wallets do |t|
        t.integer :points
      end
    end

    class Wallet < ActiveRecord::Base
      validates :points, :presence=>true, :format => { :with=> /\A\d{1,10}\z/, :message => "Only allow 1-10 digits integers"}
    end

    describe Wallet do
      it "should be invaid" do
        Wallet.new(:points=>"ffff").valid?.must_equal false
      end
    end

@senny

@senny
Owner

@kkzhang this is due to the fact how Active Record currently turns Strings on Integer columns into 0. You can observe this behavior when you create a new Wallet instance:

Wallet.create(points: "ffff")
# => SQL (0.2ms)  INSERT INTO "wallets" ("points") VALUES (?)  [["points", 0]]

In case of your example, the validation runs agains 0, which matches your format. Also note that validates_format_of is supposed to be used for string columns and not integer columns. There is validates_numericality_of for number based columns.

We are currently working on this conversion behavior as it is related to many similar issues. See #13922 for a proposed solution and links to other related issues. I'm going to close this ticket, as we are already aware of that behavior and there are enough open issues to remind us about it.

@kkzhang thanks for reporting.

@senny senny closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.