`
ghost138
  • 浏览: 45967 次
  • 性别: 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 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 带给 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中文教材(PDF)

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

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

    Ruby on Rails入门经典代码

    Ruby on Rails,简称Rails,是基于Ruby语言的一个开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在使Web开发过程更加高效、简洁。本压缩包中的"Ruby on Rails入门经典代码"提供了新手学习...

    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 的相关框架尤其受到关注。本文...

    基于Ruby语言的Ruby on Rails项目及其代码方案

    ### 基于Ruby语言的Ruby on Rails项目及其代码方案 #### 一、项目概述 本项目基于Ruby语言,利用Ruby on Rails(简称Rails)框架构建。Ruby on Rails是一款使用Ruby语言开发的应用程序框架,其核心是MVC(Model-...

Global site tag (gtag.js) - Google Analytics