418342 ภาคปลาย 2552/การบ้าน 3
(กำลังเขียนอยู่) ในการบ้านนี้เราจะทำการสร้างระบบบล็อกเบื้องต้นที่มีฟีเจอร์ดังต่อไปนี้
- มีหน้าหลักแสดงโพสต์ล่าสุด
- มีระบบให้ผู้อ่านมาพิมพ์คอมเมนต์
- มี RSS Feed ของโพสต์
- ผู้เขียนสามารถตั้งค่าต่างๆ ของบล็อก เช่น ชื่อบล็อก, จำนวนโพสต์ที่แสดงในแต่ละหน้า, ฯลฯ
- ผู้เขียนสามารถแท็กบทความต่างๆ ได้
เนื้อหา
เริ่มต้น
- ให้ดาวน์โหลดโค้ดเริ่มต้นจาก ... ในโค้ดเริ่มต้นนี้จะมี scaffold ซึ่งสร้างตามฐานข้อมูลที่เขียนไว้ข้างล่าง พร้อมกับข้อมูลทดสอบส่วนหนึ่งอยู่
- ให้ลงไลบรารี Maruku ซึ่งเป็นตัวแปรภาษา Makrdown ที่เราจะใช้ในการเขียนเนื้อหาของบล็อก ด้วยการสั่ง
gem install maruku
ฐานข้อมูล
ฐานข้อมูลของระบบบล็อกจะประกอบด้วยตารางต่อไปนี้
ตาราง posts
เก็บโพสต์ของเจ้าของบล็อก มีฟีลด์ดังต่อไปนี้
- title เป็น string
- content เป็น text ซึ่งเขียนด้วยภาษา Markdown
- published_at เป็น datetime ซึ่งจะมีค่าเป็น nil ถ้าหากผู้ใช้ยังไม่ได้ตีพิมพ์โพสต์นี้
- timestamp (created_at และ modified_at) ซึ่งสร้างด้วย t.timestamp ใน migration
ตาราง comments
เก็บคอมเมนต์ที่มีคนมาเขียน มีฟีลด์ดังต่อไปนี้
- name เป็น string เก็บชื่อคนเขียน comment
- email เป็น string เก็บ email ของคนเขียน comment
- url เป็น string เก็บ URL ของเว็บไซต์ของคนเขียน comment
- content เป็น text ซึ่งเขียนด้วยภาษา Markdown เช่นกัน
- post_id เป็น integer ซึ่งเก็บ id ของ post ที่ comment
- timestamp (created_at และ modified_at) ซึ่งสร้างด้วย t.timestamp ใน migration
ตาราง tags
เก็็บ tag ต่างๆ มีฟีลด์ดังต่อไปนี้
- name เป็น string ซึ่งเป็นชื่อของ tag
ตาราง posts_tags
ใช้ในการทำความสัมพันธ์แบบ many-to-many ระหว่าง post กับ tag มีฟีลด์ดังต่อไปนี้
- post_id
- tag_id
ตาราง settings
เก็บค่าต่างๆ ที่ผู้ใช้สามารถกำหนดให้บล็อกได้ เช่น ชื่อบล็อก ฯลฯ มีฟีลด์ดังต่อไปนี้
- name เป็น string ซึ่งเป็นชื่อของค่าที่ผู้ใช้กำหนดได้
- value เป็น string ซึ่งเก็บค่าจริง
ในตาราง settings จะมีค่าต่อไปนี้อยู่
- blog_name = ชื่อของบล็อก (จะปรากฏอยู่ที่หัวเว็บเพจ)
- blog_subtitle = คำอธิบายบล็อกสั้นๆ (จะปรากฏอยู่ที่หัวเว็บเพจเช่นกัน)
- blog_url = URL ของบล็อกซึ่งมีไว้ใช้ทำ RSS feed
- posts_per_page = จำนวนบล็อกในแต่ละหน้า
- comment_count = จำนวนคอมเมนต์เริ่มต้นที่แสดงเวลาดูโพสต์
การบ้านข้อ 1: แก้ไขโมเดล
แก้ไข Post
- ทำให้ Post มีความสัมพันธ์แบบ many-to-many กับ Tag
- ทำให้ Post มีความสัมพันธ์แบบ many-to-one กับ Comment
- เขียน validation ทำให้ Post สอดคล้องกับเงื่อนไขต่อไปนี้
- title จะต้องไม่ว่างเปล่า
- content จะต้องไม่ว่างเปล่า
- เขียนเมธอดชื่อ published? เพื่อเช็คว่าผู้ใช้ได้ตีพิมพ์โพสต์ไปแล้วหรือยัง โดย method จะเช็คว่า published_at มีค่าเป็น nil หรือไม่ ถ้าใช่แสดงว่ายังไม่ได้ตีพิมพ์
เมื่อคุณแก้โค้ดตามนี้แล้ว ให้ลองรัน
rake test:units TEST=unit/test/post_test.rb
เพื่อตรวจสอบว่าได้แก้ไขไปถูกต้องแล้วหรือไม่
แก้ไข Comment
เขียน validation ทำให้ Comment สอดคล้องกับเงื่อนไขต่อไปนี้
- name จะต้องไม่ว่างเปล่า
- email จะต้องมีรูปแบบเหมือน email (ใบ้: ใช้ validate_format_of)
- url จะต้องมีรูปแบบเหมือน URL จริงๆ (คือ http://something.someone.org/abc/def) (ใบ้: ไปหา regular expression มาจากใน net)
- content จะต้องไม่ว่างเปล่า
เมื่อคุณแก้โค้ดตามนี้แล้ว ให้ลองรัน
rake test:units TEST=unit/test/comment_test.rb
เพื่อตรวจสอบว่าได้แก้ไขไปถูกต้องแล้วหรือไม่
แก้ไข Tag
เขียน validation
ทำให้ Tag ที่มีรูปแบบถูกต้องทุกตัวสอดคล้องกับเงื่อนไขต่อไปนี้
- name จะต้องไม่ว่างเปล่า
- ใน name จะต้องไม่มีเครื่องหมายคอมมา (,) อยู่ภายใน (เนื่องจากเราใจใช้เครื่องหมายนี้ในการแยก tag ต่างๆ ออกจากกัน) กล่าวคือ "space adventure" ใช้ได้ แต่ "space,adventure" หรือ "space, adventure" ใช้ไม่ได้
ทำให้ชื่อ Tag อยู่ในรูป "ปกติ"
เราต้องการให้เวลาเจ้าของบล็อกใส่ tag ให้โพสต์ แล้วเขาสามารถพิมพ์ "life, space adventure, computer security " แล้วระบบสามารถที่จะแยกมันออกเป็น 3 tag ได้แก่ "life", "space adventure", และ "computer security" ให้โดยอัตโนมัติ
เนื่องจากเราบอกว่าชื่อแท็กจะต้องไม่มีเครื่องหมายคอมมาอยู่ข้างใน ดังนั้นเราสามารถแยก string ที่ผู้ใช้ให้มาข้างบนเป็นสามส่วนคือ "life" และ " space adventure" และ " computer security "
เวลาเราเก็บชื่อของ Tag ใน database เราต้องการกำจัดข้อมูลที่ไม่สำคัญออกจากชื่อ Tag ที่ผู้ใช้ป้อนมาไป ยกตัวอย่างเช่น ผู้ใช้ป้อน " computer security " ซึ่งมีช่องว่างอยู่ข้างหน้าชื่อ ข้างหลังชื่อ และช่องว่างระหว่างคำว่า computer กับคำว่า security มีอยู่ถึงสามตัว แต่ในเวลาเก็บข้อมูลเราต้องการให้ชื่อมีค่าเท่ากับ "computer security" เท่านั้น กล่าวคือ
- จะต้องไม่มีช่องว่างนำหน้าชื่อ Tag
- จะต้องไม่มีช่องว่างตามหลังชื่อ Tag
- ระหว่างคำสองคำที่อยู่ข้างๆ กันในชื่อ Tag จะมีช่องว่างคั่นได้เพียงช่องเดียวเท่านั้น
เราเรียกชื่อที่สอดคล้องกับกฎทั้งสามข้อข้างต้นว่าเป็นชื่อ Tag ในรูป "ปกติ"
ตรวจสอบความถูกต้อง
จงเพิ่มคลาสเมธอด normalize_name(given_name) ในคลาส Tag โดยที่เมธอดนี้ืคืนค่าของ given_name เมื่อทำให้มันอยู่ในรูปปกติแล้ว
เวลาประกาศคลาสเมธอดให้ประกาศเช่นนี้ <geshi lang="rails"> class Tag
...
def Tag.normalize_name(given_name) ... end
...
end </geshi>
เมื่อคุณแก้โค้ดตามนี้แล้ว ให้ลองรัน
rake test:units TEST=unit/test/tag_test.rb
เพื่อตรวจสอบว่าได้แก้ไขไปถูกต้องแล้วหรือไม่
แก้ไข Setting
จงเขียน validation เพื่อทำให้ Setting ทุกตัวสอดคล้องกับเงื่อนไขต่อไปนี้
- name จะต้องไม่เป็นค่าว่าง
- value จะต้องไม่เป็นค่าว่าง
- ถ้า name มีค่าเท่ากับ "posts_per_page" หรือ "comment_count" แล้ว value จะต้องเป็นสตริงที่มีค่าเป็นตัวเลข
เมื่อคุณแก้โค้ดตามนี้แล้ว ให้ลองรัน
rake test:units TEST=unit/test/setting_test.rb
เพื่อตรวจสอบว่าได้แก้ไขไปถูกต้องแล้วหรือไม่
การบ้านข้อ 2: ทำให้ Markdown ใช้ได้
แก้ไข Post
ให้สร้างเมธอดชื่อ markdowned_content ซึ่งคืนค่า content ที่ถูกแปลด้วยภาษา Markdown แล้ว ในการแปลให้ใช้ไลบรารีชื่อ Maruku ซึ่งมีวิธีใช้บอกอยู่ในเอกสารนี้ http://maruku.rubyforge.org/usage.html
เมื่อคุณแก้โค้ดตามนี้แล้ว ให้ลองรัน
rake test:units TEST=unit/test/markdown_post_test.rb
เพื่อตรวจสอบว่าได้แก้ไขไปถูกต้องแล้วหรือไม่
แก้ไข Comment
สำหรับโมเดล Comment ก็ให้สร้างเมธอดชื่อ markdowned_content ซึ่งทำงานเช่นเดียวกันกับ markdowned_content ของ Post เช่นกัน
เมื่อคุณแก้โค้ดตามนี้แล้ว ให้ลองรัน
rake test:units TEST=unit/test/markdown_content_test.rb
เพื่อตรวจสอบว่าได้แก้ไขไปถูกต้องแล้วหรือไม่