刻意练习--Rails RESTful(一)

一本被人反复提及的书《哪儿来的天才》中说过,大部分所谓的天才都是通过反复的刻意练习得到的。当你的练习时间达到10000小时以后,你就会成为该领域的专家。

最近在学习rails如何实现RESTful Web Service。自己想给自己设计一个练习的模板,进行反复练习。开发过程采用的是TDD的方式进行开发。

练习背景:

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

1.新建工程rails-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(一),布布扣,bubuko.com

时间: 2024-10-14 19:06:15

刻意练习--Rails RESTful(一)的相关文章

有意练习--Rails RESTful(一)

书要反复提及<哪里有天才>在说,大多数所谓的天才是通过反复刻意练习获得. 当你的练习时间达到10000几个小时后,.你将成为该领域的专家. 近期在学习rails怎样实现RESTful Web Service. 自己想给自己设计一个练习的模板,进行重复练习. 开发过程採用的是TDD的方式进行开发. 练习背景: 我们涉及三个Domain对象,Products.Orders.Payment 1.新建projectrails-rest-practice rails new rails-rest-pra

CXF+Spring+JAXB+Json构建Restful服务

话不多说,先看具体的例子: 文件目录结构: web.xml <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://

RESTful架构详解

1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一. 他在论文中提到:“我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强.性能好.适宜通信的架构.REST指的是一组架构约束条件和原则.” 如果一个架构符合REST的约束条件

RESTful架构详解(转)

1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一. 他在论文中提到:“我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强.性能好.适宜通信的架构.REST指的是一组架构约束条件和原则.” 如果一个架构符合REST的约束条件

linux-mint下搭建android,angularjs,rails,html5开发环境

目录[-] 必备软件: 环境配置: [open-jdk-6.0] [android-sdk] [ant] [github] [node.js] [rvm](ruby-1.9.3 rails-4.0.0 gemfile) 必备概念: 关于自动化部署我推荐大家参谋一下Fortune Zhang的一篇文章:android开发过程中我是怎么一步步让项目自动化起来的 最新更新链接:https://gist.github.com/Channely/8296901 系统以64bit为例进行配置/2013/11

restful

1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一. 他在论文中提到:"我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强.性能好.适宜通信的架构.REST指的是一组架构约束条件和原则." 如果一个架构符合REST

转载-- http接口、api接口、RPC接口、RMI、webservice、Restful等概念

http接口.api接口.RPC接口.RMI.webservice.Restful等概念 收藏 Linux一叶 https://my.oschina.net/heavenly/blog/499661 发表于 1年前 阅读 1422 收藏 28 点赞 0 评论 0 摘要: 在这之前一定要好好理解一下接口的含义,我觉得在这一类中接口理解成规则很恰当 在这之前一定要好好理解一下接口的含义,我觉得在这一类中接口理解成规则很恰当.         http接口:基于HTTP协议的开发接口.这个并不能排除没

RESTful 架构详解

1. 什么是REST REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移. 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一. 他在论文中提到:"我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强.性能好.适宜通信的架构.REST指的是一组架构约束条件和原则." 如果一个架构符合REST

Rails + rabl

当我们使用rails generate scaffold的方式生成MVC的时候,rails会自动给我们生成一系列的文件,包括了如何用json显示model的view.这样其实默认了你的系统是一个CRUD的系统,但是我们知道RESTful不是CRUD.把model直接暴露出去不是一个很好的选择. rabl是一个DSL可以方便定制生成对象的显示信息的gem:https://github.com/nesquena/rabl 下面是具体的操作过程: 1.首先创建一个新的rails工程: rails ne