歡迎您光臨本站 註冊首頁

用 Apache Derby 和 JRuby on Rails 快速構建原型

←手機掃碼閱讀     火星人 @ 2014-03-12 , reply:0
  
Ruby on Rails 提高了在快速開發數據驅動的 Web 站點方面的標準。JRuby 項目使 Ruby 比以前更快更具有可伸縮性。在 Java™ 虛擬機上運行 Rails 的最大優點之一是您可以利用其他 Java 庫,如 Apache Derby 嵌入式資料庫。Derby、JRuby 和 Rails 的組合允許快速構建動態 Web 應用程序的原型。了解如何結合使用這些技術來幫助您構建下一個偉大構想的原型。

系統要求

本文將使用若干項可實現快速 Web 開發的前沿技術。可以在 參考資料 小節中找到所有這些技術的鏈接。我們將使用 JRuby V1.1.3 和 Apache Derby,兩者是基於 Java 的技術並且要求使用 Java Development Kit(JDK)V1.4 或更高版本。強烈建議使用 V1.6 JDK,因為 Apache Derby 是與 JDK V1.6 綁定的。如果使用 V1.4 或 1.5 VM,則可以單獨下載 Derby。本文中結合使用了 V10.4.1.3 與 V1.5.0_13 JDK。本文還使用 Rails V2.1。假設您具備 Ruby 和 Ruby on Rails 的預備知識,這樣才能發揮本文的最大作用。





設置

現在的許多 Web 應用程序框架都注重開發人員的生產率,這很好,因為開發人員的時間十分寶貴,對不對?但是,經常遺漏的一件事是設置時間,包括從一台整潔的計算機轉到開發人員可以編寫和運行代碼的位置是多麼複雜。這不僅僅對於坐在家中使用新技術的開發人員非常重要,而且對於頻繁雇傭新開發人員並且想要儘快看到投資回報的組織來說同樣重要。Rails 在此領域成績斐然 — 並且結合 JRuby 與 Derby 的效果甚至更好。

安裝 JRuby

假定您已安裝 V1.6 JDK。JRuby 需要知道 JDK 的位置,因此它遵循查找名為 JAVA_HOME 的環境變數的通用約定,該環境變數指向 JDK。您還應當確保 $JAVA_HOME/bin 位於路徑中。現在只需下載 JRuby 並將其解壓縮到所需位置。建議創建此位置的環境變數 — 稱為 JRUBY_HOME — 並把 $JRUBY_HOME/bin 也放入路徑中。這是需要為 JRuby 做的全部操作,但是 Rails 呢?

安裝 Rails

JRuby 是一個 100% 的 Ruby 實現,它只是將 Java 用於其實現而不是原生代碼。它提供了 Ruby 所擁有的一切內容並且包括 gem。要安裝 Rails,只需使用 gem,如清單 1 中所示。


清單 1. 用 gem 安裝 Rails
$ jruby -S gem install rails  JRuby limited openssl loaded. gem install jruby-openssl for full support.  http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL  Successfully installed activesupport-2.1.0  Successfully installed activerecord-2.1.0  Successfully installed actionpack-2.1.0  Successfully installed actionmailer-2.1.0  Successfully installed activeresource-2.1.0  Successfully installed rails-2.1.0  6 gems installed  Installing ri documentation for activesupport-2.1.0...  Installing ri documentation for activerecord-2.1.0...  Installing ri documentation for actionpack-2.1.0...  Installing ri documentation for actionmailer-2.1.0...  Installing ri documentation for activeresource-2.1.0...  Installing RDoc documentation for activesupport-2.1.0...  Installing RDoc documentation for activerecord-2.1.0...  Installing RDoc documentation for actionpack-2.1.0...  Installing RDoc documentation for actionmailer-2.1.0...  Installing RDoc documentation for activeresource-2.1.0...  

注意,使用 JRuby 與原生 Ruby 之間惟一的真正區別是 gem 命令是以 JRuby -S 為前綴的。這將告訴 JRuby 先在 $JRUBY_HOME/bin 目錄中查找腳本。這將確保獲得 JRuby 的 gem 腳本。

可以讓 JRuby 使用現有的 gem 庫(即與原生 Ruby 安裝共享 gem 庫)。只需要設置環境變數。但是,不建議這樣做。大多數 gem 是用 Ruby 編寫的,並且與 JRuby 兼容。但是某些 gem 是用 C++ 編寫的,並且這些 gem 與 JRuby 不兼容。同樣地,某些 JRuby gem 是用 Java 語言編寫的,並且與原生 Ruby 不兼容。

運行以上命令需要花費一段時間,並且在很大程度上依賴於網路連接速度。Rails 附帶 Web 伺服器 WEBrick,該伺服器肯定不是適合生產環境的 Web 伺服器,但是適合快速實現原型化和開發。現在只需一個資料庫 — 也就是,Apache Derby。





安裝 Apache Derby

Rails 使用 ActiveRecord 庫處理資料庫訪問及資料庫表與 Ruby 對象模型之間的對象關係映射。這裡稍微有些不同,因為使用的是 JRuby 而不是 Ruby。在 Java 語言中,我們有 Java 資料庫連接(Java Database Connectivity,JDBC)API 與資料庫通信,而且我們希望在 Rails 中利用 JDBC API。因此需要一個額外的 gem,它允許 ActiveRecord 使用 JDBC。這包括特定於資料庫的信息,因此需要安裝特定於 Derby 的 gem。


清單 2. 為 Derby 安裝 ActiveRecord-JDBC gem
$ jruby -S gem install activerecord-jdbcderby-adapter  JRuby limited openssl loaded. gem install jruby-openssl for full support.  http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL  Successfully installed activerecord-jdbc-adapter-0.8.2  Successfully installed jdbc-derby-10.3.2.1  Successfully installed activerecord-jdbcderby-adapter-0.8.2  3 gems installed  Installing ri documentation for activerecord-jdbc-adapter-0.8.2...  Installing ri documentation for jdbc-derby-10.3.2.1...  Installing ri documentation for activerecord-jdbcderby-adapter-0.8.2...  Installing RDoc documentation for activerecord-jdbc-adapter-0.8.2...  Installing RDoc documentation for jdbc-derby-10.3.2.1...  Installing RDoc documentation for activerecord-jdbcderby-adapter-0.8.2...  

如果您是經驗豐富的 Rails 使用者,則可能會發現上面的代碼與原生 Ruby 沒有太大不同。Rails 總是需要資料庫專用的適配器。不過,Rails 綁定了適合 MySQL、PostgreSQL 和 SQLite 的適配器。如果您曾經將 Rails 與其他類型的資料庫(例如 Oracle 或 IBM® DB2®)結合使用,則可能已經執行過類似上面的操作。

如述,使用 JDK V1.6 的話,Derby 已經綁定好並且可以開始編寫代碼(或者生成代碼)。如果使用的是 JDK V1.5 或 V1.4,則需要執行更多步驟。需要下載並解壓縮 Derby,然後查找 derby.jar 並將其複製到 $JRUBY_HOME/lib 中。現在您已經使用 JDK V1.6 完成了這些工作,可以繼續進行開發。





創建應用程序

Ruby on Rails 在實踐中產生了 “約定優於配置(convention over configuration)” 一詞,並且使用它可以輕鬆地創建應用程序。使用 JRuby 根本不會對此產生影響。現在開始使用 Rails 生成器快速創建應用程序樁。


清單 3. 生成應用程序
>rails deadly -d sqlite3        exists          create  app/controllers        create  app/helpers        create  app/models        create  app/views/layouts        create  config/environments        create  config/initializers        create  db        create  doc        create  lib        create  lib/tasks        create  log        create  public/images        create  public/javascripts        create  public/stylesheets        create  script/performance        create  script/process        create  test/fixtures        create  test/functional        create  test/integration        create  test/unit        create  vendor        create  vendor/plugins        create  tmp/sessions        create  tmp/sockets        create  tmp/cache        create  tmp/pids        create  Rakefile        create  README        create  app/controllers/application.rb        create  app/helpers/application_helper.rb        ...  

大部分輸出已被刪除,因為這全是典型的 Rails 輸出。您會注意到,我們使用了 -d sqlite3,這將告訴生成器腳本使用 SQLite 作為資料庫。這是類似於 Derby 的嵌入式資料庫,並且它是 Rails V2.0 或更高版本附帶的,因此是安全的。我們將在下一個小節中設置 Derby 配置。就像使用任何一個 Rails 應用程序一樣,您可以繼續並啟動它。


清單 4. 啟動應用程序
=> Booting WEBrick...  JRuby limited openssl loaded. gem install jruby-openssl for full support.  http://wiki.jruby.org/wiki/JRuby_Builtin_OpenSSL  => Rails application started on http://0.0.0.0:3000  => Ctrl-C to shutdown server; call with --help for options  [2008-07-25 17:18:31] INFO  WEBrick 1.3.1  [2008-07-25 17:18:31] INFO  ruby 1.8.6 (2008-05-30) [java]  [2008-07-25 17:18:31] INFO  WEBrick::HTTPServer#start: pid=363524275 port=3000  

並且就像任何其他 Rails 應用程序一樣,我們可以通過轉到 http://localhost:3000 在瀏覽器中打開它,如下所示:


圖 1. 運行 Rails 應用程序


這些都是標準的 Rails 特性。正如歡迎屏幕建議的那樣,現在需要設置資料庫,以便可以開始嚮應用程序中添加一些內容。當然,這是使用 Derby 的指定位置。查看清單 5 並查看 Rails 的 Derby 配置。


清單 5. database.yml
development:    adapter: jdbc    driver: org.apache.derby.jdbc.ClientDriver    url: jdbc:derby://localhost/deadly_development;create=true    username: app    password: app      test:    adapter: jdbc    driver: org.apache.derby.jdbc.ClientDriver    url: jdbc:derby://localhost/deadly_test;create=true    username: app    password: app      production:    adapter: jdbc    driver: org.apache.derby.jdbc.ClientDriver    url: jdbc:derby://localhost/deadly_production;create=true    username: app    password: app  

此配置有若干個注意事項。首先,適配器只是 JDBC。通常,需要在這裡指定資料庫專用適配器,如 MySQL 或 Derby。相反,我們將使用基於 JDBC 的適配器。該 URL 將指定使用的是 Derby。注意 create=true 參數,這些參數將告訴 Derby 在資料庫尚不存在時創建資料庫。最後,注意用戶名和密碼。這些只是 Derby 的默認值。現在配置了資料庫連接,應該編寫一些代碼。不過實際上,Rails 將為我們編寫代碼。





Scaffolding

如果使用過 Rails,您很有可能使用過它的搭建(scaffolding)功能或者見過它的實際使用。這可能正是人們對 Rails 稱奇的主要原因,並因此被大量其他框架採用和複製。大多數 Rails 專家可以很快告訴您:scaffolding 的目標不是成為一種生產特性,但是它有助於構建原型是毋庸置疑的。它已經發展了許多年,尤其是在 Rails V2.0 中。讓我們看看將在清單 6 中使用的生成命令。


清單 6. 生成 scaffolding
>script/generate scaffold boat name:string captain:string crew:integer capacity:integer        exists  app/models/        exists  app/controllers/        exists  app/helpers/        create  app/views/boats        exists  app/views/layouts/        exists  test/functional/        exists  test/unit/        exists  public/stylesheets/        create  app/views/boats/index.html.erb        create  app/views/boats/show.html.erb        create  app/views/boats/new.html.erb        create  app/views/boats/edit.html.erb        create  app/views/layouts/boats.html.erb        create  public/stylesheets/scaffold.css        create  app/controllers/boats_controller.rb        create  test/functional/boats_controller_test.rb        create  app/helpers/boats_helper.rb         route  map.resources :boats    dependency  model        exists    app/models/        exists    test/unit/        exists    test/fixtures/        create    app/models/boat.rb        create    test/unit/boat_test.rb        create    test/fixtures/boats.yml        create    db/migrate        create    db/migrate/20080727053100_create_boats.rb  

這段代碼將生成 ActiveRecord 模型、帶有相應映射路徑的控制器和幾個視圖模板。它還根據命令中的參數(與模型屬性對應的名稱-值對和這些屬性的類型)創建初始的資料庫遷移腳本。要創建資料庫,只需使用 Rake 執行資料庫遷移,如下所示:


清單 7. 使用 Rake 創建資料庫表
>rake db:migrate  (in /Users/michael/code/aptana/workspace/deadly)  == 20080727053100 CreateBoats: migrating ======================================  -- create_table(:boats)     -> 0.0395s     -> 0 rows  == 20080727053100 CreateBoats: migrated (0.0407s) =============================  

這樣,系統將立即創建資料庫和 boats 表。注意,無需啟動資料庫伺服器。當 JDBC 驅動程序嘗試連接到 Derby 時,它將啟動 Derby 並創建資料庫,該腳本將創建表。這不僅僅是臨時的內存中的資料庫;而是永久保存在磁碟中。我們可以再次啟動應用程序並且該表將在其中。如果轉到 http://localhost:3000/boats,則應當會看到類似圖 2 所示的內容。


圖 2. Boats scaffolding


在周圍單擊並創建一些船隻。所有內容都存儲在 Derby 資料庫中。您可以停止並重新啟動伺服器,重新啟動計算機,或者執行別的操作。重新啟動伺服器后,所有數據都將在其中。Scaffolding 可能看似神秘,但是它並不神秘。它只是可以修改的生成的代碼。接下來,讓我們看看修改 scaffolding 代碼的簡單示例。





自定義 scaffolding

在很多 Agile 開發方法中都可以見到原型化。您可以快速實現並運行一些內容,然後從產品經理、用戶那裡得到即時反饋。例如,可以把基於 scaffolding 的原型傳遞給產品經理,然後產品經理可以研究該應用程序。在使用過一陣子並且添加了一些船隻后,它可能類似圖 3。


圖 3. 帶有測試數據的 Boats scaffolding


清單 8 顯示了 BoatsController 類的 index 方法。


清單 8. index 方法
class BoatsController < ApplicationController    # GET /boats    # GET /boats.xml    def index      @boats = Boat.find(:all, :order => "capacity DESC")        respond_to do |format|        format.html # index.html.erb        format.xml  { render :xml => @boats }      end    end  end  

實際上還有五個方法(show、new、edit、create、update 和 destroy),但是我們不需要修改這些方法。實際上,在這裡只修改了 index 方法中的第一行:finder 查詢。原來只是 Boat.find(:all)。在這裡,只是添加了一條 order 子句。您可以做出此項更改並刷新瀏覽器以查看更改,如下所示。


圖 4. 按載客量排序的船隻列表


當然,還可以有更多自定義。您可以讓用戶選擇按什麼排序、更改界面外觀等。要點在於 scaffolding 代碼本身不但對於構建原型十分有用,而且還可以輕鬆修改以接納反饋。儘管如此,使用 scaffolding 仍然有限制。有時,需要構建各種各樣並非來自 scaffolding 的模型和控制器原型。幸運的是,Rails 還提供了更多可以輔助這項工作的生成器。





更多生成器

假定需要創建 catch 模型,該模型表示船隻的捕獲物。船隻與捕獲物之間存在一對多的關係。我們將為新模型啟動另一個生成器,如下所示:


清單 9. 生成 catch 模型
>script/generate model catch quantity:integer        exists  app/models/        exists  test/unit/        exists  test/fixtures/        create  app/models/catch.rb        create  test/unit/catch_test.rb        create  test/fixtures/catches.yml        exists  db/migrate        create  db/migrate/20080727060346_create_catches.rb  

注意,只在生成命令中指定了 quantity 屬性(列)。必須執行一些手動編輯才可以添加關係。首先,修改已經生成的遷移腳本。


清單 10. CreateCatches 遷移腳本
class CreateCatches < ActiveRecord::Migration    def self.up      create_table :catches do |t|        t.integer :quantity        t.integer :boat_id                t.timestamps      end    end      def self.down      drop_table :catches    end  end  

在這裡生成了所有內容,但 boat_id 除外。現在可以通過使用 Rake 執行遷移,如下所示。


清單 11. 使用 Rake 創建 catches 表
>rake db:migrate  (in /Users/michael/code/aptana/workspace/deadly)  == 20080727060346 CreateCatches: migrating ====================================  -- create_table(:catches)     -> 0.0291s     -> 0 rows  == 20080727060346 CreateCatches: migrated (0.0299s) ===========================  

需要修改模型。打開 Boat 模型並向其中添加一行代碼,如下所示:


清單 12. Boat 模型
class Boat < ActiveRecord::Base    has_many :catches  end  

默認情況下,該類為空,因為 Rails 將根據來自資料庫的表元數據推斷該類的屬性。只需添加元編程命令來表示一艘船有多個捕獲物。類似地,通過修改 catch 模型來完成關係,如下所示:


清單 13. Catch 模型
class Catch < ActiveRecord::Base    belongs_to :boat  end  

同樣只需添加元編程命令以表示一個捕獲物屬於一艘船。使用 boat_id 表示一個捕獲物屬於一艘船時,我們遵循了 Rails 命名約定。現在可以創建新控制器。


清單 14. DeliveryController
class DeliveryController < ApplicationController    def index      @boats = Boat.find :all      @catch = Catch.new      respond_to do |format|        format.html      end    end        def record      @catch = Catch.new(params[:catch])            respond_to do |format|        if @catch.save          flash[:notice] = 'Delivery recorded successfully'          format.html { redirect_to :action => "list"}        end      end    end        def list      catches = Catch.find(:all)      @totals = {}      catches.each{|catch|        if @totals[catch.boat]          @totals[catch.boat] += catch.quantity        else          @totals[catch.boat] = catch.quantity        end      }      @totals = @totals.sort {|a,b| b[1] <=> a[1]}      respond_to do |format|        format.html      end       end  end  

這段代碼將定義三個操作。第一個是用戶請求 index 操作 — /delivery(Rails 傳遞約定將把 /delivery 映射到 DeliveryController 類中)的默認行為。在這裡,我們執行了一點額外的工作,以便首先獲得所有船隻,這樣就可以在視圖中使用它們。


清單 15. 默認交付視圖
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"   "http://www.w3.org/TR/html4/strict.dtd">  <html>      <head>          <meta http-equiv="Content-Type" content="text/html;   charset=iso-8859-1" />          <title>Record a Delivery</title>      </head>      <body>          <h1>Record a Delivery</h1>          <% form_for @catch, :url => { :action => "record" } do |f| %>            <%= f.error_messages %>                      <p>              <%= f.label :quantity %>              <%= f.text_field :quantity %>            </p>            <p>                    <%= f.label :boat %>                    <%= select("catch", "boat_id", @boats.collect{|b| [b.name, b.id] },   { :include_blank => true })%>            </p>            <p>              <%= f.submit "Record" %>            </p>          <% end %>          </body>  </html>  

這段代碼類似於使用 scaffolding 可以獲得的生成代碼,因為我們利用了 Rails 特性快速構建原型。例如,通過使用 ActionView 類中的 form_for API 使用 FormHelper 對象。我們使用了一些您在生成的代碼中看不到的內容。首先,將表單的操作 URL 設為轉到 record 方法,如清單 14 所示。我們將簡單地查看此方法。接下來,使用 select helper 創建帶有選項值的自定義 HTML 選擇標記。使用在 DeliveryController 類的 index 方法中檢索到的船隻,如清單 14 所示。使用一個慣用的 Ruby 並創建數組集,每個數組都有船隻名稱及其 ID。這些將成為生成的 HTML 中的選項標籤和選項值。這段代碼本應該放入控制器中,但是它演示了 Ruby 的表現力並且該表現力是讓 Ruby 非常適合快速原型化和開發的原因之一。

清單 15 中的表單執行清單 14 中的 DeliveryController 類的 record 操作。此方法將簡單地創建一個新 Catch 實例並保存。然後它將轉發給 list 操作(同樣來自清單 14)。此操作將查詢資料庫以檢索所有 Catch 記錄。然後它聚集記錄以計算資料庫中每艘船的捕獲物總數。您也可以使用自定義查詢執行此計算。記錄集合隨後被劃分到一組雙元素數組中,其中第一個元素是 Boat 對象,第二個元素是該船隻的捕獲物總數。隨後被傳遞到如下所示的視圖:


清單 16. 列表視圖
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">  <html>      <head>          <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />          <title>List Totals</title>      </head>      <body>          <h1>Totals</h1>                    <table>            <tr>              <th>Boat</th>              <th>Total</th>            </tr>                    <% for total in @totals %>            <tr>              <td><%=h total[0].name %></td>              <td><%=h total[1] %></td>            </tr>          <% end %>          </table>                    <br />          <%= link_to 'Add catch', :action => "index" %>      </body>  </html>  

這就是創建所有船隻及其總數表的非常標準的 Rails 模板。我們還使用最後一個 helper 為用戶創建返回到 index 操作的鏈接。現在我們擁有了一個迷你應用程序的完整原型,這將結束本文,但是我們另外介紹了一些內容:關於結合使用 IDE 與 JRuby 和 Derby 的簡要說明。





IDE 支持

對於許多開發人員,快速構建原型和開發意味著需要使用一種 IDE。Ruby 不是構建 IDE 的最簡單語言,並且對於 JRuby 也是這樣。但是,有若干個優秀 IDE 可用,包括基於 Eclipse 的 RadRails。還有一些介紹這個優秀工具的文章(請參閱 參考資料),但是結合使用 JRuby 與 Derby 可能會有點棘手。大多數 IDE(包括 RadRails)都需要 Ruby 調試 gem,以便 IDE 的調試器可以連接到 Ruby VM 中。此 gem 是用 C++ 編寫的原生 gem。這個 gem(目前)不可以與 JRuby 結合使用。相反,必須編寫 Java 版本,但幸運的是,已經為這個非常重要的 gem 編寫了 Java 版本。需要直接下載一個基於 Java 的 gem,然後安裝它和一些其他基於標準 Ruby 的 gem。此過程如下所示:


清單 17. 向 JRuby 中添加調試支持
$ jruby -S gem instal -l ruby-debug-base-0.10.1-java.gem   Successfully installed ruby-debug-base-0.10.1-java  1 gem installed  Installing ri documentation for ruby-debug-base-0.10.1-java...  Couldn't find file to include: 'VERSION'  Installing RDoc documentation for ruby-debug-base-0.10.1-java...  Couldn't find file to include: 'VERSION'  $ jruby -S gem install --ignore-dependencies -v 0.10.1 ruby-debug  Successfully installed ruby-debug-base-0.10.1-java  1 gem installed  Installing ri documentation for ruby-debug-base-0.10.1-java...  Couldn't find file to include: 'VERSION'  Installing RDoc documentation for ruby-debug-base-0.10.1-java...  Couldn't find file to include: 'VERSION'  $ jruby -S gem install --ignore-dependencies ruby-debug-ide  Successfully installed ruby-debug-ide-0.2.0  1 gem installed  

您可以在使用標準的 Ruby 調試 gem 的任何 IDE 中輕鬆地添加斷點並調試應用程序,還可以使用調試器逐步調試一些 Rails 代碼,並且更好地了解其中的奧秘。





結束語

在本文中,我們看到了 JRuby、Rails 和 Apache Derby 的組合如何能夠生成快速構建原型和開發的優秀環境。使用 Rails,我們能夠使用生成器生成樣本代碼,並且可以通過少量工作創建更多自定義應用程序。在 JRuby 和 Derby 的幫助下,我們在應用程序中內嵌了一個事務性持久資料庫;只要我們的應用程序運行,這個資料庫就不會停止。現在,您可以使用更多 Rails 特性來添加更多模型、控制器和視圖。您可以使用 Rails 中的 Ajax helper 輕鬆地嚮應用程序添加 Ajax。您還可以使用 IDE,例如基於 Eclipse 的 RadRails,從而進一步提高原型構建與開發的速度。(責任編輯:A6)



[火星人 ] 用 Apache Derby 和 JRuby on Rails 快速構建原型已經有810次圍觀

http://coctec.com/docs/linux/show-post-69107.html