Oracle 和 Ruby on Rails
利用 Oracle Application Express 3.0 中的高级打印功能
结合使用 Oracle 和 Ruby on Rails
本教程介绍如何使用 Oracle 安装 Ruby/Rails,以及如何开发高效且功能强大的 Ruby/Rails 应用程序。您将获得为企业创建强大的 Ruby/Rails 应用程序所需的知识。
本教程包括下列主题:
将鼠标置于此图标上可以加载和查看本教程的所有屏幕截图。(警告:因为此操作会同时加载所有屏幕截图,所以网速较慢时,响应时间可能会比较长。)
注:此外,您还可以在下列步骤中将鼠标放在每个单独的图标上,从而仅加载和查看与该步骤相关的屏幕截图。可以通过单击各个屏幕截图来将其隐藏。
Ruby on Rails 是一个免费的 Web 应用程序框架,旨在提高创建数据库驱动的 Web 站点的速度和方便性,并从一开始就提供主要代码框架(结构)。通常缩写为 Rails 或 RoR,Ruby on Rails 是一个用 Ruby 编程语言编写的开源项目,使用 Rails 框架的应用程序是用模型-视图-控制器设计模式开发的。
RoR 在 J2EE 和 PHP 编程人员中备受推崇。当您了解 RoR 的优势后,它对 J2EE 和 PHP 编程人员的吸引力具有重要作用。首先,它使用任何自视甚高的设计模式都很钦佩的严格的模型-视图-控制器体系结构 — 这可以解释它为什么吸引了大量 J2EE 开发人员。其次,使用 Rails 可以轻松地构建基本系统 — 这对 PHP 开发人员具有吸引力。
RoR 为 MVC 提供了令人满意的解决方案。模型不仅仅是数据;它执行适用于该数据的所有业务规则。模型既可充当网关守卫又可充当数据存储。视图通常基于模型中的数据生成一个用户界面。尽管视图可能会通过各种方式向用户显示输入的数据,但视图本身从不处理传入的数据。数据显示之后,视图的工作就完成了。控制器接收来自外界的事件(通常是用户输入),与模型进行交互,并向用户显示相应的视图。
RoR 将 ActiveRecord 作为对象关系映射 (ORM) 层提供,以便连接数据库和操作数据。ActiveRecord 严格遵循标准的 ORM 模型:表映射到类,行映射到对象,列映射到对象属性。
创建 Rails 应用程序时,将在根目录下生成以下目录和文件:app、components、config、db、doc、lib、log、public、Rakefile、README、script、test、tmp 和 vendor。
Ruby 是一种动态的开源编程语言,重点关注简单性和工作效率。其简洁的语法易于阅读、便于编写。要了解有关 Ruby 语言的更多信息,参见附录:Ruby 入门。
要获得更多信息,您可以访问 Ruby on Rails OTN 论坛。
返回主题列表
为了学习该动手操作讲座,需要安装以下软件:
| 1. |
安装 Oracle 数据库快捷版或 Oracle 数据库 11g。
|
| 2. |
安装 Oracle 即时客户端和 OracleOnRails(ruby、rubygems、activesupport、activerecord、rake、ruby-oci8 等)。还需要配置模式。参见附录:通过 Oracle 安装 Ruby on Rails 中的下列说明。
|
| 3. |
下载并解压缩 rubyrails.tar 文件。该文件包含执行本教程所需的所有文件。 |
返回主题列表
您将在本部分中使用以下命令:
| OCI8.new (userid, password, dbname = nil, privilege = nil): |
通过 userid 和 password 连接到 Oracle。dbname 是 Net8 的连接字符串。如果您需要 DBA 权限,则将 privilege 设置为 :SYSDBA 或 :SYSOPER。
|
| OCI8#logoff |
断开与 Oracle 的连接。将回滚未提交的事务。
|
| OCIError |
包含 Oracle 的错误代码的异常类。您可以通过 OCIError#message 获得错误消息,通过 OCIError#code 获得错误代码。 |
创建 ruby 脚本过程中的第一个任务是创建到数据库的连接。执行以下步骤:
| 1. |
在终端窗口中,通过执行以下命令来执行 connect.rb 脚本:
ruby connect.rb
如果连接成功,您会看到以下消息;如果连接失败,您将看到一条错误消息。
|
| 2. |
本教程的其余脚本中将包括以下命令:
require 'config.rb'
#create connection
conn = OCI8.new(DB_USER, DB_PASSWORD, DB_SERVER)
# operations on conn goes here
#log out
conn.logoff
|
返回主题列表
您将在本部分中使用以下命令:
| OCI8#parse (sql) |
创建一个游标,准备执行 SQL 语句并返回 OCI8::Cursor 的实例。
|
| OCI8#exec (sql, *bindvars) |
执行 SQL 语句。返回值的类型取决于 SQL 语句的类型。指定 bindvars 后,它们在执行前作为绑定变量进行绑定。 |
| OCI8::Cursor#exec(*bindvars) |
执行用游标分配的 SQL 语句。返回值的类型取决于 SQL 语句的类型。 |
| OCI8::Cursor#getColNames |
将选择列表的名称作为数组获取。在执行后使用此方法。 |
要创建一个简单查询并显示结果,执行以下步骤。
| 1. |
在终端窗口中,通过执行以下命令来执行 fetch.rb 脚本:
ruby fetch.rb
其输出显示在屏幕截图中。
|
| 2. |
还可以通过另一种方式编写更针对于 ruby 的相同的代码。在终端窗口中,通过执行以下命令来执行 fetch_r.rb 脚本:
ruby fetch_r.rb
其输出显示在屏幕截图中。
|
返回主题列表
绑定变量提高了代码可重用性,消除了 SQL 注入攻击的风险。您将在本部分中使用以下命令:
| OCI8::Cursor#bind_param(key, val, type = nil, length = nil) |
显式绑定变量。当 key 为数字时,它通过位置绑定(从 1 开始)。当 key 为字符串时,它通过占位符名称绑定。
|
| OCI8#exec (sql, *bindvars) or OCI8::Cursor#exec(*bindvars) |
也可以通过 bindvars 绑定变量。 |
| OCI8::Cursor#[key] |
获取/设置绑定变量的值。 |
要在本示例中使用绑定变量,执行以下步骤。
| 1. |
在终端窗口中,通过执行以下命令来执行 bind.rb 脚本:
ruby bind.rb
其输出显示在屏幕截图中。
|
| 2. |
要使用绑定变量测试性能改善,通过执行以下命令来执行 bind_perf_test.rb 脚本:
ruby bind_perf_test.rb
其输出显示在屏幕截图中。
|
返回主题列表
您将在本部分中使用以下命令:
| OCI8::Cursor#define(pos, type, length = nil) |
在分析和执行过程中使用该方法。pos 从 1 开始。当 type 为 String 时使用 length。 |
您可以显式指明获取的值的数据类型。要在本示例中定义数据类型,执行以下步骤。
| 1. |
在终端窗口中,通过执行以下命令来执行 define.rb 脚本:
ruby define.rb
其输出显示在屏幕截图中。
您会看到两个输出块之间的差别。
|
返回主题列表
在 Oracle 数据库中操作数据(插入、更新或删除数据)时,更改的数据或新数据在提交到数据库中之前仅在数据库会话中可用。更改的数据提交至数据库,然后可供其他用户和会话使用。这是一个数据库事务。 单独提交每个更改会额外增加服务器的负载。通常,您希望提交所有数据或者都不提交。进行您自己的事务控制具有性能和数据完整性优势。 您将在本部分中使用以下命令:
| OCI8#autocommit |
获取/设置自动提交模式的状态。默认值是 false(记住:注销时不回滚未提交的事务)。如果为 true,每次执行 insert/update/delete 语句时都自动提交事务。 |
| OCI8#commit() |
提交事务。 |
| OCI8#rollback() |
回滚事务。 |
要了解如何管理事务,执行以下步骤。
| 1. |
在终端窗口中,通过执行以下命令来执行 transaction.rb 脚本:
ruby transaction.rb
该脚本使用 conn1 连接更新一行。在 Oracle 中,新数据在提交前仅在原始数据库会话中可见。其输出显示在屏幕截图中。
在这种情况下,conn2 连接不知道 conn1 的未提交事务发生了什么。
|
| 2. |
更新 transaction.rb 脚本,取消对 conn1.autocommit = true 的注释,然后保存文件。
使用以下命令再次执行脚本:
ruby transaction.rb
现在,conn2 知道哪些内容是新增的。其输出显示在屏幕截图中。
|
| 3. |
单独提交每一行会额外增加服务器的负载。您可以比较单独提交每行与在事务结束后提交之间的性能差异。要测试差别,使用以下命令执行 trans_perf_test.rb 脚本:
ruby trans_perf_test.rb
注意,第二个数字比第一个数字小。其输出显示在屏幕截图中。
|
返回主题列表
PL/SQL 是 Oracle 对 SQL 的过程语言扩展。PL/SQL 存储过程和函数存储在数据库中,因此其访问速度非常快。使用 PL/SQL 存储过程允许所有数据库应用程序重用逻辑,无论应用程序以何种方式访问数据库。许多与数据相关的操作在 PL/SQL 中的执行速度比将数据提取到一个程序中(例如,Ruby)然后再进行处理的速度快。
您将在本部分中使用以下命令:
| DBMS_UTILITY 和 DBMS_OUTPUT |
Oracle 存储程序包。TO_CHAR 是一个内置函数。 |
要在 Ruby 脚本中调用 PL/SQL 过程和函数,执行以下步骤。
| 1. |
在终端窗口中,通过执行以下命令来执行 plsql.rb 脚本:
ruby plsql.rb
其输出显示在屏幕截图中。
|
返回主题列表
Oracle 字符大对象 (CLOB) 和二进制大对象 (BLOB) 列(以及 PL/SQL 变量)可以包含大容量 (GB) 的字符和二进制数据。您将在本部分中使用以下命令:
| OCI8::BLOB#available |
检查 BLOB 是否可用。要使用 BLOB,您首先需要插入 EMPTY_BLOB()。 |
| OCI8::BLOB#read(size = nil) |
从 BLOB 读取最大的字节大小,如果大小省略,则读取到文件结束处。 |
| OCI8::BLOB#write(string) |
将给定的字符串写入到 BLOB。 |
要创建一个小型应用程序以将图像加载并显示到数据库,执行以下步骤。
| 1. |
脚本文件所在的文件夹中有一个 PNG 文件。创建一个名为 download 的文件夹。在终端窗口中,通过执行以下命令来执行 blob.rb 脚本:
mkdir download
ruby blob.rb
其输出显示在屏幕截图中。
|
返回主题列表
所有版本的 Oracle 数据库都包含“XML DB”。此试验包括将 XML 数据从 Oracle 返回至 Ruby 的基本操作。您将在本部分中使用以下命令:
| DBMS_XMLGEN.getxml (statement) |
根据 SELECT 语句从关系数据生成 XML。它返回 CLOB。 |
要了解 Oracle 的基本 XML 功能,执行以下步骤。
| 1. |
在终端窗口中,通过执行以下命令来执行 xml.rb 脚本:
ruby xml.rb
其输出显示在屏幕截图中。
|
返回主题列表
ActiveRecord 连接业务对象和数据库表以创建持久的域模型,其中的逻辑和数据位于一个包装中。它是对象关系映射 (ORM) 设计模式的一个实现。要在本示例中使用 ActiveRecord,执行以下步骤。
| 1. |
在终端窗口中,通过执行以下命令来执行 activerecord.rb 脚本:
ruby activerecord.rb
其输出显示在屏幕截图中。
|
返回主题列表
在本教程的其余部分,您将使用以下术语:
| Rake |
一个用于构建其他 Ruby 程序的 Ruby 程序。在 Rails 中,Rake 用于执行一系列任务,如 db:migrate、db:schema:dump、db:schema:load、db:test:prepare 和 db:test:purge。它在作用域和目的方面与常见的 Linux 设计工具类似。 |
| 移植 |
开发人员可以在 Ruby(而非数据描述语言 (DDL))中创建、修改和删除其数据库对象。 |
| 结构 |
通过创建、编辑、查看和删除 ActiveRecord 类反映的条目,为您的数据提供一个简单接口。结构生成后,它将包含控制器文件(确定您应用程序的用户最终转向哪些页面)和视图文件(呈现应用程序用户将看到的页面)。 |
要使用移植和结构构建一个 Rails 应用程序,执行以下步骤。
| 1. |
您将创建一个名为 holapp 的非常基本的 Rails 应用程序。在终端窗口中,执行以下命令:
rails holapp
cd holapp
gedit config/database.yml
|
| 2. |
用以下内容替换 config/database.yml 文件中的 development 部分,然后保存并关闭该文件。
development: adapter: oracle
database: orcl11g
username: hr password: hr
|
| 3. |
现在可以生成 comic 模型。在终端窗口中,执行以下命令:
ruby script/generate model comic
|
| 4. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit db/migrate/001_create_comics.rb
|
| 5. |
用以下内容替换 self.up 部分,然后保存并关闭该文件。
def self.up
create_table :comics do |t|
t.column :name,:string
t.column :description, :string
t.column :price, :float
end
end
|
| 6. |
现在可以对数据库移植进行 rake 操作,以生成目标表。在终端窗口中,输入以下命令:
rake db:migrate
|
| 7. |
可以通过以下命令生成 comic 模型的结构
ruby script/generate scaffold comic
|
| 8. |
Webrick 是用 Ruby 编写的 HTTP 服务器库,它使用 servlet 扩展其功能。使用以下命令启动 Webrick 服务器:
ruby script/server
|
| 9. |
您可以查看应用程序。打开一个浏览器窗口,输入以下 URL:
http://localhost:3000/comics
通过单击 New Comic 来确保应用程序正常运行,创建一些记录。
|
返回主题列表
一对一关系表示表 A 中的一行与表 B 中的零行或一行相关联。要创建表之间具有一对一关系的 Rails 应用程序,执行以下步骤。
| 1. |
打开另一个终端窗口,并执行以下命令:
cd /home/oracle/Work/ruby/holapp
source /etc/bashrc
|
| 2. |
生成 order 和 invoice 模型。在终端窗口中,执行以下命令:
ruby script/generate model order
ruby script/generate model invoice
|
| 3. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit db/migrate/002_create_orders.rb
|
| 4. |
用以下内容替换 self.up 部分,然后保存并关闭该文件。
def self.up create_table :orders do |t| t.column :name, :string t.column :description, :string end end
|
| 5. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit db/migrate/003_create_invoices.rb
|
| 6. |
用以下内容替换 self.up 部分,然后保存并关闭该文件。
def self.up
create_table :invoices do |t| t.column :order_id, :integer t.column :invoicetype, :string t.column :description, :string t.column :amount, :float end end
|
| 7. |
现在可以对数据库移植进行 rake 操作,以生成目标表。在终端窗口中,输入以下命令:
rake db:migrate
|
| 8. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit app/models/order.rb
|
| 9. |
用以下内容替换文件的内容,然后保存并关闭该文件。
class Order < ActiveRecord::Base has_one :invoice end
|
| 10. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit app/models/invoice.rb
|
| 11. |
用以下内容替换文件的内容,然后保存并关闭该文件。
class Invoice < ActiveRecord::Base belongs_to :order end
|
| 12. |
可以通过以下命令生成 order 模型的结构:
ruby script/generate scaffold order
|
| 13. |
您希望编辑生成的 html。在终端窗口中,输入以下命令:
gedit app/views/orders/list.rhtml
|
| 14. |
在该文件中,用 Order.columns 替换 Order.content_columns。然后保存并关闭文件。
|
| 15. |
可以通过以下命令生成 invoice 模型的结构:
ruby script/generate scaffold invoice
|
| 16. |
您希望编辑生成的 html。在终端窗口中,输入以下命令:
gedit app/views/invoices/list.rhtml
|
| 17. |
在该文件中,用 Invoice.columns 替换 Invoice.content_columns。然后保存并关闭文件。
|
| 18. |
您可以查看应用程序。打开一个浏览器窗口,输入以下 URL:
http://localhost:3000/orders
创建一个新视图。
|
| 19. |
默认情况下,创建结构时由 Rails 生成控制器文件。这些控制器文件具有某些默认操作,如果您希望应用程序以其他方式(而非 Rails 默认生成的方式)进行操作,就需要修改这些默认操作。在终端窗口中,输入以下命令:
gedit app/controllers/invoices_controller.rb
|
| 20. |
用以下内容替换 create 部分,然后保存并关闭该文件。
def create
@order = Order.find(:first, :order => "id DESC") @invoice = Invoice.new(params[:invoice]) if @invoice.save if !@order.nil? @order.invoice = @invoice end flash[:notice] = 'Invoice was successfully created.' redirect_to :action => 'list' else render :action => 'new'
end end
|
| 21. |
您可以查看应用程序。打开一个浏览器窗口,输入以下 URL:
http://localhost:3000/invoices
创建一个新发票。创建发票之后,您会发现它与您最后创建的定单相关联。
|
返回主题列表
一对多关系表示表 A 中的一行与表 B 中的任意数量的行(可能是零行、一行或多行)相关联。要创建表之间具有一对多关系的 Rails 应用程序,执行以下步骤。
| 1. |
生成 order 和 invoice 模型。在终端窗口中,执行以下命令:
ruby script/generate model line_item
|
| 2. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit db/migrate/004_create_line_items.rb
|
| 3. |
用以下内容替换 self.up 部分,然后保存并关闭该文件。
def self.up create_table :line_items do |t| t.column :order_id, :integer t.column :subject, :string t.column :description, :string end end
|
| 4. |
现在可以对数据库移植进行 rake 操作,以生成目标表。在终端窗口中,输入以下命令:
rake db:migrate
|
| 5. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit app/models/order.rb
|
| 6. |
在文件中添加 has_many :line_items 条目,如下所示。然后保存并关闭文件。
class Order < ActiveRecord::Base has_one :invoice has_many :line_items end
|
| 7. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit app/models/line_item.rb
|
| 8. |
用以下内容替换文件的内容,然后保存并关闭该文件。
class LineItem< ActiveRecord::Base belongs_to :order end
|
| 9. |
可以通过以下命令生成 line_item 模型的结构:
ruby script/generate scaffold line_item
|
| 10. |
您希望编辑生成的 html。在终端窗口中,输入以下命令:
gedit app/views/line_items/list.rhtml
|
| 11. |
在该文件中,用 LineItem.columns 替换 LineItem.content_columns。然后保存并关闭文件。
|
| 12. |
您可以查看应用程序。打开一个浏览器窗口,输入以下 URL:
http://localhost:3000/line_items
创建一个新定单。
|
| 13. |
您希望修改控制器文件。在终端窗口中,输入以下命令:
gedit app/controllers/line_items_controller.rb
|
| 14. |
用以下内容替换文件的内容,然后保存并关闭该文件。
def create @order = Order.find(:first, :order => "id DESC") @line_item = LineItem.new(params[:line_item]) if @line_item.save if !@order.nil? @order.line_items << @line_item end flash[:notice] = 'LineItem was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end
|
| 15. |
您可以查看应用程序。打开一个浏览器窗口,输入以下 URL:
http://localhost:3000/line_items
创建 2 个 line_item。您将发现它们与最后创建的定单相关联。
|
返回主题列表
多对多关系表示表 A 中任意数量的行与表 B 中任意数量的行相关联。要创建表之间具有多对多关系的 Rails 应用程序,执行以下步骤。
| 1. |
生成 article、author 和 articles_author 的模型。在终端窗口中,执行以下命令:
ruby script/generate model article
ruby script/generate model author
ruby script/generate model articles_author
|
| 2. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit db/migrate/005_create_articles.rb
|
| 3. |
用以下内容替换 self.up 部分,然后保存并关闭该文件。
def self.up create_table :articles do |t| t.column :title, :string t.column :abstract, :string end end
|
| 4. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit db/migrate/006_create_authors.rb
|
| 5. |
用以下内容替换 self.up 部分,然后保存并关闭该文件。
def self.up create_table :authors do |t| t.column :name, :string t.column :vocation, :string end end
|
| 6. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit db/migrate/007_create_articles_authors.rb
|
| 7. |
用以下内容替换 self.up 部分,然后保存并关闭该文件。
def self.up create_table :articles_authors do |t| t.column :article_id, :integer t.column :author_id, :integer end end
|
| 8. |
现在可以对数据库移植进行 rake 操作,以生成目标表。在终端窗口中,输入以下命令:
rake db:migrate
|
| 9. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit app/models/article.rb
|
| 10. |
替换文件中的内容,如下所示。然后保存并关闭文件。
class Article < ActiveRecord::Base has_and_belongs_to_many :authors
set_sequence_name "ARTICLES_AUTHORS_SEQ" end
|
| 11. |
您希望编辑生成的脚本。在终端窗口中,输入以下命令:
gedit app/models/author.rb
|
| 12. |
替换文件中的内容,如下所示。然后保存并关闭文件。
class Author < ActiveRecord::Base has_and_belongs_to_many :articles
set_sequence_name "ARTICLES_AUTHORS_SEQ" end
|
| 13. |
可以通过以下命令生成 article 模型的结构:
ruby script/generate scaffold article
|
| 14. |
您希望编辑生成的 html。在终端窗口中,输入以下命令:
gedit app/views/articles/list.rhtml
|
| 15. |
在该文件中,用 Article.columns 替换 Article.content_columns。然后保存并关闭文件。
|
| 16. |
可以通过以下命令生成 author 模型的结构:
ruby script/generate scaffold author
|
| 17. |
您希望编辑生成的 html。在终端窗口中,输入以下命令:
gedit app/views/authors/list.rhtml
|
| 18. |
在该文件中,用 Author.columns 替换 Author.content_columns。然后保存并关闭文件。
|
| 19. |
可以通过以下命令生成 articles_author 模型的结构:
ruby script/generate scaffold articles_author
|
| 20. |
您希望编辑生成的 html。在终端窗口中,输入以下命令:
gedit app/views/articles_authors/list.rhtml
|
| 21. |
在该文件中,用 ArticleAuthor.columns 替换 ArticlesAuthor.content_columns。然后保存并关闭文件。
|
| 22. |
您希望修改控制器文件。在终端窗口中,输入以下命令:
gedit app/controllers/articles_controller.rb
|
| 23. |
用以下内容替换文件的内容,然后保存并关闭该文件。
def create @author = Author.find(:first, :order => "id DESC") @article = Article.new(params[:article]) if @article.save if !@author.nil? @author.articles << @article end flash[:notice] = 'Article was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end
|
| 24. |
在终端窗口中,输入以下命令:
gedit app/controllers/authors_controller.rb
|
| 25. |
用以下内容替换文件的内容,然后保存并关闭该文件。
def create @article = Article.find(:first, :order => "id DESC") @author = Author.new(params[:author]) if @author.save if !@article.nil? @article.authors << @author end flash[:notice] = 'Author was successfully created.' redirect_to :action => 'list' else render :action => 'new' end end
|
| 26. |
您可以查看应用程序。从您的浏览器窗口,输入以下 URL:
http://localhost:3000/articles
创建一篇文章。
|
| 27. |
然后从您的浏览器窗口,输入以下 URL:
http://localhost:3000/authors
创建两个作者。
|
| 28. |
现在,您通过输入以下 URL 可以看到作者和文章之间的关联:
http://localhost:3000/articles_authors
|
| 29. |
返回以下 URL,再创建 3 篇文章
http://localhost:3000/articles
|
| 30. |
然后输入以下 URL,就会看到您刚创建的文章与最后创建的作者相关联。
http://localhost:3000/articles_authors
|
返回主题列表
在本教程中,您学习了如何:
返回主题列表
|