用
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 作为映射容器。而活动记录采用的是更容易使用的 " 约定 " 方式进行映射。下面让我们来看看活动记录是如何做的。
1.将表映射成类
为了将表映射成类, Ruby 类必须从 ActiveRecord::Base 继承。这个 Base 类在 ActiveRecord 包中。那么一个类从 ActiveRecord::Base 继承后发生了什么呢?实际上这个子类已经和一个数据表相对应了。也许大家看到这有一些迷糊,我除了写一个从 ActiveRecord::Base 继承的空类什么代码都没写,怎么就映射完了。其实这要依靠活动记录的命名约定。活动记录假设一个类名的复数形式(英文类名)就是表名。如果类名中有多个大写字母,那么活动记录就假设表名就是这些单词中间用下划线隔开后连在一起,请看下面的例子。
无论是桌面程序还是基于 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 作为映射容器。而活动记录采用的是更容易使用的 " 约定 " 方式进行映射。下面让我们来看看活动记录是如何做的。
1.将表映射成类
为了将表映射成类, 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 |
接下来让我们看看如何将字段映射成属性。
2.将字段转换为属性
在一个数据表被映射成类后,表中的字段就将自动映射成类的属性。这是因为活动记录是在程序运行时动态地将表中的字段映射成类的属性。事实上,在从 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
|
下面让我们来讨论主键的映射。
3.将主键映射成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 |
4.将记录映射成对象
无论什么时候,映射类的查询方法被执行时,在内部都会调用相应的 SQL 语句来查询数据库,并且将查询结果返回,这些返回的结果最终以对象的形式表现。列值将成为对象的属性。返回的每一行将被映射成一个对象。例如以下代码将返回 Id 等于 100 的 Order 对象:
an_order = Order.find(100)
|
上面的代码演示了如何得到特定的记录。接下来让我们看一下使用活动记录建立相应的操作的步骤。
使用活动记录的步骤
虽然使用活动记录映射数据表不需要复杂的设置,但我们必须按着活动记录所制定的规范进行操作。这些规范将成为活动记录工作的一部分,以下就是使用活动记录的步骤。
1. 建立表
2. 连接数据库
3. 建立 ORM
4. 进行增、删、改操作
第一步需要完全按着规范来做。建立表的过程一定要严格按着规范进行,否则就会覆盖活动记录的默认值。以下是建立表的详细过程:
1. 建立表
如果你不想在映射时做大量的工作,那么数据表必须按着活动记录所制定的规范来建立。过程如下:
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) ); |
2. 连接数据库
就象 RoR 的其它操作一样,数据库的连接也是非常快速的。这就意味着活动记录在内部做了很多的工作,如自动侦测特定的数据库适配器的细节。为了连接数据库,必须使用相应的连接参数调用 Base 类的 establish_connection() 方法。这些参数根据数据库的不同而不同。下面的语句是使用 establish_connection 通过用户名、密码、数据库等信息连接本机 MySQL 数据库,其中 "encoding = > gb2312" 是为了操作中文所需。
establish_connection( :adapter = > "mysql", :host = > "localhost", :username = > "root", :encoding = > "gb2312", :password = > "1234", :database = > "test" ) |
3. 建立 ORM
在建立完数据库和表后,下一步就是将这个数据表映射成 Ruby 的类。我们从上述可知, RoR 映射数据表是非常快的。只要一个类从 ActiveRecord::Base 继承,数据表就自动映射成了 Ruby 类(类名为表名的单数形式)。下面是将 orders 表映射成 Order 类的代码:
class Order
<
ActiveRecord::Base … … end |
4. 进行增、删、改操作
对一个数据表最常用的三种操作就是增、删、改。这也是一个数据库应用程序的其本的操作。使用活动记录对数据表进行这三种操作是非常容易的。下面的代码将描述如何使用活动记录对数据进行这三种操作。
· 增加记录
增加记录是在建立一个空表后应该做的第一件事。在活动记录中为我们建立了 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 语句:
这个登录程序非常简单。下面将描述这个程序的基本功能:
这个程序有一个窗口允许用户输入用户名和密码。在输入用户名和密码后,系统将会验证它们的合法性。在用户登录后,系统将这个用户的信息记录在 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 的应用程序的代码是非常少的。本文只是对活动记录的主要功能进行简单的描述,如果读者对其感性趣,可以查阅相关的文档了解更详细信息。