Deliberate practice-rails restful (1)

Source: Internet
Author: User
Tags http 200

As said in the book "where is the genius", many so-called geniuses are obtained through repeated deliberate exercises. When your exercise time reaches 10000 hours, you will become an expert in this field.


I recently learned how to implement restful Web Service in rails. I want to design an exercise template for myself and perform the exercises repeatedly. The development process adopts TDD for development.


Exercise Background:

We have three domain objects: Products, orders, and payment.


1. Create a new project rails-rest-Practice

Rails new rails-rest-Practice

CD! $

Bundle install


2. Install rspec-rails

Add in gemfile

Gem "rspec-rails",: Group => [: development,: Test]

Then

Bundle install

Rails g rspec: Install

Remove -- warnings from. rspec


3. Get/products => User get List of Products

Step 1: Create a controller and return HTTP status 200

The user products API is as follows:

GET/products user get List of Products


Create a file: 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
Response CT (response).Have_http_status(200)
End
End
End


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


Create a file: APP/controllers/products_controller.rb

Class productscontroller <applicationcontroller
Def Index
End
End


Run rake spec and get an error:

Actioncontroller: urlgenerationerror:
No route matches {: Action => "Index",: controller => "Products "}


Configure config/routes. Rb

Resources: products do
Collection do
Get: Index
End
End


Run rake spec and get an error:

Failure/error: Get: Index
Actionview: missingtemplate:

Modify APP/controllers/products_controller.rb

Class productscontroller <applicationcontroller
Def Index
Render: Nothing => true
End
End


This completes our first step. Although it seems that this step has not been tested, it is actually not. In this step, we have set up routes, at the same time, a necessary controller class and its corresponding methods are created.


Step 2: Return JSON

Install rabl

Add rabl to gemfile

Gem 'rabl'

Bundle install

Refer to rails + rabl


Modify and test: 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
Keep CT (product). To receive (: All). and_return (@ products). Once

Get: Index,{: Format =>: JSON}
CT (response). To have_http_status (200)

Products_json = JSON. parse (response. Body)
Reverse CT (products_json.size). To eq (2)
End
End


Run the test rake spec

Error:

Nameerror:
Uninitialized constant Product


Create model product:

Rails G model Product Name: String Description: Text

Rake DB: migrate


Run the test rake spec

Error:

Failure/error: products_json = JSON. parse (response. Body)
JSON: parsererror:
A json text must at least contain two octets!

This is because our response is incorrect and we have not configured how to obtain the output in JSON format.


Create a file: APP/views/products/index. JSON. rabl

Collection @ products,: object_root => false
Attributes: Name


Run rake spec again and pass the test


Step 3: add more fields

In spec/products/products_controller_spec.rb

Products_json = JSON. parse (response. Body)
Reverse CT (products_json.size). To eq (2)

CT (products_json [0] ['id']). To eq (1)
CT (products_json [1] ['id']). To eq (2)

Round CT (products_json [0] ['name']). To eq ('apple juice ')
Reverse CT (products_json [1] ['name']). To eq ('banana juice ')

CT (products_json [0] ['description']). To eq ('good ')
CT (products_json [1] ['description']). To eq ('Just so so ')

CT (products_json [0] ['uri ']). To end_with ('/products/1 ')
CT (products_json [1] ['uri ']). To end_with ('/products/2 ')


In 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: Create the corresponding Controller method and return HTTP 200

Add test: spec/products/products_controller_spec.rb

It 'get product by product id' do
Get: Show, {: Id => 1}
CT (response). To have_http_status (200)
End


Corresponding modification: APP/controllers/products_controller.rb

Def show
Render: Nothing => true
End


Corresponding modification: config/routes. Rb

Resources: products do
Collection do
Get: Index
End

Member do
Get: Show
End
End

Rake spec passed the test.


Step 2: Create the corresponding JSON display

Add test: 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
Keep CT (product). To receive (: Find). With (1). and_return (@ Product). Once

Get: Show, {: Id => 1,: format =>: JSON}
CT (response). To have_http_status (200)

Product_json = JSON. parse (response. Body)
CT (product_json ['id']). To eq (1)
Round CT (product_json ['name']). To eq ('apple juice ')
CT (product_json ['description']). To eq ('good ')
CT (product_json ['uri ']). To end_with ('/products/1 ')
End


Corresponding modification: APP/controllers/products_controller.rb

Def show
@ Product = product. Find (Params [: Id]. to_ I)
End

Q: Params [: Id]. to_ I, why does Params [: Id] from the test code make a string type?


Add JSON display: 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}


Run the test and pass


Step 3: reconstruct rabl

Modify APP/views/products/show. JSON. rabl

Object @ Product

Attributes: ID,: name,: Description

Node (: URI) {| product | product_url product}


Modify APP/views/products/index. JSON. rabl

Collection @ Products

Extends 'products/show'


Configure rabl: Create the file config/initializers/rabl_config.rb.

Rabl. Configure do | config |
Config. include_json_root = false
End


Run the test and pass. This reduces the repeated code between rabl.


Step 4: HTTP 404

Add test: spec/products/products_controller_spec.rb

It 'get 404 when product not found 'do
Wrong CT (product). To receive (: Find). With (100). and_raise (activerecord: recordnotfound)

Get: Show, {: Id => 100,: format =>: JSON}
CT (response). To have_http_status (404)
End


Corresponding modification:

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

Refer to rescue_from


(Updating. Please advise)

The part that will be modified is how to write rspec, see: http://betterspecs.org/

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.