Displaying articles with tag url

Ruby on Rails :: Restful URL Customizing

Posted by PunNeng, Sun Sep 02 19:52:00 UTC 2007

อีกหนึ่งส่วนสำคัญของเรื่องนี้ คือ url ของการใช้งาน restful ของ rails
ลองอ่าน restful ของ rails ก่อน ผมติดไว้ว่าจะเขียนเรื่อง routing ไว้ ก็จะเขียนต่อตรงนี้เลยละกัน

หลังจากที่ประกาศ

map.resources :products

ใน config/route.rb แล้ว จะมีชื่อของ route ที่ถูกสร้างไว้เพียบเลย แต่ที่ใช้บ่อยๆ กับ CRUD คร่าวๆ ตามนี้

  • products_path (get -> index) # /products
  • products_path (post -> create) # /products
  • product_path(:id) (get -> show) # /products/:id
  • product_path(:id) (put -> update) # /products/:id
  • product_path(:id) (delete -> destroy) # /products/:id
  • new_product_path (get -> new) # /products/new
  • edit_product_path (get -> edit) # /products/:id;edit

ซึ่งจริงๆ แล้ว _path ก็จะมี _url ไว้ให้เรียกใช้อีกชุดนึง

สำหรับการ map เข้าในแต่ละ action จะทำได้ด้วยการกำหนด request method

Get (Read)

จะใช้ get สำหรับการ request ขอข้อมูล

link_to "List Products", products_path
link_to @product.title, product_path(@product)

ปกติจะใช้กับ link

Post (Create)

จะใช้ post สำหรับการสร้าง หรือการเพิ่มเข้าฐานข้อมูล

<% form_for(:product, :url => products_path) do |f| %>

ปกติจะใช้กับ form

Put (Update)

จะใช้ put สำหรับการปรับปรุงข้อมูลที่มีอยู่แล้ว

<% form_for(:product, :url => product_path(@product), :html => { :method => :put }) do |f| %>

ปกติใช้กับ form เช่นกัน

Delete (Delete)

จะใช้ delete สำหรับการลบ

<%= link_to 'Destroy', product_path(product), :confirm => 'Are you sure?', :method => :delete %>

จริงๆ ไม่จำเป็นเท่าไหร่ว่า method อันไหน ใช้กับอะไร เพียงแต่ใส่ method ให้ได้ ก็ใช้ได้เหมือนๆ กัน

ต่อไป จะทำการกำหนด action ที่นอกเหนือจาก CRUD
ซึ่งผมเคยเขียนไปครั้งนึงแล้ว ลองหยิบตัวอย่างมาสองสามอันที่ใช้บ่อยๆ ละกัน

map.resources :messages, :path_prefix => "/threads/:thread_id"
# --> GET /threads/7/messages/1

หรือใช้ nest

map.resources :threads do |thread| thread.resources :messages end

เวลาเรียกใช้ จะเรียกแบบนี้

<%= link_to @message.title, message_path(@thread, @message) %>
<%= link_to "Message List", messages_path(@thread) %>
<%= link_to @message.title, message_path(:thread_id => @thread, :id => @message.id) %>
<%= link_to "Message List", messages_path(:thread_id => @thread) %>

ยืดหยุ่นสุดๆ อยากใช้แบบไหน ก็ได้เหมือนๆ กัน ถ้าใส่ instance ลงไป ก็จะยิงไปที่ id อัตโนมัติ หรือถ้าเป็นค่าอื่น ก็ระบุไป ถ้าไม่ระบุ ก็เป็น id

ข้อสังเกตอีกนิดนึง คือการระบุให้เป็น singular/plural ถ้าเป็น singular ก็ต้องระบุไป ว่าอันไหน ถ้าไม่ต้องการทำกับ instance ตัวไหนตัวนึงหรือต้องการทำทีละหลายๆ ตัว ก็ระบุเป็น plural ไป จริงๆ เรื่องนี้ใช้ความเข้าใจเอาก็ได้ เพราะมันก็เหมือนๆ english นั่นแหละ :)

map.resources :messages, :collection => { :rss => :get }
# --> GET /messages;rss (maps to the #rss action)
# also adds a url named "rss_messages"

:collection ไว้ใช้กับ plural
วิธีใช้

<%= link_to "RSS", rss_messages_path %> # --> GET /messages;rss (maps to the #rss action)

จะเซ็ตเป็น post ก็ได้ แล้วใส่ที่ form ก็ได้เหมือนๆ กัน สำหรับตัวอย่างการใช้งานกับ form ดูได้จากการที่ใช้ scaffold_resource สร้างมาให้ก็ได้

map.resources :messages, :member => { :mark => :post }
# --> POST /messages/1;mark (maps to the #mark action)
# also adds a url named "mark_message"

คราวนี้ ไว้ใช้กับ singular เช่น

<% form_for :message, @message, :url => :url => mark_message_path(@message) do |f| %>

ผมขี้เกียจละ ตัวอย่างที่่เหลือ คิดว่าคงจะพอเข้าใจอะไรลางๆ แล้วละครับ

map.resources :messages, :new => { :preview => :post }
# --> POST /messages/new;preview (maps to the #preview action)
# also adds a url named "preview_new_message"

map.resources :messages, :new => { :new => :any, :preview => :post }
# --> POST /messages/new;preview (maps to the #preview action)
# also adds a url named "preview_new_message"
# --> /messages/new can be invoked via any request method

map.resources :messages, :controller => "categories",
:path_prefix => "/categories/:category_id",
:name_prefix => "categories_"
# --> GET /categories/7/messages/1
# has named route "categories_messages"

อีกนิดนึง ใน rails 2.0 มันเปลี่ยนเครื่องหมายนิดหน่อย จาก /messages;rss เปลี่ยนมาเป็น /messages/rss แทน

ปล. มันมี map.resource อีกตัวนึง แต่ไว้ใช้สำหรับ singleton ซึ่งผมยังไม่เคยใช้เลย

1 comment | Filed Under: Ruby on Rails | Tags: url

Ruby on Rails :: URL Customizing

Posted by PunNeng, Wed Aug 29 22:22:00 UTC 2007

กลับมาเขียนกันต่อ

ว่าจะเขียนเรื่อง route ใน rails มานานละ แต่เนื่องจากมันมีอะไรเพิ่มมาตลอด เลยต้องรอมันนิ่งก่อน แต่รอไปรอมา rails 2.0 ก็จะมาอีกแล้ว =='

ไม่เป็นไร เอาเท่าที่มีไปก่อน

จาก post อันเก่าๆ ที่เคยเขียนไป ลักษณะของ url ใน rails จะเป็นแบบนี้

/:controller/:action:/:id

นี่เป็นตัว default ของมัน ลองเปิดใน config/route.rb จะเจอ

map.connect ':controller/:action/:id.:format'
map.connect ':controller/:action/:id'

มันจะถูก map ใน controller โดยจะอยู่ในรูป

params = { :controller => 'blog', :action => 'edit', :id => '22' }

นีี่เป็นตัวกำหนดค่า default ของมัน ซึ่งเราสามารถกำหนดนามสกุลได้ด้วย เผื่อบางคนอยากได้แบบเดิมๆ เพื่อความเป็นมิตรกับ search engine
ใน controller เราจึงเรียกใช้งานได้โดย

params[:controller] # or params[:action] # or params[:id]

ถ้าจะเปลี่ยนหรือปรับปรุง จะทำไง มาดูกัน

เราสามารถกำหนด parameters เพิ่มให้มันได้ เช่น

map.connect 'articles/:year/:month/:day', :controller => 'articles', :action => 'find_by_date'

ดูเปลี่ยนไปละ
ใน controller/action เราจะเรียกเพิ่มได้ว่า

params[:controller] #=> articles params[:year] #=> ???? params[:month] #=> ?? params[:day] #=> ??

อันนี้ยังไม่ดีพอ มันยังดูกำกวม แบบนี้น่าจะดูดีกว่า

map.connect 'articles/:year/:month/:day', :controller => 'articles', :action => 'find_by_date', :year => /\d{4}/, :month => /\d{1,2}/, :day => /\d{1,2}/

แบบนี้ชัดเจนเลย ใส่ regular expression ลงไปได้ด้วย

อีกหนึ่งอย่างที่ผมชอบคือ การกำหนดชื่อของ route เช่น

map.login 'login', :controller => 'session', :action => 'login' map.show_account 'account/:id', :controller => 'account', :action => 'show'

จาก map.login เราจะใช้งานมันได้โดย

link_to "Login", login_path
link_to "View Account", show_account_path(:id => @account)

เราจะได้

<a href="/login">Login<a>
<a href="/account/2">View Account<a>

ถ้าอยากได้ url แบบ full path ก็แค่เปลี่ยนจาก login_path เป็น login_url

สมมติว่า controller เราต้อง rewrite อยู่ทุกๆ action ก็สามารถย่อโดยใช้ with_options ได้เป็น

map.with_options :controller => 'blog' do |blog| blog.show '', :action => 'list' blog.delete 'delete/:id', :action => 'delete', blog.edit 'edit/:id', :action => 'edit' end

ก็จะใช้ังานได้โดย

link_to @article.title, show_path(:id => @article)

ที่เหลืออีกเล็กๆ น้อยๆ

ActionController::Routing::Routes.draw do |map| map.connect '/', :controller => 'home' map.connect 'sitemap.xml', :controller => 'home', :action => 'sitemap' ... end

นี่เป็น pattern ง่าย โดยมันจะเรียงลำดับความสำคัญจากบนลงล่าง
url ที่เข้ามา ถ้าจับคู่กับ pattern อันไหนก่อน ก็เข้าเงื่อนไขนั้น

อีกอย่าง

map.connect '*path' , :controller => 'home' , :action => 'unrecognized?'

อันนี้ไว้สำหรับประกาศในทุกๆ กรณีของ url ที่เข้ามา หน้าที่ของมันง่ายๆ คือไว้ดัก url ที่ไม่มีนั่นแหละ

กรณีที่มีการสร้าง route แบบ run-time ยังสามารถสั่ง reload ได้โดย

Action::Controller::Routes.reload

ปล. ไว้จะมาต่อเรื่อง routing ของ restful กันอีกทีครับ

ข้อมูลจาก api ของ rails ครับ

0 comments | Filed Under: Ruby on Rails | Tags: url

codegent: we're hiring