欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Ruby On Rails的第一个应用(二)--验证

程序员文章站 2022-03-03 07:57:35
...

 

II 任务B:验证和单元测试

 

一、迭代B1:验证

  到迭代A1止,new product时,如果输入无效价格或者没有输入商品描述,都会把商品添加到数据库中。所以现在需要添加验证。

  验证代码应该放到哪里呢?模型层!无论是从数据库中读出,还是写到数据库中,都会先通过模型层。在模型层验证,不用管数据直接来自表单,还是经过程序处理的。

  现在模型类的源代码(/app/models/product.rb):

class Product < ActiveRecord::Base
end

 注:在mac下:ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-darwin11.4.0],rails3.2.13 环境。还会生成这样一行:

attr_accessible :description, :image_url, :price, :title

 

先验证非空的文本字段:

validates :title, :description, :image_url, :presence => true

 这里,validates是标准的rails验证器。它会根据一个或者多个条件来验证一个或多个模型字段。

:presence=>true是要验证每个字段都存在,并且内容不为空。也可以写成presence: true,现在这两种写法是一样的意思。按个人习惯保持统一就可以。

现在来看一下效果。点new product进入http://localhost:3000/products/new。不输入任何内容,直接点Create Product按钮,会看到一片红色高亮显示,表示修改生效了。用一行代码就搞定这些了,另外还会注意到,不需要重启程序来测试修改,只要重新加载网页就行。

Ruby On Rails的第一个应用(二)--验证
            
    
    博客分类: ruby on rails Ruby On Rails的第一个应用depotruby on railsrails

再来验证一下价格为有效正数:

validates :price, :numericality => {:greater_than_or_equal_to => 0.01}

 :numericality验证是否是一个有效的数字;另外还给:greater_than_or_equal_to选项(忒TM长了吧- -)传递一个值0.01(用0.01,不用0;原因是可能输入0.001,而我们价格在数据库中只允许到小数点后两位,结果保存到数据库的数据会是0而不是0.001)。

Ruby On Rails的第一个应用(二)--验证
            
    
    博客分类: ruby on rails Ruby On Rails的第一个应用depotruby on railsrails

现在又要确保每个商品有唯一的标题。来添加一个唯一性验证:

validates :title, :uniqueness => true

  Ruby On Rails的第一个应用(二)--验证
            
    
    博客分类: ruby on rails Ruby On Rails的第一个应用depotruby on railsrails

还要验证图片是否有效:

validates :image_url, :format => {
:with=> %r{\.(gif|jpg|png)$}i,
:message => 'must be a URL for GIF, JPG, or PNG image.'
}

 用format选项来实现这个功能。format可以判断字段是否和正则表达式相匹配,这里只检查.gif,.jpg,.png。事实上,我们可能要改变表单,让用户浏览一个可用图片,不过这种情况还是要验证。

现在添加的验证有以下几项内容:

·字段的标题、描述以及图片的URl不是空的

·价格是一个有效的数字,且不少于0.01

·标题在所有的端口中是唯一的。

·图片的URL看起来要是有效的

现在模型的代码如下:

 

class Product < ActiveRecord::Base
	validates :title, :description, :image_url, :presence => true
	validates :price, :numericality => {:greater_than_or_equal_to => 0.01}
	validates :title, :uniqueness => true
	validates :image_url, :format => {
			:with		=> %r{\.(gif|jpg|png)$}i,
			:message => 'must be a URL for GIF, JPG, or PNG image.'
		}
	end

 

 

 

继续之前再测试一下:

rake test

oh~有两个地方报错了,我们发现一个是在test_should_create_product中,另一个在test_should_update_product中。这就是我们添加的验证导致的,也正是验证的目的,现在测试的创建和更新商品失败了。

E:\works\ruby\depot>rake test
        SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
        This poses a security threat. It is strongly recommended that you
        provide a secret to prevent exploits that may be possible from crafted
        cookies. This will not be supported in future versions of Rack, and
        future versions will even invalidate your existing user cookies.

        Called from: D:/dev/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/ac
tionpack-3.2.1/lib/action_dispatch/middleware/session/abstract_store.rb:28:in `i
nitialize'.

Rack::File headers parameter replaces cache_control after Rack 1.5.
Run options:

# Running tests:



Finished tests in 0.000000s, NaN tests/s, NaN assertions/s.

0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
        SECURITY WARNING: No secret option provided to Rack::Session::Cookie.
        This poses a security threat. It is strongly recommended that you
        provide a secret to prevent exploits that may be possible from crafted
        cookies. This will not be supported in future versions of Rack, and
        future versions will even invalidate your existing user cookies.

        Called from: D:/dev/RailsInstaller/Ruby1.9.3/lib/ruby/gems/1.9.1/gems/ac
tionpack-3.2.1/lib/action_dispatch/middleware/session/abstract_store.rb:28:in `i
nitialize'.

Rack::File headers parameter replaces cache_control after Rack 1.5.
Run options:

# Running tests:

F.....F

Finished tests in 0.796875s, 8.7843 tests/s, 11.2941 assertions/s.

  1) Failure:
test_should_create_product(ProductsControllerTest) [E:/works/ruby/depot/test/fun
ctional/products_controller_test.rb:20]:
"Product.count" didn't change by 1.
<3> expected but was
<2>.

  2) Failure:
test_should_update_product(ProductsControllerTest) [E:/works/ruby/depot/test/fun
ctional/products_controller_test.rb:39]:
Expected response to be a <:redirect>, but was <200>

7 tests, 9 assertions, 2 failures, 0 errors, 0 skips

 

解决办法是在/test/functional/products_controller_test.rb中给出有效的测试数据(下的源代码中这个文件在test/controllers/目录下),修改后的代码:

 

require 'test_helper'

class ProductsControllerTest < ActionController::TestCase
  setup do
    @product = products(:one)
    @update = {
      title:       'Lorem Ipsum',
      description: 'Wibbles are fun!',
      image_url:   'lorem.jpg',
      price:       19.95
    }
  end

  test "should get index" do
    get :index
    assert_response :success
    assert_not_nil assigns(:products)
  end

  test "should get new" do
    get :new
    assert_response :success
  end

  test "should create product" do
    assert_difference('Product.count') do
      post :create, product: @update
    end

    assert_redirected_to product_path(assigns(:product))
  end

  test "should show product" do
    get :show, id: @product
    assert_response :success
  end

  test "should get edit" do
    get :edit, id: @product
    assert_response :success
  end

  test "should update product" do
    put :update, id: @product, product: @update
    assert_redirected_to product_path(assigns(:product))
  end

  test "should destroy product" do
    assert_difference('Product.count', -1) do
      delete :destroy, id: @product
    end

    assert_redirected_to products_path
  end
end

 

 

修改后,运行测试,正常。说明我们的修改没有破坏什么。但是我们要确保的是不仅现在能工作,而且进一步修改后也能正常。以后我们需要功能测试,现在我们做下单元测试。