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

当你的练习时间达到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(一)的更多相关文章

  1. 从0使用Ruby on Rails打造企业级RESTful API项目实战之我的云音乐

    本节对我们项目实现的功能和知识点做一个简单的介绍,因为是RESTful API项目,所以对于后端来说基本上没有什么UI界面可展示,那我们就在关键的点,使用客户端(Android)实现的效果图. 课程简 ...

  2. Rails ---> routes.rb 详解

    理解路由的目的 看懂routes.rb文件中的代码 使用经典的hash风格或者现在比较流行的Restful风格构造你自己的路径 断定一个路径会映射到哪一个controller和action 路由的双重 ...

  3. Rails : 产品环境(生产环境)的部署

    bundle install rails server (默认为开发环境) rails server -p80 -e production (指定为生产环境 ,并自定义指定站点端口) rake RAI ...

  4. RESTFUL接口

    原文地址:http://kb.cnblogs.com/page/512047/ 1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者 ...

  5. Building a RESTful Web Service Using Spring Boot In Eclipse

    一.构建restful web service 创建Maven的java web工程,maven的pom文件加入依赖包 创建包hello Greeting.java package hello; pu ...

  6. RESTful架构详解(转)

    1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的 ...

  7. 虚拟研讨会:如何设计好的RESTful API?

    http://www.infoq.com/cn/articles/how-to-design-a-good-restful-api/ REST架构风格最初由Roy T. Fielding(HTTP/1 ...

  8. 使用 Struts 2 开发 RESTful 服务

    REST 简介 REST 是英文 Representational State Transfer 的缩写,这个术语由 Roy Thomas Fielding 博士在他的论文<Architectu ...

  9. 【转】REST on Rails指南

    REST on Rails指南1:理解资源 这是来自http://www.softiesonrails.com的REST简明指南. PART I 在理解REST on Rails之前,有必要先思考一下 ...

随机推荐

  1. Spring——AOP配置时的jar包异常

    首先:这不是SSH整合的,这是单独配置Spring AOP的一个小例子. 所需要的jar包:如图: 我在这里出现的两个问题: 1.没有导入asm的jar包. 所报的异常为: java.lang.Cla ...

  2. UVALive - 4621 Cav 贪心 + 分析

    题目大意:有一张洞穴地图,要在这个洞穴里面存放水,要求水不能碰到洞穴顶部.如今给出每一个位置的顶部位置和地面高度.问最多能够放多少水 解题思路:根据物理定理,每一段有水的连续区间,水位高度必须相等 所 ...

  3. HiPAC高性能规则匹配算法之查找过程

    收到一封邮件,有位朋友认为我误解了nf-HiPAC.如此的一个高性能算法怎能被什么传统的hash,tree之类的胁迫.是啊.HiPAC是一个非常猛的算法.文档也比較少,这就更加添加了其神奇感,可是这决 ...

  4. APUE学习总结

    简介 本文总结了个人,一个数字,对应称号<APUE>第一版的每一章,但是,独立的二级标题和书,人需求进行编写. 3.文件I/O 本章所说明的函数常常被称之为不带缓存的I/O(与第5章中说明 ...

  5. Div 滚动栏滚动到指定的位置

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. Android适应方案汇总(三)

    在Android适应方案汇总(一个).(两)在.我们理解一些基本概念. 那么详细的开发,我们应该重视起来. 首先,我们需要知道.关键的事实是,这两个适配器: (1).这点在单位的使用上用dp.sp以及 ...

  7. Mahout推荐算法ItemBased

    Mahout推荐的ItemBased 一.   算法原理 (一)    基本的 下面的例子,参见图评分矩阵:表现user,归类为item. 图(1) 该算法的原理: 1.  计算Item之间的相似度. ...

  8. Oracle在不同的语言环境结果to_date错误的问题

    我写了一个存储过程,它使用了功能,有一些功能to_date(dateFrom, 'yyyy/mm/dd').执行发现数据插入错误后,数据插入"0001/9/14". 感觉莫名其妙, ...

  9. JDK源代码学习系列07----Stack

                                                                   JDK源代码学习系列07----Stack 1.Stack源代码很easy ...

  10. cocos2d-x路~使得第一个字游戏(一个)

    前言 去年的回忆.另外,在第三.他们开发了他们的第一场比赛四月,它是游戏.所以我决定走上独立开发的道路上.了.第一款游戏达到它应有的盈利水平.然而这款游戏开发后的时间里.都没再取得还有一款令自己惬意的 ...