用Ruby on Rails來編寫數據庫管理系統是非常快速的。Ruby on Rails之所以有如此高的生產率,不 光是Ruby的語法靈活,而這一切在很大程序上是拜活動記錄(Active Record)所賜。那麼什麼是活動記 錄呢?如果用一句話來解釋,那就是一個可以將數據映射成對象的框架(這有些類似於Hibernate)。也 許你會說:"這有什麼,現在這種框架多得是,Hibernate不是也非常強大嗎?",但如果你用了Ruby on Rails(以下簡稱為RoR),你就會發現它和其它的同類框架是多麼的不同,它比其它框架更容易使用,編程 效率也更高,據官方說,使用RoR比使用Java和Hibernate的生產率高10倍(也許並沒有這麼誇張,但活動 記錄的數據映射的確比其它框架的數據映射的生產率高一些)。
無論是桌面程序還是基於Web的程序,數據處理始終是它們的核心。數據可以使用不同的技術進行描述 和處理。
這些數據處理技術之一就是對象關系映射技術,或者簡稱為ORM技術。ORM技術將數據庫中的數據表或 視圖映射成了面象對象的類。而ORM框架的作用就是架起數據和對象之間的橋梁,以及為橋梁兩端的數據 和對象提供相應的服務。由於ORM框架自成一體,因此,開發人員的主要工作就是將ORM框架和其它的框架 (如web框架)連接起來,從而使它們可以協同工作。
在ORM框架家族中,RoR很特別。RoR的核心是ORM框架,而這個框架在RoR中是以活動記錄的形式表現的 。在本文中,我們將關注活動記錄的一些基本概念和她最誘人的地方:快速連接和操作數據庫。本文的第 一部分將討論活動記錄的基礎知識。第二部分將一步步地指導讀者如何使用活動記錄快速地連接和操作數 據庫。在第三部分中我們以一個完整的例子來討論如何將活動記錄和ActionController以及ActionView一 起使用。以上是本文所討論的主要內容。
什麼是活動記錄
活動記錄是一個ORM框架,也可以看做是和RoR一起發布的一個數據庫映射層。活動記錄是RoR的核心。 活動記錄是一個ORM層,它提供了以下的映射服務:
1. 將表映射成類
2. 將字段映射成類的屬性
3. 將表中的主鍵映射成Ids屬性
4. 將行映射成對象
活動記錄和其它的ORM框架最大的區別是它們的映射方式不同。大多數流行的ORM框架(如Hibernate) 是以XML作為映射容器。而活動記錄采用的是更容易使用的"約定"方式進行映射。下面讓我們來看看活動 記錄是如何做的。
將表映射成類
為了將表映射成類,Ruby類必須從ActiveRecord::Base繼承。這個Base類在ActiveRecord包中。那麼 一個類從ActiveRecord::Base繼承後發生了什麼呢?實際上這個子類已經和一個數據表相對應了。也許大 家看到這有一些迷糊,我除了寫一個從ActiveRecord::Base繼承的空類什麼代碼都沒寫,怎麼就映射完了 。其實這要依靠活動記錄的命名約定。活動記錄假設一個類名的復數形式(英文類名)就是表名。如果類 名中有多個大寫字母,那麼活動記錄就假設表名就是這些單詞中間用下劃線隔開後連在一起,請看下面的 例子。
類名 表名 Record Records LineItem Line_Items Datum Data以上所描述的是活動記錄的默認的映射行為,我們也可以為活動記錄定義自已的行為。要改變這些默 認的行為,可以按以下步驟做:
1.將全局變量ActiveRecord::Base. pluralize_table_names設為false。這個變量被定義在config目 錄中的environment.rb中。
2.可以通過set_table_name改變默認的表名。例如,如果將表Orders映射成類Order的代碼如下:
class Order < ActiveRecord::Base end
但如果這個類名要映射成MyOrder,那麼它的實現代碼如下:
class Order <ActiveRecord::Base set_table_name "MyOrder" end
接下來讓我們看看如何將字段映射成屬性。
將字段轉換為屬性
在一個數據表被映射成類後,表中的字段就將自動映射成類的屬性。這是因為活動記錄是在程序運行 時動態地將表中的字段映射成類的屬性。事實上,在從ActiveRecord::Base的類自動將表中的字段包裝在 了類中。下表將描述SQL數據類型將被映射成Ruby的哪些數據類型:
SQL數據類型 Ruby數據類型(類) int, integer Fixnum decimal, numeric Float interval, date Date clob, blob, text String float, double float chat, varchar, string String datetime, time Time
下面讓我們來討論主鍵的映射。
將主鍵映射成Ids
假設有一個Orders表,它的主鍵是Order_Id。現在讓我們看看這個Order_Id字段,這個字段由16個數 字組成,其中包括Item id,User Id等。在以後如果Order_id變成20位數字,最後4位數字是一個RFID代 碼,那麼所有依賴這個Order_id字段的列都將發生變化。這些工作量是非常大的,即使這個應用程序並不 大。然而活動記錄確能自動做到這些。自動映射可按如下代碼去做:
class Order < ActiveRecord::Base set_primary_key "orderId" end
將記錄映射成對象
無論什麼時候,映射類的查詢方法被執行時,在內部都會調用相應的SQL語句來查詢數據庫,並且將查 詢結果返回,這些返回的結果最終以對象的形式表現。列值將成為對象的屬性。返回的每一行將被映射成 一個對象。例如以下代碼將返回Id等於100的Order對象:
an_order = Order.find(100)
上面的代碼演示了如何得到特定的記錄。接下來讓我們看一下使用活動記錄建立相應的操作的步驟。
使用活動記錄的步驟
雖然使用活動記錄映射數據表不需要復雜的設置,但我們必須按著活動記錄所制定的規范進行操作。 這些規范將成為活動記錄工作的一部分,以下就是使用活動記錄的步驟。
1.建立表
2.連接數據庫
3.建立ORM
4.進行增、刪、改操作
第一步需要完全按著規范來做。建立表的過程一定要嚴格按著規范進行,否則就會覆蓋活動記錄的默 認值。以下是建立表的詳細過程:
·建立表
如果你不想在映射時做大量的工作,那麼數據表必須按著活動記錄所制定的規范來建立。過程如下:
1.表名應該是復制形式(如orders)。
2.主鍵應該被命名為Id,它的數據類型應該是整型。
如果某個表引用了另外一個表,那麼這個表的外鍵應該按如下格式取名:
<表名的單數形式>_id
因此,按著上面兩條規范建立orders表的SQL語句(MySQL數據庫)如下:
create table orders ( id int not null auto_increment, name varchar(50) not null, … … primary key (id) );
·連接數據庫
就象RoR的其它操作一樣,數據庫的連接也是非常快速的。這就意味著活動記錄在內部做了很多的工作 ,如自動偵測特定的數據庫適配器的細節。為了連接數據庫,必須使用相應的連接參數調用Base類的 establish_connection()方法。這些參數根據數據庫的不同而不同。下面的語句是使用 establish_connection通過用戶名、密碼、數據庫等信息連接本機MySQL數據庫,其中"encoding => gb2312"是為了操作中文所需。
establish_connection( :adapter => "mysql", :host => "localhost", :username => "root", :encoding => "gb2312", :password => "1234", :database => "test" )
·建立ORM
在建立完數據庫和表後,下一步就是將這個數據表映射成Ruby的類。我們從上述可知,RoR映射數據表 是非常快的。只要一個類從ActiveRecord::Base繼承,數據表就自動映射成了Ruby類(類名為表名的單數 形式)。下面是將orders表映射成Order類的代碼:
class Order < ActiveRecord::Base … … end
·進行增、刪、改操作
對一個數據表最常用的三種操作就是增、刪、改。這也是一個數據庫應用程序的其本的操作。使用活 動記錄對數據表進行這三種操作是非常容易的。下面的代碼將描述如何使用活動記錄對數據進行這三種操 作。
·增加記錄
增加記錄是在建立一個空表後應該做的第一件事。在活動記錄中為我們建立了new方法來向表中增加記 錄,並通過update_attributes方法保存新增加的記錄。代碼如下:
order = Order.new
order.name = "computer"
order.update_attributes(params[:order])
刪除記錄
為了刪除記錄,活動記錄提供了delete方法。這個方法支持單行刪除,也支持多行刪除。以下語句刪 除了id等於12的記錄:
Order.delete(12)
下面的語句刪除了多條記錄:
Order.delete([3, 54, 100])
·修改記錄
在修改記錄之前,首先要確定要修改的記錄,這一過程一般使用查詢來完成。因此,修改就是查詢和 更新記錄的組合。如下面的語句將id=100的記錄中的name的值改為"car"。
order = Order.find(100)
order.name = "car"
order.save
上面的代碼只是粗略地描述了一下活動記錄的功能。我們將在下面的實例中演示如何將活動記錄和
ActionController以及ActionView一起使用建立一個登錄程序。
實例
這個登錄程序非常簡單。下面將描述這個程序的基本功能:
這個程序有一個窗口允許用戶輸入用戶名和密碼。在輸入用戶名和密碼後,系統將會驗證它們的合 法性。在用戶登錄後,系統將這個用戶的信息記錄在session中,直到它們注銷登錄。
下面將描述組成系統的模塊:
User.rb - 數據表(users)的映射
login_controller.rb - 控制前端和後端的數據流
login.rhtml - 顯示登錄界面
下面是建立users表的SQL語句:
create table users (
id int not null auto_increment,
name varchar(100) not null,
password char(40) null,
primary key (id);
}
接下來我們處理數據表映射類。由於我們正在使用RoR中的活動記錄。因此,除了可以使用 establish_connection方法連接數據庫外,我們還可以使用config目錄中的database.yml文件來描述數據 庫連接信息。如下是在database.yml的development中的設置情況:
development:
adapter: mysql
database: test
encoding: gb2312
username: root
password: 1234
host: localhost
然後使用以下命令建立數據表映射類User:
ruby script/generate model User
這個User類包含兩個方法:try_to_begin(這個方法調用login方法)和login。代碼如下:
class User < ActiveRecord::Base
def self.login(name, password)
find(:first, :conditions =>
["name = ? and hashed_password = ?", name,password])
end
def try_to_login
User.login(self.name, self.password)
end
end
Login方法使用了find方法查詢users表中的記錄,並進行驗證。這個方法的邏輯是非常簡單的: try_to_login方法通過controller被調用。然後將用戶名密碼傳入login方法中。Login方法返回包含用戶 名和密碼的數據對象。
接下來我們使用如下命令建立控制類:
ruby script/generate controller Login
以下代碼是控制類的實現,其中包括數據驗證和處理session。
class LoginController < ApplicationController
def login
@user = User.new(params[:user])
logged_in_user = @user.try_to_login
if logged_in_user
session[:user_id] = logged_in_user.id
redirect_to(:action => "index")
else
flash[:notice] = "不正確的用戶名和密碼!"
end
end
end
下面是login.rhtml的代碼
<% @page_title = "增加一個用戶" -%>
<%= error_messages_for 'user' %>
<%= form_tag %>
<table>
<tr>
<td>User name:</td>
<td><%= text_field("user", "name") %></td>
</tr>
<tr>
<td>密碼:</td>
<td><%= password_field("user", "password") %></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value=" ADD USER " /></td>
</tr>
</table>
<%= end_form_tag %>
到現在這個程序已經完成了。如果你將這個應用程序和使用其它語言編寫的同樣的應用程序相比,基 於RoR的應用程序的代碼是非常少的。本文只是對活動記錄的主要功能進行簡單的描述,如果讀者對其感 性趣,可以查閱相關的文檔了解更詳細信息。