ROR问题(转载)

转载 http://blog.csdn.net/aabbcc456aa/article/details/7482349

本章目錄

  • Asset 靜態檔案
  • 第一種方式:替換 HTML 片段
  • 第二種方式:使用 JavaScript 腳本
  • 第三種方式:使用 JSON 資料格式
  • Ajax 表單
  • Ajax 按鈕
  • 關於除錯

Assets 與 Ajax 應用程式

Assets靜態檔案

Assets指的是JavaScriptStylesheets和圖檔等靜態檔案,這些檔案並不會隨Requests不同而有所不同。而在Rails目錄中,只有public這個目錄是公開讀取的,所以通常我們會將靜態檔案都放在public這個目錄下,好讓瀏覽器可以直接讀取。但是隨著JavaScriptStylesheet檔案越來越多時,如何管理這些檔案變為一項議題,為了加快瀏覽器的下載速度,我們會合併JavaScriptStylesheet檔案,來減少瀏覽器Request下載次數。更進一步的還會壓縮這些檔案來加速下載時間。像是Yahoo!Google都有各自開源出自己的壓縮工具YUI CompressorClosure Compiler

Rails 3.1引進了一項新功能叫做Assets pipeline,這個功能可以讓我們突破public目錄限制,可以將靜態檔案依需求放在不同目錄下,Rails會幫你組合並壓縮起來。特別是有一些Rails的外掛套件需要使用JavaScript等靜態檔案,在沒有這個功能之前,我們必須將JavaScript等檔案複製放在public目錄下,這樣瀏覽器才能讀取的到。

Rails 3.1之前版本想要有類似的功能,筆者推薦可以安裝Jammit這套工具來管理Assets。如果是升級到3.1的話,記得在config/application.rb中加上config.assets.enabled = true才會啟用這個功能。

Assets的位置在app/assets/下,首先最重要的就是app/assets/javascripts/application.jsapp/assets/stylesheets/application.css,這兩個檔案看起來充滿註解,其實它是個manifest檔案,列出了所有要載入的靜態檔案,這些檔案的位置依照慣例放在app/assetsvendor/assets目錄下。

讓我們先看看application.js

// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
//
//= require jquery
//= require jquery_ujs
//= require_tree .

其中的require_jqueryrequire_jquery_ujs會載入JQueryRailsJQuery adapater,這是因為我們在Gemfile中有裝jquery-rails這個套件,所以這裡可以讀取的到。而require_tree .會載入這個目錄下的所有JavaScript檔案。總之,這個manifest的最後輸出結果就是通通壓縮成一個application.js檔案。

同理application.css也是一樣載入所有stylesheets目錄下的CSS檔案,最後壓縮成application.css

/*
 * This is a manifest file that'll automatically include all the stylesheets available in this directory
 * and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
 * the top of the compiled file, but it's generally better to create a new file per style scope.
 *= require_self
 *= require_tree . 
*/

讓我們看看View,在Layout檔案中:

<%= stylesheet_link_tag    "application" %>
<%= javascript_include_tag "application" %>

因為最後輸出都壓縮成一個檔案了,所以這裡只需要載入application.cssapplication.js

如何處理圖片

放在app/assets/images下的圖片該怎麼使用呢?在實際佈署後,Rails會將檔案名稱加以編碼,例如rails.png會變成rails-bd9ad5a560b5a3a7be0808c5cd76a798.png。這麼做的原因是當圖片有變更的時候,編碼就會不同而有不同的檔名,這樣就可以避免瀏覽器快取到舊的檔案。也因為檔案名稱會變動,所以放在app/assets/images下的圖片,要用的時候就沒有辦法寫死檔名。在一般的View中,可以使用image_tag這個Helper

<%= image_tag("rails.png") %>

如果在CSS裡的話,有兩種辦法:一是將檔案命名為erb結尾,例如app/assets/stylesheets/main.css.erb,然後使用asset_path這個Helper

h1 {
  background-image: url('<%= asset_path("rails.png") %>');
}

另一種方法是使用SassSCSS語法。其中SCSS相容於CSS。例如命名為app/assets/stylesheets/main.css.scss,然後使用image-url這個Sass提供的方法:

h1 {
    background-image: image-url("rails.png")
}

如果是js檔案中想要拿圖片的位置,就只能用js.erb的格式,然後內嵌asset_path Helper方法了。

Precompile編譯靜態檔案

放在app/assets目錄下的AssetsRails支援使用不同的語法,例如使用Sass語法產生CSSCoffeeScript產生JavaScript,或是用ERb樣板也可以。使用的方法是將附檔名命名成.css.sass.css.scss.js.coffee.css.erb.js.erbRails就會編譯出結果給瀏覽器。

Sass是一種CSS3語法的擴充,可以使用巢狀、變數、混入、選擇子繼承等等功能,可以更有效率有彈性的撰寫StylesheetSass最後會編譯出合法的CSS讓瀏覽器使用。使用上它區分成兩種形式的語法scsssass,前者可以與現有的css程式碼直接混合在一起,後者則透過縮排來省略了大括號{}(就像Python用縮排一樣)。CoffeeScript也是類似原理,它是一種迷你的程式語言,編譯之後會輸出可讀性高、符合JavaScript Lint規範的JavaScript程式碼。

學習這兩種新語法需要額外的時間投入,但是對需要常常撰寫CSSJavaScript的設計師來說,應該是很不錯的工具,讀者可以自行斟酌是否採用。如果你不打算使用的話,可以編輯Gemfile拿掉以下:

gem 'sass'
gem 'coffee-script'

如果採用Sass的話,推薦還可以採用Compass這套CSS框架的框架。

編譯出最後結果

開發的時候,Rails會自動將Asset的壓縮結果快取在tmp下,所以開發者不需要特別處理。但是實際正式上線時,最後壓縮的檔案還是必須放在public目錄下由網頁伺服器直接提供(或是由CDN)效能較好,以下的rake指令可以產生出來:

rake assets:precompile

產生出來的檔案在public/assets/下。

rake assets:clean

這樣就會刪除。

注意,如果在開發模式下執行了rake assets:precompile,那麼因為放在public/assets/下的靜態檔案會優先丟給瀏覽器,所以這時候再修改app/assets下的原始碼會沒有作用。所以,開發時請記得要刪除這個目錄。

不過,如果你有很多靜態檔案的話,開發模式下每次都要重新編譯太辛苦了。你可以先compile一次,然後把public/assets/下目前正在開發的檔案砍掉即可。

如何拆成數個壓縮檔

上述的application.jsapplication.css中,預設會壓縮所有app/assets目錄下的檔案,如果你需要拆開,只需要修改其中的內容把require_tree那行移除,那麼就只會壓縮你所指定的目錄或檔案。

例如,要新增新的Manifest檔案的話,假設叫做app/assets/javascripts/search.js,內容如:

//= require ./foobar

這樣就會將assets/javascripts/foobar這個目錄下的檔案通通壓縮成search.js,而在View中:

<%= javascript_include_tag "application" %>
<%= javascript_include_tag "search" %>

就會載入。注意到如果啟用了assets功能,javascript_include_tag只能接受一個參數,即Manifest檔案的名稱。

為了讓rake assets:precompile也能產生新的壓縮檔案,你還需要編輯config/environments/production.rb加入:

config.assets.precompile += %w( search.js )

如何關閉這個功能

也可以不使用這個功能,請修改config/application.rb將以下設定改成false

config.assets.enabled = false

這樣的話,在View中就必須列出所有你要載入的Script檔案:

<%= stylesheet_link_tag    "reset", "application", :cache => "all" %>
<%= javascript_include_tag 'jquery', 'rails', 'application', :cache => "all" %>

這些檔案都必須放在public目錄下。而加上cache參數Rails會合併這些檔案,但是並不會壓縮。

Ajax

AjaxAsynchronous JavaScript and XML的縮寫,是一種不需要重新整理頁面,透過JavaScript來與伺服器交換資料、更新網頁內容的技術。目的在於改善使用者的操作介面,提昇流暢度。它主要是透過瀏覽器提供的XMLHttpRequestObject來達成,不過因為跨瀏覽器的困難度,大多數人們會選擇使用JavaScript Library來處理Ajax,例如JQueryYUI等。雖然Ajax的縮寫中包括XML,但是實務上並不一定要用XML格式,事實上也已經很少人使用XML當作傳輸的格式了。總歸來說,依照Ajax使用的格式分類,有三種方式:

  • 向伺服器請求 HTML 片段,然後客戶端瀏覽器上的 JavaScript 再替換掉頁面上的元素
  • 向伺服器請求 JavaScript 程式腳本,然後客戶端瀏覽器執行它
  • 向伺服器請求 JSON 或 XML 資料格式,然後客戶端瀏覽器的 JavaScript 解析後再動作。

第一種方式非常簡單,但是限制是一次只能更新一小塊內容。Rails 比較常見使用第二種方式,容易使用彈性又大。而第三種方式則將 JavaScript 程式都放在客戶端瀏覽器上,相較於第二種則多了解析 JSON 或 XML 的部份。以Web API的設計角度來看,與表現層無關的JSON格式是比較乾淨的,可以獲得比較好的重複使用性。

講解JavaScriptJQuery語法已經超過本書範圍,本章接下來會假設讀者已經有基本認識。身為一個Web程式設計師,不得不對JavaScript要有基本了解。

Unobtrusive JavaScript

Rails 從 3.0 開始將支援AjaxJavaScript都改成用Unobtrusive JavaScript(UJS)的方式。什麼是Unobtrusive呢? 用個範例來說吧:

link_to 'Remove', event_path(1), :method => :delete

Rails 3之前,會輸出:

<a onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);f.submit();return false;" href="/events/1">Remove</a>

Rails 3之後,會輸出:

<a rel="nofollow" data-method="delete" class="delete" href="/events/1">Remove</a>

Unobtrusive也就是將JavaScript程式與HTML完全分開了。

第一種方式:替換 HTML 片段

編輯 app/views/events/index.html.erb 最下方加入:

<%= link_to "say hello", { :controller => "welcome", :action => "say" }, :id => "ajax-load"  %>
<div id="content">
</div>

<script type="text/javascript" charset="utf-8">
    $(document).ready(function() {
        
        $('#ajax-load').click( function(){
            $('#content').load( $(this).attr("href") );
            return false;
        });
        
    });
</script>

第二種方式:使用 JavaScript 腳本

編輯 app/views/events/index.html.erb,在迴圈中間加入

<%= link_to 'ajax show', event_path(event), :remote => true, "data-type" => "script" %>

編輯 app/controllers/events_controller.rb,在 show action 中加入

respond_to do |format|
  format.html
  format.js
end	

新增 app/views/events/_event.html.erb,內容與 show.html.erb 相同

新增 app/views/events/show.js.erb,內容如下

$('#content').html("<%= escape_javascript(render :partial => 'event') %>")
             .css({ backgroundColor: '#ffff99' });

瀏覽 http://localhost:3000/events

escape_javascript()可以縮寫為j()

j()Rails 3.1之後版本才有

第三種方式:使用 JSON 資料格式

JavaScript Object Notation(JSON)是一種源自JavaScript的資料格式,是目前Web應用程式之間的準標準資料交換格式,在Rails之中,每個物件都有to_json方法可以很方便的轉換資料格式。 (TODO)

<%= link_to 'ajax show', event_path(event), :remote => true, "data-type" => :json, :id => "update_foobar" %>

點擊ajax show就會送出Ajax request了,但接下來要怎麼撰寫處理JSON的程式呢?

$(function() {
    $('#update_foobar').bind("ajax:success", function(event, data) {            
        var foobar = $('#foobar');
        foobar.html( data.foobar_number );
    });
});

當然,你也可以把HTML片段當做JSON的資料來傳遞。

另一種JSON的變形是JSONP(JSON with Padding),將JSON資料包在一個JavaScript function裡,這個做的用處是讓這個API可以跨網域被呼叫。要回傳JSONP格式,只需要在render :json時多一個參數是:callback即可

respond_to do |format|
  format.json { render :json => @user.to_json, :callback => "process_user" }
end

或是使用Rack::JSONP這個Middleware,只要有?callback=參數就會自動變成JSONP。等同於上述使用:callback => params[:callback]

Ajax 表單

除了超連結 link_to 加上 :remote 可以變成 Ajax 之外,表單 form_for 也可以加上 :remote 變成 Ajax。

form_for(@user, :remote => true

Ajax 按鈕

同理於超連結 link_to,按鈕 button_to 加上 :remote => true 參數也會變成 Ajax。

關於除錯

使用 Ajax 後,因為頁面沒有經過重新整理,發送的 request 請後是在背景執行的,所以在除錯的時候需要有額外的工具來協助我們觀察 JavaScript 運作的情形。推薦您安裝Firefox 瀏覽器以及 Firebug 這套工具。在SafariChrome也有內建類似Firebug的開發工

posted @ 2013-04-22 21:25  无姬霸王  阅读(97)  评论(0编辑  收藏  举报