`
ghost138
  • 浏览: 45251 次
  • 性别: Icon_minigender_1
  • 来自: ...重庆
最近访客 更多访客>>
社区版块
存档分类
最新评论

Ruby on Rails 的終極 Unobstrusive jQuery 方案

    博客分类:
  • ROR
阅读更多
使用jQuery,你的RoR Application 可享有所有 Unobtrusive JavaScript 帶來的優點,使編碼和Markup絕對分開,又可以要最快的速度建立所有用戶端的功能和介面效果。

現在的 RoR + Prototype 方案,其中最大一個問題就是如何處理 ySlow 作者 Steve Souders 極度重視的 "Put CSS at top", "Put Javascript At bottom"問題。不少人正為這問題煩惱。

以下文章將討論如何建立一個完全使用 jQuery ,不使用 Prototype 的方法。

Rails 組群亦提供了一些 jQuery 方案,可惜一般方案沒有完全利用 Unobstrusive Programming 的優點,使編碼胡亂放在頁面中間。

這次我們會看看結合 content_for 和 jRails (http://ennerchi.com/projects/jrails),以建立最好的方案。




第一步: 安裝 jQuery


首先建立一個 Layouts。在 你的 controller 檔 (例如 /app/controllers/blogs_controller.rb) 的頂部插入編碼


class BlogsController < ApplicationController  
   layout "application_layout"
end

然後,在/views/layouts 內新增 "application_layout.html.erb",並貼上編碼

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"  xml:lang="en" lang="en">
<head>
  
  <%=stylesheet_link_tag "http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.0/themes/cupertino/jquery-ui.css" %>
 
</head>  
<body>
<%= yield %>
</body>
</html>
<!-- include javascripts -->
<%=javascript_include_tag("http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js") %>
<%=javascript_include_tag("http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js") %>
<!--//include javascripts //-->
<!-- jquery and other functions-->
<%javascript_tag do %>
$(document).ready(function() {
    <%= yield :js_ready %>
});
<%end %>
<!-- //jquery and other functions //-->



以上編碼有五點要注意:

stylesheet_link_tag 從 Google CDN 包括了 jQuery UI 這jQuery UI 基本 的stylesheet
<%= yield %> 將頁面主要內容放在原始檔中間位置。
底下兩行是 javascript_include_tag 編碼,把 jQuery 的原始檔,從 Google CDN 包括至網頁。這裡使用了有別於一般 include javascript 放在<head></head>中的方法。原因是"Put CSS at top", "Put Javscript At bottom", 使網頁以最高效率運作。
最後幾行 <%javascript_tag do %>...<%end%> 是輸出 Javascript 原始檔的地方。這幾行對於分開 Program 和 Markup 最為重要。還有,這裡利用了jQuery 出名的"$(document).ready()",使所有javascript 等候至 HTML 下載妥當後才執行。
注意編碼總共有兩處 "yield" 編碼。 使用這 'yield',使輸出可以放在不同的地方。我們利用了這特性,使 HTML 被放在原始檔的中間,而Javascript 被放到原始檔的底部。

將javascript_include_tag 放在<head></head>, ySlow 立即指出問題。

將javascript_include_tag 放在<head></head>, ySlow 立即指出問題。雖然還有Grade A的分數,但是加多幾個Javascript include,分數便會急降。最重要是,下載速度已經慢了很多。


將javascript_include_tag 放在最底, ySlow 有 Grade A 的分數。
Javascript 放在最底部使網頁加速。

現在頁面可以使用 jQuery 了!


第二步:使用jQuery 和 jQuery UI

首先,我們要測試 jQuery UI 的介面效果。為此,我們先在頁面加上一排常用的Tabs。

在測試的頁面 (例如: /views/blogs/index.html.erb) 加入以下編碼:

<div id="section_tabs">
  <ul>
    <li><%=link_to "Introduction", "#intro"%></li>
    <li><%=link_to "Contact Us", "#contact_us"%></li>
    <li><%=link_to "About Me", "#about_me"%></li>
  </ul>
  <div id="intro">
      Hello, it is nice to meet you.
  </div>
  <div id="contact_us">
      Email: arthurccube@nowhere.com
  </div>
  <div id="about_me">
      I am someone.
  </div>
</div>
<% content_for :js_ready do  %>
  jQuery('#section_tabs').tabs();
<% end %>


以上編碼建立了 Tabs 的 DOM 結構,單單一句"jQuery('#section_tabs').tabs();", 便完成tabs 所需的所有 javascript 。jQuery UI 聰明地使用selector "id" (#section_tabs) 去找出了解相關 Tabs 的目標,並對相關 DOM 結構修改為Tabs 內容。

而 "<% content_for :js_ready do  %>" 這段編碼,是對應在 application_layout 的 "<%= yield :js_ready %>",兩段編碼的結果,是令到相關的javascript 放到頁面的最底部。




jQuery UI 成功建立了一個Tabs。


這時我們再查看ySlow,"Put Javascript At Bottom" 仍然是完美的!



第三步: Rails 去 Prototype 化和Unobstrusive 化


Unobstrusive Javascript 的意思是 "把功能('行為層面')和網面的結構/內容和演示分開"(http://en.wikipedia.org/wiki/Unobtrusive_JavaScript)。

可惜,RoR 因為使用了很多即用即寫的Prototype Helpers,使Javascript 和網頁變得難以分割。

令人高興的是,RoR的 Overriding 功能十分廣泛,我們可以輕易的把有問題的Helpers 修改。

筆者選了最典型的問題Helper - observe_field 來做例子。

首先,安裝 jRails Plugins ,使相關Helpers 使用jQuery:

./script/plugin install http://ennerchi.googlecode.com/svn/trunk/plugins/jrails


在'<%= javascript_include_tag("http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.1/jquery-ui.min.js") %>' 之後插入編碼:


<%= javascript_include_tag("jrails.js") %>

這段編碼把 jRails 所寫的 Javascript 放到頁面。

重啟Application,然後,在剛才的測試頁面 '/app/views/blogs/index.html.erb' 頂部插入編碼:

  <% form_tag 'search',
   {:id => 'form_search'} do %>
      Search: <%=text_field_tag "query"%>    
      <%= observe_field(:query,
        :url => { :controller => :blogs, :action => :search },
        :frequency => 0.5,
        :update => :intro,
        :with => :input)
      %>
  <% end  %>

以上編碼的 observe_field 監察一個名為 'query' 的輸入(即是<%=text_field_tag "query"%> 的輸出)。等會,如果用者在瀏覽器修改這欄位的輸入,observe_field 便把資料送到在 blogs controller 的 search action。



檢視編碼後可看到Javascript 被隨意放在HTML 編碼的中間。

所以,為解決這 Unobstrusive 問題,要修改兩個檔案。

首先在 /app/views/layouts/application_layout.html.erb 最底部插入編碼:

<%= yield :rails_helpers %>

這段編碼用來輸出我們將會修改的 Rails Helper 內容,因為我們將會修改的 observe_field 自己也有一個<script></script> tag, 這個 "yield :rails_helpers"不要放進任何"javascript_tag"內。

現在我們在 '/app/helpers/application_helper.rb' 插入編碼:

  # override the existing observe_field putting the javascripts at bottom
  def  observe_field(field_id, options = {})
    content_for :rails_helpers do
      super(field_id, options )
    end
     
  end

以上編碼Override 了 RoR 原本的沒有 Unobstrusive 概念 的 'observe_field' Helper,使把輸出放到 :rails_helpers,即是整個網頁的最底部。

現在刷新頁面,再檢視原始檔。所有javascript,包括observe_field的編碼也在最底部!



所有javascript 也在最底部!

現在,使observe_field 可以回傳結果,我們在 '/app/controllers/blogs_controller.rb'插入:

  def search
    render :text => "searching results from query <u><i>'#{params[:input]}'</i></u> @ #{Time.now}"
  end



不用按鈕,在Search 輸入的字句也被送到伺服器中。

把Javascript 放在最底的結果是,整個網頁的HTML 結構和相片可以用最快的速度下載到用戶端,即是最重要的'Put Javascript at bottom"!

這個observe_field 只是一個Unobstrusive 化一個Rails Helper 的例子。讀者可用相同的放法修改所有相關的Helper,令Javascript 不存於頁面中間。





第四步:安裝特別的 jQuery Plugins


現在您的系統擁有Rails 和 jQuery。基本上可以安裝的工具很全面,筆者在此列出一個例子。

我們將安裝一個非常好用的 simple auto_complete (http://github.com/grosser/simple_auto_complete/tree/master)

首先,在 http://github.com/grosser/simple_auto_complete/tree/master 下載 simple_auto_complete plugins。

解壓後將文件夾放在/app/vendoer/plugins 內。

在剛下載文件夾找到 '/example_js/javascripts',把 'jquery.autocomplete.js' 複製到 '/public/javascripts'。

並把在 '/example_js/stylesheets' 的 'jquery.autocomplete.css' 複製到 '/public/stylesheets'。

重啟Application。

所有相關的Javascript 和 Stylesheets 已放到了適當位置。

現在修改 '/app/views/layouts/application_layout.html.erb',使這些檔案包括到網頁輸出。

在 '<head>...</head>' 之間任何位置插入編碼:

<%=stylesheet_link_tag "jquery.autocomplete.css" %>


在 '<%=javascript_include_tag("jrails.js")%>' 下面插入編碼:

<%=javascript_include_tag("jquery.autocomplete.js") %>


在'/app/controllers/blogs_controller.rb' 插入以下編碼:

    autocomplete_for :blog, :title do |items|
      items.map{|item| "#{item.id}: <b>#{item.title}</b>"}.join("\n")
    end


註:以上編碼假設您有 blog.rb,其擁有欄名 title。讀者可改作其他 model 和欄名也有效。

在測試的頁面 /views/blogs/index.html.erb 加入以下編碼:

<% form_for :blog do |f|%>
   Autocomplete: <%= f.text_field :auto_user_name, :class => 'autocomplete', 'autocomplete_url'=>autocomplete_for_blog_title_blogs_path %>
<%end %>
<%content_for :js_ready do %>
   //autocomplete
   $('input.autocomplete').each(function(){
     var input = $(this);
     input.autocomplete(input.attr('autocomplete_url'));
   });
<%end %>


這段編碼首先建立關於 blog 的一張表格。然後,使用 jQuery (i.e. $) 的編碼監察相關輸入。

留意輸入會被送到 'autocomplete_for_blog_title_blogs_path' 這路徑。

所以我們要在 routes.rb 加入:

map.resources :blogs, :collection => { :autocomplete_for_blog_title => :get}




autocomplete 功能完成,輸入的字句會自動回傳提示。


第五步:Forgery Token

基於安全理由,網站可能啟動了 forgery token. 我們可以將所有 Ajax 也加上 forgery token ,使相關伺服器要求被接納。



在 "/app/views/layouts/application.html.erb" 內的 "$(document).ready(function() {" 這句編碼下面加入:

// All non-GET requests will add the authenticity token
// if not already present in the data packet
jQuery("body").bind("ajaxSend", function(elm, xhr, s) {
    if (s.type == "GET") return;
   
    if (s.data && s.data.match(new RegExp("\\b" + window._auth_token_name + "="))) return;
    if (s.data) {
      s.data = s.data + "&";
    } else {
      s.data = "";
      // if there was no data, jQuery didn't set the content-type
      xhr.setRequestHeader("Content-Type", s.contentType);
    }
    var auth_token = encodeURIComponent(window._auth_token_name);
   
      s.data = s.data || "";
    if (s.data.indexOf(auth_token) < 0 )  s.data += (s.data ? "&" : "") + auth_token + "=" +  encodeURIComponent(window._auth_token);
});   


總結

雖然RoR 本身提供了很多有用的 Helpers,但是RoR 和 Prototype 密不可分的結構,使優化網頁變得複雜。

這違反了Obstrusive 概念。

筆者演示了怎樣把 Prototype 從 RoR 分開,而且將Javascript 放在原始檔的底部。

之後,我們利用RoR 方便的 Overriding 特性,把一些Helpers 修改為輸出在原始檔最底部 (:rails_helpers)。

最後,我們可以享受各個好用的RoR 或 jQuery Plugins ,亦容易的使程式 Obstrusive化。
分享到:
评论

相关推荐

    Ruby on Rails Tutorial

    《Ruby on Rails Tutorial》中文版(原书第2版,涵盖 Rails 4) Ruby 是一门很美的计算机语言,其设计原则就是“让编程人员快乐”。David Heinemeier Hansson 就是看重了这一点,才在开发 Rails 框架时选择了 Ruby...

    Ruby On Rails中文教材(PDF)

    Ruby on Rails,简称Rails,是一款基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-Controller)架构模式,旨在简化Web应用程序的开发。Rails由David Heinemeier Hansson于2004年创建,它提倡“约定优于配置...

    ruby on rails 101

    ### Ruby on Rails 101:深入理解与实践 #### 引言 《Ruby on Rails 101》是一本介绍Ruby on Rails(简称RoR或ROR)的基础书籍,旨在为初学者提供一个全面而深入的学习框架。本书由Peter Marklund编写,包含了五天...

    Ruby on Rails安装包全集(Linux)

    Ruby on Rails是一款基于Ruby语言的开源Web开发框架,它遵循MVC(模型-视图-控制器)架构模式,简化了Web应用的开发流程。在Linux环境下安装Ruby on Rails需要一系列的依赖包和步骤,本资源包提供了所需的所有组件,...

    ruby on rails最新版

    Ruby on Rails,简称Rails,是基于Ruby编程语言的一个开源Web应用程序框架,它遵循MVC(模型-视图-控制器)架构模式,旨在提高开发效率和代码的可读性。Rails以其“约定优于配置”(Convention over Configuration)...

    ruby on rails社区网站开发源码

    Ruby on Rails,简称Rails,是由David Heinemeier Hansson创建的一个开源Web应用程序框架,它基于Ruby编程语言。这个框架以其MVC(Model-View-Controller)架构、约定优于配置(Convention over Configuration)的...

    提升Ruby on Rails性能的几个解决方案

    Ruby On Rails 框架自它提出之日起就受到广泛关注,在“不要重复自己”,“约定优于配置”等思想的指导下,Rails 带给 Web 开发者的是极高的开发效率。 ActiveRecord 的灵活让你再也不用配置繁琐的 Hibernate 即可...

    ruby on rails 3 tutorial.pdf

    《Ruby on Rails 3 Tutorial》是一本专门为初学者设计的指南,旨在帮助读者快速掌握Ruby on Rails这一强大的Web开发框架。Ruby on Rails(简称Rails)是基于Ruby语言的一个开源框架,它采用MVC(Model-View-...

    Ruby on Rails Guides v2 - Ruby on Rails 4.2.5

    ### Ruby on Rails Guides v2 - Ruby on Rails 4.2.5 #### 一、重要概念及基础假设 - **重要概念**:本指南旨在帮助读者深入理解Ruby on Rails(以下简称Rails)4.2.5版本的核心功能与最佳实践。 - **基础假设**:...

    Ruby on Rails入门权威经典

    《Ruby on Rails入门权威经典》是一本专门为初学者设计的指南,旨在帮助读者全面掌握Ruby on Rails这一强大的Web开发框架。Ruby on Rails(简称Rails)是基于Ruby编程语言的开源框架,以其“DRY(Don't Repeat ...

    ruby on rails for dummies

    《Ruby on Rails for Dummies》是一本专门为初学者设计的Ruby on Rails教程,它旨在帮助新手快速理解并掌握这个强大的Web开发框架。Ruby on Rails(简称Rails)是基于Ruby编程语言构建的一个开源Web应用程序框架,它...

    Ruby on Rails实践

    Ruby on Rails,简称Rails,是由David Heinemeier Hansson基于Ruby语言开发的一个开源Web应用程序框架。这个框架遵循“约定优于配置”(Convention over Configuration)的原则,致力于简化Web应用的开发流程,提高...

    Ruby on Rails教程:学习使用Rails进行Web开发Ruby on Rails Tutorial: Learn Web Development with Rails

    本书教您如何使用Ruby on Rails开发和部署真正的,具有工业实力的Web应用程序,Ruby on Rails是为诸如Twitter,Hulu,GitHub和Yellow Pages等顶级网站提供支持的开源Web框架。

    Ruby on Rails中文指南

    Ruby on Rails,简称Rails,是一款基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-Controller)架构模式,旨在提升开发效率和代码的可读性。Rails以其“约定优于配置”的设计理念,以及“DRY(Don't Repeat ...

    ruby on rails 教程源码

    Ruby on Rails,简称Rails,是基于Ruby语言的开源Web应用框架,它遵循MVC(Model-View-Controller)架构模式,旨在使开发过程更加简洁高效。这个“ruby on rails 教程源码”很可能是为了辅助学习者深入理解Rails的...

    Ruby On Rails(PDF)

    ### Ruby on Rails与Java框架对比分析 #### 一、引言 随着互联网技术的迅猛发展,Web开发领域也迎来了各种各样的开发框架和技术栈。在众多的开发框架中,Ruby on Rails (RoR) 和 Java 的相关框架尤其受到关注。本文...

Global site tag (gtag.js) - Google Analytics