環境
・Ruby : 1.8.7
・Rails : 3.0.0
・DB : PostgreSQL
・OS : Ubuntu 10.04
手っ取り早く試すために scaffold で
% rails g scaffold products name:string price:integer
こんなマイグレーションになる。
class CreateProducts < ActiveRecord::Migration
def self.up
create_table :products do |t|
t.string :name
t.integer :price
t.timestamps
end
end
def self.down
drop_table :products
end
end
バリデーションを設定する
class Product < ActiveRecord::Base
validates :price, :presence => true, :format => { :with => /\d+/ } # 数値だけ入力可
end
これで、ブラウザから http://localhost:3000/products にアクセスし、新規にデータを作成する。
その際、name : 'test', price : aaaa と不正な値を入力すると、当然 Invalid price にな・・・・・・らない!!!
なんと price が 0 で登録が成功してしまう。
実際 rails c として下記を実行するとよくわかる。
irb(main):001:0> p = Product.new => #<Product id: nil, name: nil, price: nil, created_at: nil, updated_at: nil> irb(main):002:0> p.price = 'aaaa' => "aaaa" irb(main):003:0> puts p.price 0 => nilちなみに 100aaa を price に代入すると price は 100 になる。数値じゃない文字は無視してるのか? フォームで数値の形式バリデーションを行いたいなら ActiveModel を使うしかないのか?
class ProductForm
extend ActiveModel::Naming
include ActiveModel::Conversion
include ActiveModel::Validations
attr_accessor :name, :price
validates :price, :presence => true, :format => { :with => /\d+/ }
end
こんな感じのフォーム用モデルを作成すれば、price に aaaa を入力して検証するとエラーになる。というわけで、ちゃんとした web アプリを作るなら、scaffold のように ActiveRecord のインスタンスを form_for に使うわけにはいかないだろう。
ActiveModel で便利になったんじゃなくて、ActiveModel が必須になっただけなんじゃないだろうか。
しばらく Rails に触ってなかったので、これが Rails3 からの挙動かどうかはわからない。
確か 2.0.2 とかのころは違ったと思うんだけど。
DB にはいろいろな型を利用できるが、Web から入力されたデータは全て文字列。
当然どこかで変換する必要はある。
そして「正規表現は文字列を対象にするものなので、数値列の検証に利用すべきでない」というのも理解できる。
どこまで自動的に内部で変換するのか?いつ変換するのか?あたりの問題なのかな?
ともかく文字列を数値に変換してくれるのはありがたいが、数値にならない文字を切り捨てるのはやりすぎだと思う。
これは ActiveRecord がより DB のレイヤに近づいたということなんだろうか。
[追記]
無視してるというか to_i の仕様ですね。
0 件のコメント :
コメントを投稿