深入淺出 RoR (4-3) - RESTful 與 CRUD action

posted 01 Nov 2008

Rails 1.2 引進了 REST 觀念。而在 Rails 2.0 ,RESTful 更成為這個版本的主要重點之一。

如果你對 RESTful Rails 不甚了解,推薦 RESTful Rails 簡單心得 這篇文章當入門磚。而希望深入了解的可以閱讀 ihower 的 什麼是 REST跟RESTful? 。不過我傾向建議你看完這篇文章再去啃這兩篇。

    ActionController::Routing::Routes.draw do |map|
        map.resources :blogs
    end

在 config/routes.rb 加入上面那一行,就是具體在 rails 實作 RESTful 支援的方式。

這樣的宣告將在自動對應 URL路徑跟 Controller 的 action ,而有以下的結果 :

    GET: /blogs => [:action => 'index']
    GET: /blogs.xml => [:action => 'index', :format => 'xml']
    GET: /blogs/1 => [:action => 'show', :id => 1]
    GET: /blogs/1/edit => [:action => 'edit', :id => 1]
    GET: /blogs/1.xml => [:action => 'show', :id => 1, :format => 'xml']
    POST: /blogs => [:action => 'create']
    PUT: /blogs/1 => [:action => 'update', :id => 1]
    DELETE: /blogs/1 => [:action => 'destroy', :id => 1]

也就是使用 named routes 來實作出 verb-oriented controllers,單一個 resource 根據 HTTP verb 而有不同的行為。

除了產生對應 routes 的 action 給 Controller,最方便的是自動產生了一些 helpers 給 views。

helpersHTTP Verb產生的Path對應的Action
blogs_path GET /blogs index
blog_path(id) GET /blogs/1 show
new_blog_path GET /blogs/new new
blogs_path POST /blogs create
edit_blog_path(id) GET /blogs/1/edit edit
bloh_path(id) PUT /blogs/1

update

blog_path(id) DELETE /blogs/1 destroy

相信這一些解說能大致讓你對 blogs_controller 或 view 裡的一些 path 有一些粗淺的了解。

verb-oriented 有什麼好處呢?最明顯的好處就是在 Rails 1.1 中需要花上很多功夫刻的 action code,在 Rails 2.x 中大部分都可以藉由 htttp verb 作掉。

本篇文章接下來對 controller 的 action 作一點簡單的解說。

index 是拉列表的動作。因此 Post.all 是拉出 Post 這個 model 所有的資料。

    def index
      @posts = Post.find(:all)
    end

show 秀出單筆資料。 Post.find(123) 是指找 Post model 裡 id 為 123 的資料。http://demosite.com/blogs/show/123 的 blogs 是 controller、show 是 action;如果在 route 裡面沒有特別指定,則 123 通常就是 params[:id]

    def show
      @post = Post.find(params`[`:id`]`)
    end

new 應該不必多說,就是 initial 一個 Post 的新 object。 def new @post = Post.new end

edit 這邊跟 show 相同的作法,是拉出 Post model 裡指定的 object ,只是資料拉出來,編輯。

    def edit
      @post = Post.find(params`[`:id`]`)
    end

create 這邊我們要翻回 app/views/blogs/new.html.erb 這個 view 並列一起來看。

    def create
      @post = Post.new(params`[`:post`]`)
      if @post.save
        flash[:notice] = 'Post was successfully created.'
        redirect_to blog_path(@post)
      else
        render :action => "new"
      end
    end

<h1>New post</h1>

<% form_for :post , :url => blogs_path do |f| -%>
    <%= f.error_messages %>
    <div><label>subject</label><%= f.text_field :subject %></div>
    <div><label>content</label><%= f.text_area :content %> </div>
    <%= f.submit "Submit", :disable_with => 'Submiting...' %>
<% end -%>


<%= link_to 'Back', blogs_path %>

在 RESTful Rails 的寫法中,對 blogs_path (就是 index action )丟 POST 就是對應到 create 的動作。而 Rails 在設計上,form 是綁 model 的,因此整個 form 的內容會被包成一個 hash,在這裡就是 params`[`:post`]`。create action 初始一個 object ,並把 params`[`:post`]` 整包塞進這個 object 裡。如果 @post 能夠成功的儲存,就「重導」到 index action ,失敗則「退回」到 new action 。

update 這邊我們也要翻回 app/views/blogs/edit.html.erb 這個 view 一起來看。

    def update
      @post = Post.find(params`[`:id`]`)
      if @post.update_attributes(params`[`:post`]`)
       flash[:notice] = 'Post was successfully updated.'
       redirect_to blog_path(@post)
      else
        format.html { render :action => "edit" }
      end
    end
<h1>Editing post</h1>
<% form_for :post , :url => blog_path(@post) , :html => {:method => :put} do |f| -%>
    <%= f.error_messages %>
    <div><%= f.text_field :subject %>
    <div><%= f.text_area :content %></div>
    <%= f.submit "Submit", :disable_with => 'Submiting...' %>
<% end -%>

<%= link_to 'Show', blog_path(blog) %> |
<%= link_to 'Back', blogss_path %>

在 RESTful Rails 的寫法中,對 blog_path (就是 show action )丟 PUT 就是對應到 update 的動作。form 會背包成一個 hash,如果 @post 能夠吃進 params`[`:post`]` 進行更新且成功儲存,就會「重導」到 show action,失敗則「退回」到 edit action。

delete 找到該筆資料並刪除之。在 RESTful Rails 的寫法中,對 blog_path(就是 show action) 丟 DELETE 對應到 destroy 的動作。可看一下 link_to “Destroy” 那一行。

<h1>My Blog</h1>
<h2><%= link_to 'New post', new_blog_path %></h2>
<table>
  <tr>
  </tr>

<% for post in @posts %>
  <tr>
    <td><%= post.subject %> </td>
    <td><%= link_to 'Show', blog_path(post) %></td>
    <td><%= link_to 'Edit', edit_blog_path(post) %></td>
    <td><%= link_to 'Destroy',  blog_path(post), :confirm => 'Are you sure?', :method => :delete %></td>
  </tr>
<% end %>
</table>

看到這個段落,我想應該能讓你對 RESTful Rails 以及 CRUD 中的各種互動有一點粗淺的瞭解。

blog comments powered by Disqus