开发人员:开放源代码
Rails 上的 HR 模式作者:Casimir Saternos
了解创建可使用旧模式的 Ruby on Rails Web 应用程序的技巧。2009 年 11 月更新 Oracle 数据库有着辉煌的历史和光明的未来。它拥有最新的创新特性以及超前很多现代技术的历史。应用程序不断更替,但是组织的数据一直保留在已通过各种版本迁移的 Oracle 数据库中。由于现在存在大量的旧模式,这已经带来了技术上的挑战。许多组织面临着如何使其客户群更广泛地利用这些数据的挑战。 Ruby on Rails(或者简称“Rails”)是一个完备的应用程序框架,开发人员、DBA 和系统管理员可以使用该框架快速开发 Web 应用程序。该框架是开放源代码的,其使用渐为流行。使用该框架,您可以比使用其他框架更快速地构建和开发与数据库集成的 Web 应用程序。 现在提供的大多数 Rails 示例和教程都包括创建一个带表和列的新数据库模式,这些表和列遵守该框架要求的结构和命名惯例。这些教程还假设一个相当简单的对象关系映射 — 使用旧模式时该映射不适用。但是,该框架和 Oracle 数据库都提供一些特性,这些特性可用于创建与旧模式集成的 Web 应用程序。 本文说明创建 Oracle 演示模式 HR 的 Web 前端的技巧。本文的示例代码包括一个完整的 Ruby on Rails Web 应用程序,该应用程序基于 HR 模式开发,该模式运行于 Oracle 数据库 10g 快捷版 (XE) 上。该应用程序是在 Windows 环境下开发的,但在其他支持 rails 和 Oracle 的环境下也可运行。非 Windows 用户在执行本文所述命令时应将所有反斜线转换为正斜线。 为什么使用 Ruby on Rails?可用于 Web 开发的平台有很多,包括 Microsoft .Net、Java 2 企业版和 PHP。此外,还有 Oracle Application Express,这是 Oracle 数据库 10g 及更高版本的一个特性(也可单独提供),人们普遍认为 Oracle Application Express 是快速开发与 Oracle 数据库集成的 Web 应用程序的理想平台。那么为什么还对一个使用相对不熟悉的语言的新平台这么感兴趣呢? 依设计,Rails 可以进行极快的 Web 应用程序开发。Rails 是通过遵守惯例而不是强制开发人员预先做出所有配置决定来做到这一点的。安装了 Ruby 和各种所需的程序包之后,您只需运行很少的几个命令并编辑一个文件 (database.yml) 就可以创建一个最小的 Web 应用程序。附带的代码生成器或代码库可应对 Web 开发中很多最常见的任务。Ruby 语言具有 Java 等语言的面向对象的功能,但是还可以用于创建简单的脚本。该语言功能全面,使您无需借助各种不同技术来完成手边的任务就可以创建应用程序。
Rails 因其加快了应用程序的开发速度而赢得了近乎传奇般的声誉。之所以取得这样的成功,部分是因为其要求遵守规定的编码标准和命名惯例。这些标准和惯例不仅是 Rails 框架所要求的,它们通常也是很好的编码习惯。 传统模式与 Oracle 和 Rails 集成的有关惯例包括:
继续创建基于旧模式运行的 Rails 应用程序的方法有很多。一些技巧涉及使用 Rails 特性,还有一些技巧涉及修改底层数据库对象。演示 Web 应用程序并不尝试说明继续进行的每个可能方法,而是尝试利用 Oracle 和 Rails 两者的强大功能,提供一个清晰、开发速度快、易于维护的合理解决方案。 Rails 社区将 Ruby on Rails 框架的特征归结为“教条式”。这可以看作是肯定性的描述,表明该软件的设计加强了对标准和惯例的遵守。但是,这样的目标也引发了担忧 — 该框架会限制或约束应用程序开发。我们的应用程序包括实现表明框架灵活性的一些要求。 Ruby on Rails 框架提供在新的或旧的数据库模式上快速构建 Web 应用程序所需的工具。看一下 rake(一个 Ruby 构建实用程序)的输出,这可以让您感受一下创建该项目所需的工作量: C:\hr_rails\hr>rake stats (in E:/ruby_apps/hr_rails/hr) +----------------------+-------+-------+---------+---------+-----+-------+ | Name | Lines | LOC | Classes | Methods | M/C | LOC/M | +----------------------+-------+-------+---------+---------+-----+-------+ | Controllers | 243 | 201 | 7 | 35 | 5 | 3 | | Helpers | 0 | 0 | 0 | 0 | 0 | 0 | | Models | 167 | 144 | 6 | 8 | 1 | 16 | | Libraries | 0 | 0 | 0 | 0 | 0 | 0 | | Functional tests | 440 | 315 | 10 | 50 | 5 | 4 | | Unit tests | 50 | 35 | 5 | 5 | 1 | 5 | +----------------------+-------+-------+---------+---------+-----+-------+ | Total | 900 | 695 | 28 | 98 | 3 | 5 | +----------------------+-------+-------+---------+---------+-----+-------+ Code LOC: 345 Test LOC: 350 Code to Test Ratio: 1:0.9 开发该应用程序需要的类不到 30 个,代码不到 350 行! 安装和运行 Web 应用程序安装 Oracle 数据库快捷版、Ruby、Rails 和 OCI8 程序包是安装该应用程序的前提条件。由于介绍每个过程将需要一系列文章,因此我仅向您提供安装资源参考: 安装这些程序后,下载并解压缩 hr_rails.zip 文件,该文件包含与本文相关的所有代码资源。文件解压缩后,其目录结构如下。
该目录结构没有什么特别的,它是所有 Rails 应用程序的标准结构。应用程序的名称(本示例为 hr)显示为根目录。app 目录中的 models、views 和 controllers 目录包含大量的应用程序代码。config 目录包含 database.yml 文件(用于配置数据库连接)和 routes.rb 文件(用于定义充当应用程序索引的页面)。public 文件夹包含保存 Web 资源(包括脚本、图像和样式表)的目录。尽管本文没有讨论,但 test 目录包含对应用程序进行单元测试的相关资源。 安装了软件、创建了模式并配置了 Rails 应用程序后,就可以运行该应用程序了。从 hr 目录,运行: ruby script\server 该命令启动 WEBBrick(安装时随带的 Ruby Web 服务器)。在 Web 浏览器中,输入将在端口 3000 运行的 Web 应用程序的 URL,例如 http://localhost:3000。 下面列出了在应用程序中显示的页面的示例:
数据库和 HR 模式配置安装 Rails 的服务器上必须安装了 SQL*Plus 客户端(或者 Oracle 即时客户端软件)。必须创建一个 TNSNAMES.ora 项,来引用包含要使用的 HR 模式的数据库。有必要向 Oracle 新用户说明一下:TNSNAMES.ora 文件包含用于连接 Oracle 数据库的连接信息。数据库可以位于同一计算机上也可以位于远程服务器上。连接信息包括服务器名称、数据库名称和正在使用的数据库端口。Ruby OCI8 程序包使用该信息来让 Rails 与数据库通信。OCI8 层是用 Ruby 编写的层,该层利用底层 Oracle 数据库配置(在 TNSNAMES.ora 中指定)来构建数据库连接。 要创建 Web 应用程序所需的模式对象,首先执行以下任务:
要完成这些任务,运行 create_rails_db_user_and_privs.sql 脚本,并对提示做出相应的回答。例如: C:\hr_rails\hr>sqlplus /nolog SQL*Plus: Release 10.1.0.2.0 - Production on Wed Mar 8 12:31:01 2006 Copyright (c) 1982, 2004, Oracle. All rights reserved. SQL> @create_rails_db_user_and_privs Enter the DBA user: system Enter the DBA password: notmanager Enter the Database Name ( Oracle SID): xe Enter the (new) rails user (user will be DROPPED and created): hr_rails Enter the rails user's password: hr_rails Enter the HR user (to grant the rails user privs): hr Enter the HR user's password: hr Connected. . . . 运行了许多命令后就创建了许多对象。在 create_db_objects.log 文件(在工作目录中创建)中查看结果。 集成数据库和应用程序数据库。面向对象的编程专家 Martin Fowler 对应用程序 数据库和集成 数据库做了区分,该区分十分有用。一般来说,应用程序数据库是由单个应用程序使用的数据库,而集成数据库则被大量应用程序访问和使用。Rails 开发是针对使用应用程序数据库的应用程序开发。当前的项目显示了一种结合使用集成数据库和 Rails 的方法。 在该应用程序中,并没有直接使用 HR 用户访问该模式,而是创建了一个新用户(本文中命名为 hr_rails)。为 Rails 应用程序专门指定一个用户能够使 DBA 清晰地分辩访问所讨论数据库模式的应用程序。此外,Rails 鼓励使用符合标准命名惯例的表和列名称。新模式将包含与底层 HR 表相对应的视图。这些视图自然可更新而不只是能查询,因此也可用于所有插入、更新和删除操作。实际上,该方法是要努力创建一种在某种程度上独立于集成数据库模式的应用程序数据库模式(使用 Fowler 的术语)。 使用 Oracle 的“自然可更新”视图可提供一个有用的界面来利用 ActiveRecord 的对象关系功能。此外,这些视图还以一种最适于 Rails 访问的形式对表结构和数据进行格式设置。这些视图还可以隔离 Rails 应用程序,从而增强对访问 HR 模式的 Rails 数据库用户和其他应用程序用户的审计可见性。Oracle SQL 的所有功能(包括 Oracle 对语言和功能扩展)都可通过 find_by_sql 来加以利用。 对于应用程序内的引用,在“关于该站点”页面的一个图像上可以找到实体关系图的一部分。还有一个从该页面(以及从主页)指向另一个页面(该页面查询 Oracle 数据字典以显示视图名称以及列名称和类型)的链接。 更改 HR 模式尽管 HR 模式基本上保持不变,但是应用程序确实需要一些调整。我添加了 Rails 用于填充表的主键的一些序列。其他应用程序可能需要访问这种序列,因此 HR 模式本身附带有这种序列。 我修改了一个 HR 模式中已经存在的触发器 (UPDATE_JOB_HISTORY),以便仅在与员工有关的工作或部门发生变化时调用 add_job_history 过程。我做这样的更改是为了将调用该触发器的情形限制在与员工的工作历史记录实际相关的字段上。我又添加了一个触发器 (DELETE_JOB_HISTORY),用于在删除员工时删除员工的工作历史记录。设置数据库约束的方式要求该触发器允许删除员工。例如,在生产应用程序中,可能归档 JOB_HISTORY,员工记录的状态可能是“非活动”。 开发过程用于创建示例应用程序的开发过程大致如下所示:
支架。在开发过程中,会生成每个表完整的模型、视图和控制器。尽管为所有正在使用的模型生成了全部支架,但最终版本并不包括全部可用功能。用户只能查看地区和国家列表。可以查看、插入、更新和删除位置、部门和员工列表。 模型。每个 Model 类都有类似的特性。下面显示了代表性示例。您可以参考代码查看其他详细信息。 输入域验证。Rails 框架尝试将验证代码集中在 Model 类中。这种方法有很多好处,最值得一提的是使用 Model 类的所有插入和更新处理都将包括定义的约束,并在验证规则失败时向用户返回一致的消息。但是,该数据库自身还可以并应该用于约束数据。这样就可以限制任何 应用程序或 SQL 语句输入表中的数据。此外,可以使用视图层按照其设计强制执行验证。设计较好的 GUI 可以防止用户选择无效的选项。设置了长度的文本域可防止字符串超过允许的最大长度。下拉框可防止用户在需要包含外键输入的域中输入不符合要求的内容。 员工模型验证确保包括必填域;字符串数据域不超过最大长度;电子邮件地址唯一;工资是数字。(视图通过强制用户从下拉框中选择数据隐式验证部门和经理)。 validates_presence_of :email, :hire_date, :last_name, :first_name, :phone_number, :salary validates_uniqueness_of :email validates_length_of :first_name, :maximum => 20 validates_length_of :last_name, :maximum => 25 validates_length_of :email, :maximum => 25 validates_length_of :phone_number, :maximum => 20 validates_numericality_of :salary, :only_integer => true 此外,员工模型中有自定义验证代码,可确保工资和佣金都设置在有效范围内: def validate if salary != nil if salary < 1 errors.add(:salary, "must be positive.") end if salary > 999999 errors.add(:salary,"must be less than 999999") end end if commission !=nil unless commission >= 0 && commission < 1 errors.add(:commission, "must be greater than 0 and less than 1.") end end end 查询。我们在代码中看不到与 INSERT、UPDATE、DELETE 和 SELECT * 查询有关的 SQL 语句,而每个 Model 类都会使用这类查询。这类代码是在后台生成的。但是,旧模式的一个共同特征就是需要复杂的 SQL 语句来检索或汇总数据。另外,Oracle 数据库还提供其他 RDBMS 中没有的强大功能。例如,它可以使用单个层次查询生成数据的树状表示。在其他数据库系统中要实现此类功能可能需要编写许多查询语句和复杂的代码。Rails 通过在 Model 类中定义一个 find_by_sql 函数,提供了一种执行 Oracle 特定 SQL 语句的方法。 构建公司层级结构的查询如下所示: SELECT tree.*, LEAD (hierarchy_level) OVER (ORDER BY seq) next_level FROM ( SELECT CONNECT_BY_ROOT last_name top_node_name, (last_name || ', ' || first_name ||' ('||job_title||')') employee_name, emp.id employee_id, SYS_CONNECT_BY_PATH (last_name, '->') node_path, LEVEL hierarchy_level, ROWNUM seq FROM( SELECT e.*, j.job_title FROM employees e, jobs j WHERE e.job_id = j.id ) emp START WITH emp.job_title= 'President' CONNECT BY PRIOR emp.id = manager_id ORDER SIBLINGS BY emp.id ) tree ORDER BY seq 显示结果的页面包含 JavaScript,该 JavaScript 允许用户“下钻”层级结构。LEAD 分析函数允许访问多行而无需使用自联接。结果集中的当前行可以有效“预测”下一行中的层级,这极大地简化了用于显示层级结构的 JavaScript 代码。
定义了与员工模型相关的许多关系。员工属于部门,向经理汇报。在数据库级别,存在反映这些关系的外键约束。Rails 框架还指定了这些关系为一对多。经理本身是员工表中的一个字段。 belongs_to :department belongs_to :manager, :class_name => "Employee", :foreign_key => "manager_id" belongs_to :job has_many :department has_many :managed_employee, :class_name => "Employee", :foreign_key => "manager_id" 这些关系设置了大量方便的方法,使得程序员可通过模型对象轻松访问相关数据。 控制器。对生成的控制器对象的修改相对较少。主控制器为主视图和活动视图添加了方法。员工视图包括几个额外的调用 — 对用于填充经理和部门下拉框的模型的调用。其余代码只是自动生成的支架的一部分。 修改了 config\routes.rb 文件,以便 http://localhost:3000 映射到应用程序的主页。 视图。站点中的所有页面都有公用的标题、左侧导航栏和页脚。这些都被整合到一个 布局 文件中。默认情况下,Rails 查找 /app/views/layout 目录中一个名为 <controller_name>_layout.<xml 或 rhtml> 的布局。但是,如果您在 layouts 目录中创建一个名为 application 的布局,则没有基于控制器名称的布局的控制器将使用该布局。 视图利用了许多 Rails 类,这些类旨在将视图中显示的代码的数量减至最少。使用 number_to_currency 帮助器或 number_with_precision 帮助器将数字数据转换为货币格式。 Rails 还包括一些 JavaScript 库,这些库提供大量与 AJAX 支持和 DOM 处理相关的服务。虽然这些服务的用途并不广泛,但是可以提供点击大多数页面上的图像时使图像不显示的视觉效果。此外,还包括其他一些 JavaScript 函数,利用这些函数可实现鼠标放置按钮效果和公司层级结构下钻。 高级 Oracle 功能示例应用程序利用 Rails 功能自动生成按主键插入、更新和删除以及从表中选择时所需的简单 SQL 语句。但是,也包括一些使用 Oracle SQL 的查询。region.rb 模型包含创建地区薪酬报告 (GROUP BY ROLLUP) 以及列出应用程序使用的视图的模式报告 (LAG OVER) 的 SQL。employee.rb 模型包括用于构建公司层级结构的查询。该查询使用 CONNECT BY 执行递归搜索以及 LEAD OVER。 总结HR 将继续提供广受欢迎的模式来演示 SQL 功能。如该应用程序所演示的,它还作为一个例子来说明如何使用 Ruby on Rails 创建使用旧模式的 Web 应用程序。 Casimir Saternos 是 Oracle 认证 DBA、IBM 认证企业开发人员和 Sun 认证 Java 程序员,住在宾夕法尼亚州 Allentown。 |