2010年1月8日金曜日

Inspecting Requests

我々のアプリは、いまだちょっと静的に見えます。と言うのも、ページを動的に生成してはいるのですが、外部ユーザに新しい投稿を許すような設計にまだなっていないから、です。ここをやっつけてしまいましょう。ユーザに新しいブログエントリ用のフォームを提供しましょう。ユーザが実行ボタンを押すと、ページの頭に新しい投稿が現れるようにするのです。

今まではrequestオブジェクトで何かをする、と言う事を避けてきました。しかし、requestオブジェクトは避けるべきものではありません!ユーザがwebフォームに何か入力して投稿すると、ユーザのブラウザはフォームの値を保持した新しいrequestを生成します。ここでは、ユーザが入力した値を受け取るrequest-bindings機能を使います。request-bindingsの型は:

request-bindings : (request? . -> . bindings?)

です。
request-bindingsに加えて、名前を受け取り、その名前に関連した値を返すextract-binding/single機能と言うものもあります。

extract-binding/single : (symbol? bindings? . -> . string?)

最後に、exists-binging?で束縛に名前があるかどうかチェックします。

exists-binding? : (symbol? bindings? . -> . boolean?)

これらの機能を使って、requestを受け取り、何か役立つ事を行う機能を実装しましょう。

Exercise.bingings?を受け取るcan-parse-post?と言う機能を書いてみましょう。'title'bodyと二つのシンボルに束縛されたものがあれば#tを返し、そうじゃなければ#fを返します。


can-parse-post? : (bindings? . -> . boolean?)


Exercise.束縛を受け取るcan-parse-post?と言う機能を書いてみましょう。ここではでは'title'bodyと言うシンボルに値が束縛されている構造とします。parse-postはこれらの値を含む投稿を生成します。

parse-post : (bindings? . -> . post?)


さて、これらの補助機能を用いて、入力フォームを操れるようにwebアプリを拡張します。ページの最後に小さな入力フォームを付け加えて、新規投稿を加えられるようにプログラムを変更してみましょう。そして、startメソッドは、最初にリクエストがパース可能であるかどうか調べ、そうであるならば、投稿セットを拡大し、最終的にこれらのブログ投稿を表示するようにします。


#lang web-server/insta

; ブログは (listof post) で
; 投稿は (make-post title body)
(define-struct post (title body))

; BLOG: blog
; 静的ブログ
(define BLOG
(list (make-post "First Post" "This is my first post")
(make-post "Second Post" "This is another post")))

; start: request -> html-response
; リクエストを受け取り全てのwebコンテンツを
; 表示するページを生成する
(define (start request)
(local [(define a-blog
(cond [(can-parse-post? (request-bindings request))
(cons (parse-post (request-bindings request))
BLOG)]
[else
BLOG]))]
(render-blog-page a-blog request)))


; can-parse-post?: bindings -> boolean
; 束縛が 'title と 'body を含む値がある場合、真を返す
(define (can-parse-post? bindings)
(and (exists-binding? 'title bindings)
(exists-binding? 'body bindings)))


; parse-post: bindings -> post
; 束縛を受け取り、取り出した投稿を返す
(define (parse-post bindings)
(make-post (extract-binding/single 'title bindings)
(extract-binding/single 'body bindings)))

; render-blog-page: blog request -> html-response
; ブログをリクエストを受け取り、ブログコンテンツである
; html-response ページを生成する
(define (render-blog-page a-blog request)
`(html (head (title "My Blog"))
(body
(h1 "My Blog")
,(render-posts a-blog)
(form
(input ((name "title")))
(input ((name "body")))
(input ((type "submit")))))))



; render-post: post -> html-response
; 投稿を受け取り、html-response 要素を生成する
(define (render-post a-post)
`(div ((class "post"))
,(post-title a-post)
(p ,(post-body a-post))))


; render-posts: blog -> html-response
; ブログを受け取り、全投稿の html-response
; 要素を生成する
(define (render-posts a-blog)
`(div ((class "posts"))
,@(map render-post a-blog)))


これは動くように見えますが・・・一つ問題があります!二つの新規投稿をしてみてください。一体、何が起きるでしょうか?

0 件のコメント:

コメントを投稿