環境
・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 件のコメント :
コメントを投稿