码迷,mamicode.com
首页 > 其他好文 > 详细

有意练习--Rails RESTful(一)

时间:2015-09-17 21:39:06      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:

书要反复提及《哪里有天才》在说,大多数所谓的天才是通过反复刻意练习获得。

当你的练习时间达到10000几个小时后,。你将成为该领域的专家。


近期在学习rails怎样实现RESTful Web Service。

自己想给自己设计一个练习的模板,进行重复练习。

开发过程採用的是TDD的方式进行开发。


练习背景:

我们涉及三个Domain对象,Products、Orders、Payment


1.新建projectrails-rest-practice

rails new rails-rest-practice

cd !$

bundle install


2.安装rspec-rails

在Gemfile中加入

gem "rspec-rails", :group => [:development, :test]

然后

bundle install

rails g rspec:install

在.rspec 中去掉 --warnings


3.GET /products => user get list of products

step 1:创建controller,返回HTTP Status 200

user products api例如以下:

GET   /products       user get list of products


创建文件:spec/products/products_controller_spec.rb

require ‘rails_helper‘

describe ProductsController, :type => :controller do
   describe ‘products controller‘ do
      it ‘get index of products‘ do
         get :index
         expect(response).to have_http_status(200)
      end
   end
end


have_http_status:http://rubydoc.info/gems/rspec-rails/RSpec/Rails/Matchers#have_http_status-instance_method


创建文件:app/controllers/products_controller.rb

class ProductsController < ApplicationController
   def index
   end
end


执行rake spec。得到错误:

     ActionController::UrlGenerationError:
       No route matches {:action=>"index", :controller=>"products"}


配置相关config/routes.rb

resources :products do
   collection do
      get :index
   end
end


执行rake spec,得到错误:

Failure/Error: get :index
     ActionView::MissingTemplate:

改动app/controllers/products_controller.rb

class ProductsController < ApplicationController
   def index
      render :nothing => true
   end
end


这样就完毕我们的第一个步骤。尽管看似这个步骤什么都没測,事实上不然,在这一步中。我们搭建好了routes。同一时候创建了必要的controller类和其相应的方法。


step 2:返回JSON

安装rabl

在Gemfile中加入rabl

gem ‘rabl‘

bundle install

參考Rails + rabl


改动測试:spec/products/products_controller_spec.rb

render_views

describe ‘products controller‘ do
   before(:all) do
      @products = [
         Product.new({:id => 1, :name => ‘apple juice‘, :description => ‘good‘}),
         Product.new({:id => 2, :name => ‘banana juice‘, :description => ‘just so so‘})
      ]
   end

   it ‘get index of products‘ do
      expect(Product).to receive(:all).and_return(@products).once

      get :index, {:format => :json}
      expect(response).to have_http_status(200)

      products_json = JSON.parse(response.body)
      expect(products_json.size).to eq(2)
   end
end


执行測试rake spec

得到错误:

NameError:
       uninitialized constant Product


创建model Product:

rails g model Product name:string description:text

rake db:migrate


执行測试rake spec

得到错误:

    Failure/Error: products_json = JSON.parse(response.body)
     JSON::ParserError:
       A JSON text must at least contain two octets!

这是由于我们的response不正确,而且我们没有配置怎么获取json格式的输出。


创建文件: app/views/products/index.json.rabl

collection @products, :object_root => false
attributes :name


再次执行測试rake spec,測试通过


step3: 加入很多其它的字段

在 spec/products/products_controller_spec.rb中

products_json = JSON.parse(response.body)
expect(products_json.size).to eq(2)

expect(products_json[0][‘id‘]).to eq(1)
expect(products_json[1][‘id‘]).to eq(2)

expect(products_json[0][‘name‘]).to eq(‘apple juice‘)
expect(products_json[1][‘name‘]).to eq(‘banana juice‘)

expect(products_json[0][‘description‘]).to eq(‘good‘)
expect(products_json[1][‘description‘]).to eq(‘just so so‘)

expect(products_json[0][‘uri‘]).to end_with(‘/products/1‘)
expect(products_json[1][‘uri‘]).to end_with(‘/products/2‘)


在app/views/products/index.json.rabl中

collection @products, :object_root=>false
attributes :id, :name, :description

node :uri do |product|
   product_url product
end


4.GET /products => user get a product of specified id

step 1: 创建相应的controller方法。返回HTTP 200

加入測试:spec/products/products_controller_spec.rb

it ‘get product by product id‘ do
   get :show, {:id => 1}
   expect(response).to have_http_status(200)
end


相应改动:app/controllers/products_controller.rb

def show
   render :nothing => true
end


相应改动:config/routes.rb

resources :products do
   collection do
      get :index
   end

   member do
      get :show
   end
end

rake spec測试通过


step 2:创建相应的JSON显示

加入測试:spec/products/products_controller_spec.rb

before(:all) do
   #... ...
   @product = Product.new({:id => 1, :name => ‘apple juice‘, :description => ‘good‘})
end

it ‘get product by product id‘ do
   expect(Product).to receive(:find).with(1).and_return(@product).once

   get :show, {:id => 1, :format => :json}
   expect(response).to have_http_status(200)

   product_json = JSON.parse(response.body)
   expect(product_json[‘id‘]).to eq(1)
   expect(product_json[‘name‘]).to eq(‘apple juice‘)
   expect(product_json[‘description‘]).to eq(‘good‘)
   expect(product_json[‘uri‘]).to end_with(‘/products/1‘)
end


相应改动:app/controllers/products_controller.rb

def show
   @product = Product.find(params[:id].to_i)
end

Q:params[:id].to_i,为什么这里从測试代码过来的params[:id]它使一个string类型呢


加入JSON显示:app/views/products/show.json.rabl

object false

node(:id) { |product| @product.id }
node(:name) { |product| @product.name }
node(:description) { |product| @product.description }
node(:uri) { |product| product_url @product }


执行測试,通过


step 3:重构rabl

改动app/views/products/show.json.rabl

object @product

attributes :id, :name, :description

node(:uri) { |product| product_url product }


改动app/views/products/index.json.rabl

collection @products

extends ‘products/show‘


配置rabl:创建文件config/initializers/rabl_config.rb

Rabl.configure do |config|
   config.include_json_root = false
end


执行測试,通过,这样降低了rabl间的反复代码


step 4:HTTP 404

加入測试:spec/products/products_controller_spec.rb

it ‘get 404 when product not found‘ do
   expect(Product).to receive(:find).with(100).and_raise(ActiveRecord::RecordNotFound)

   get :show, {:id => 100, :format => :json}
   expect(response).to have_http_status(404)
end


相应改动:

class ProductsController < ApplicationController
   rescue_from ActiveRecord::RecordNotFound, with: :product_not_found

   #... ... 

   def show
      @product = Product.find(params[:id])
   end

   protected
      def product_not_found
         response.status = :not_found
      end
end

參考rescue_from


(更新中,欢迎不吝赐教)

将会要改动的部分是怎样笔试rspec,参考:http://betterspecs.org/

版权声明:本文博主原创文章,博客,未经同意不得转载。

有意练习--Rails RESTful(一)

标签:

原文地址:http://www.cnblogs.com/lcchuguo/p/4817617.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!