Ruby on Rails 初學入門(4) - Scaffold 的程式說明(MVC)

瞭解Scaffold 的程式流程是怎麼跑後, 再來就由它的程式碼來學習囉~

先看下述幾個頁面:

  • Controller: app/controllers/posts_controller.rb
  • Model: app/models/post.rb
  • View: app/views/posts/edit.html.erb # 編輯
  • View Layout: app/views/layouts/posts.html.erb # 此檔案是 posts html layout 的 template 檔.

下述的內容可搭配此圖一起看:

RoR Scaffold 程式說明

Index Controller 流程

  1. 進入 Controller index function
  2. Post find 去將 Model 的 Post class 產生實體(new)回傳
  3. 決定要秀 HTML 頁面 或 XML 頁面
  4. View / Layout
進入 Controller index function

程式進入點是 /posts 或 /posts.xml 預設就是會跑 Controller index function.

先看 Controller: app/controllers/posts_controller.rb 的 index function.


class PostsController < ApplicationController
  # GET /posts
  # GET /posts.xml
  def index
    @posts = Post.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @posts }
    end
  end
end

由此可知 Controller 是繼承自 ApplicationController(app/controllers/application.rb), 而註解寫到的就是存取此 index 可以用 GET /posts 和 GET /posts.xml 兩種方式, 來分別看到 View 的 Template 結果和 XML 結果.


def index

def index 是 function, 到底是對應到哪個頁面, 可由下述步驟查詢:

bash$ rake routes 可以看到:

  • posts GET  /posts  {:action=>"index", :controller=>"posts"}
  • formatted_posts GET   /posts.:format  {:action=>"index", :controller=>"posts"}

此處的 def index 就是 routes 的 :action => "index"

Post find 去將 Model 的 Post class 產生實體(new)回傳


@posts = Post.find(:all)

到此處時, 這邊就是使用到 Model 的 Post class, 這段程式的流程會從 Post.find(:all) 直接進入 Model, 完成後再繼續下面的處理.

於 Post.find(:all) 可見: Model: app/models/post.rb, 程式碼只有下面2行:


class Post < ActiveRecord::Base
end

find() 這是於 ActiveRecord 的 function, 因為 class Post 是繼承自 ActiveRecord, 所以可直接使用, 也是於此做其它資料正確性的檢查.

決定要秀 HTML 頁面 或 XML 頁面


respond_to do |format|

再來看最後輸出, 要輸出前為何還要加 respond_to? 且同一個 function 是如何輸出兩種不同的結果?

於程式可以看到 respond_to 裡面有包兩個輸出檔: format.html / format.xml, 由此可知是由此產生 HTML/XML 檔輸出.

respond_to 判斷何時要送 HTML, 何時要送 XML, 主要是靠 "HTTP 的 Accept-Type", 若不用 respond_to 的話, 程式得要改寫成下述:(參考: REST on Rails指南5: respond_to)


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

    if client_format == "text/html"
        # TO DO: render the default template
    elsif client_format == "application/javascript"
        # TO DO: return some javascript
    elsif client_format == "application/xml" || client_format == "text/xml"
        # TO DO: return some XML back the client
        # ... more elsif statements here for each MIME type you want to support
    end
end

因為 respond_to 處理掉上述的事情, 所以就可以用下述存取看看, 就可以得到不同的結果:

  • http://DOMAIN/posts/1
  • http://DOMAIN/posts/1.xml
View / Layout


format.html # index.html.erb

於 format.html 這邊, 它就會去讀取 View 的 index.html.erb 檔, 而 View 裡面也有固定的 Layout file 做定義.

先看 Layout file: (只看 body 部份)


<body>
    <p style="color: green"><%= flash[:notice] %></p>
    <%= yield  %>
</body>

<%= flash[:notice] %>

此段變數的訊息會從 Controller 取出, 於 Create / Update 的 Controller 完成後, 就會看到 Post was successfully created. 等訊息.

<%= yield  %>

而此行, 就會把 View 的內容放進去(取代 yield), 例如 View 的編輯頁面:

View: app/views/posts/edit.html.erb, 內容大致如下:


<%= error_messages_for :post %>
<% form_for(@post) do |f| %>
  <p>
    <b>Id</b><br />
    <%= f.text_field :id %>
  </p>

<%= error_messages_for :post %>

此行就是 Model 有錯誤時, 錯誤訊息(:message)會於此印出. ex: 若於 Model 加入此段: validates_length_of :title, :minimum => 20, :message => "最少要 %d 字元", 那 title 若沒有輸入超過 20個字, 就會顯示錯誤訊息(若有任何錯誤, 資料就不會被新增/修改).

相關文章


關於 Tsung

對新奇的事物都很有興趣, 喜歡簡單的東西, 過簡單的生活.
本篇發表於 Programming。將永久鏈結加入書籤。

發表迴響

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料