ActiveRecord教程
(一、ActiveRecord基礎(chǔ))
ActiveRecord是Rails提供的一個(gè)對(duì)象關(guān)系映射(ORM)層,從這篇開(kāi)始,我們來(lái)了解Active Record的一些基礎(chǔ)內(nèi)容,連接數(shù)據(jù)庫(kù),映射表,訪問(wèn)數(shù)據(jù)等。
Active Record使用基本的ORM模式:表映射成類,行映射成為對(duì)象,列映射成對(duì)象的屬性。與很多大量使用配置的ORM庫(kù)不同,Active Record最小化了配置。想象一下,有一個(gè)使用Active Record的程序把Mysql數(shù)據(jù)庫(kù)中的orders表轉(zhuǎn)換到類,通過(guò)制定的ID查找到order,設(shè)定order的名稱,然后保存回?cái)?shù)據(jù)庫(kù):
require "rubygems"
require_gem "activerecord"
ActiveRecord::Base.establish_connection(:adapter => "mysql",
:host => "localhost", :database => "railsdb")
class Order < ActiveRecord::Base
end
order = Order.find(123)
order.name = "Dave Thomas"
order.save
在上面的例子里不需要任何配置,Active Record為我們做了這些事情,下面我們來(lái)看看ActiveRecord是怎樣工作的。
表和類
當(dāng)你創(chuàng)建了一個(gè)ActiveRecord::Base類的子類,Active Record假定表名是復(fù)數(shù)的,而類名是單數(shù)的,當(dāng)類名包括多個(gè)單詞時(shí),表名被假定為單詞間帶有下劃線,復(fù)數(shù)形式不規(guī)則,例如:
類名 表名 類名 表名
Order orders LineItem line_items
TaxAgency tax_agencies Person people
Diagnosis diagnoses Quantity quantities
Batch batches Datum data
默認(rèn)的,Active Record的表名是復(fù)數(shù)的,類名是單數(shù)的,如果你不太習(xí)慣,可以通過(guò)設(shè)置一個(gè)全局標(biāo)記來(lái)禁用它,在config目錄的environment.rb文件中設(shè)置:
ActiveRecord::Base.pluralize_table_names = false
單復(fù)數(shù)規(guī)則可以對(duì)付大部分情況,對(duì)于一些特殊情況,Active Record允許我們覆蓋默認(rèn)的生成的表名,使用set_table_name命令,例如:
class Sheep < ActiveRecord::Base
set_table_name "sheep" # Not "sheeps"
end
class Order < ActiveRecord::Base
set_table_name "ord_rev99_x" # Wrap a legacy table...
end
(二、列和屬性)
ActiveRecord中的一個(gè)對(duì)象相當(dāng)于數(shù)據(jù)庫(kù)中表的一行,對(duì)象的屬性對(duì)應(yīng)于表的列,也許你會(huì)注意到我們的Order類沒(méi)有提及關(guān)于 orders表的任何東西,這是因?yàn)锳ctiveRecord在運(yùn)行時(shí)來(lái)確定這些對(duì)應(yīng)關(guān)系,Active Record將數(shù)據(jù)庫(kù)中的模式反應(yīng)到類中。
我們的orders表可能使用下面的sql來(lái)創(chuàng)建:
create table orders (
id int not null auto_increment,
name varchar(100) not null,
email varchar(255) not null,
address text not null,
pay_type char(10) not null,
shipped_at datetime null,
primary key (id)
);
我們可以創(chuàng)建一個(gè)類來(lái)轉(zhuǎn)換這個(gè)表:
require 'rubygems'
require_gem 'activerecord'
# Connection code omitted...
class Order < ActiveRecord::Base
end
當(dāng)我們創(chuàng)建了Order類,就可以訪問(wèn)它的屬性來(lái)獲取信息,下面的代碼使用columns()方法,來(lái)返回一個(gè)Columns對(duì)象的數(shù)組,在這里,我們顯示了orders表中的每個(gè)列,并且顯示指定字段的詳細(xì)信息。
require 'pp'
pp Order.columns.map { |col| col.name }
pp Order.columns_hash['shipped_at']
運(yùn)行代碼,會(huì)得到下面的輸出:
["id", "name", "email", "address", "pay_type", "shipped_at"]
#<ActiveRecord::ConnectionAdapters::Column:0x10e4a50
@default=nil,
@limit=nil,
@name="shipped_at",
@type=:datetime>
注意,Active Record決定了每個(gè)列的類型,在這個(gè)例子里,將shipped_at列作為datetime類型,該列的值被保存在一個(gè)ruby的Time類型的對(duì)象中,我們可以寫些代碼來(lái)驗(yàn)證該列的類型及其內(nèi)容:
order = Order.new
order.shipped_at = "2005-03-04 12:34"
pp order.shipped_at.class
pp order.shipped_at
輸出為:
Time
Fri Mar 04 12:34:00 CST 2005
下面的列表展示了sql和ruby間的數(shù)據(jù)類型對(duì)應(yīng)關(guān)系:
SQLType Ruby Class SQLType Ruby Class
int, integer Fixnum float, double Float
decimal, numeric Float char, varchar, string String
clob, blob, text String datetime, time Time
interval, date Date Boolean 后面詳細(xì)介紹
有一個(gè)潛在的可能是關(guān)于decimal的,在數(shù)據(jù)庫(kù)里,使用decimal的列來(lái)存儲(chǔ)number和fix number型,Active Record將decimal映射成Float類的對(duì)象,盡管這樣可以應(yīng)用于大多數(shù)應(yīng)用,浮點(diǎn)數(shù)是不精確的,在對(duì)這一類型的屬性進(jìn)行一系列操作的時(shí)候,可 能會(huì)發(fā)生舍入的錯(cuò)誤,你也許可以使用integer類型來(lái)作為替代方案,例如,存儲(chǔ)貨幣型的時(shí)候可以將元,角,分,分別存入不同的字段。做為一種選擇,你 可以使用聚合(aggregations),使用多個(gè)分開(kāi)的字段來(lái)構(gòu)建貨幣類型。
(三、Boolean屬性)
一些數(shù)據(jù)庫(kù)支持boolean類型,而另一些則不支持,這使得Active Record要抽象boolean類型變得困難。例如,如果數(shù)據(jù)庫(kù)不支持boolean類型,有的開(kāi)發(fā)者使用char(1)來(lái)替代,而內(nèi)容使用“t”和 “f”來(lái)表示true和false,而另外一些開(kāi)發(fā)者使用integer類型,0是false,1是true。即使數(shù)據(jù)庫(kù)支持boolean類型,在內(nèi)部 也許還是使用0和1來(lái)存儲(chǔ)。
在Ruby里,在條件判斷中,數(shù)字0和字符f都被認(rèn)為是true值,這就意味著如果你直接使用屬性的值,你的代碼會(huì)被認(rèn)為該列的值是true,而不是你認(rèn)為的false,例如:
# 不要這樣使用
user = Users.find_by_name("Dave")
if user.superuser
grant_privileges
end
當(dāng)在查詢條件中使用屬性時(shí),你必須在列名后添加一個(gè)問(wèn)號(hào):
# 這樣是正確的
user = Users.find_by_name("Dave")
if user.superuser?
grant_privileges
end
當(dāng)使用訪問(wèn)操作符來(lái)獲取屬性的值時(shí),當(dāng)值為數(shù)字0,或者字符“0”,“f”,“false”,或“”(空字符串),或nil,或一個(gè)常量false時(shí),都被認(rèn)為是false,否則,就會(huì)被認(rèn)為是true。
如果你在一個(gè)遺留系統(tǒng)上或者非英語(yǔ)系統(tǒng)上開(kāi)發(fā),上面對(duì)true的定義也許會(huì)無(wú)法工作,在這種情況下,你可以override內(nèi)建的謂詞方法的定義,例如,荷蘭語(yǔ)情況下,字段也許包含J或者N,這種情況下,你可以像下面這樣:
class User < ActiveRecord::Base
def superuser?
self.superuser == 'J'
end
# . . .
end
(四、存儲(chǔ)結(jié)構(gòu)化數(shù)據(jù))
有時(shí),能夠在某個(gè)屬性中直接存儲(chǔ)任意的ruby對(duì)象是很方便的,一種辦法就是Active Record支持序列化,將一個(gè)ruby對(duì)象變?yōu)橐粋€(gè)YMAL字符串,并且將這個(gè)字符串存儲(chǔ)到屬性對(duì)應(yīng)的數(shù)據(jù)庫(kù)字段中。在數(shù)據(jù)庫(kù)定義中,這個(gè)字段必須為text類型。
因?yàn)锳ctive Record將數(shù)據(jù)庫(kù)中的Char型和text型映射為ruby的string型,所以如果我們需要告訴Active Record使用序列化功能,例如,我們想知道某個(gè)客戶進(jìn)行的最后的5次消費(fèi),我們創(chuàng)建一個(gè)含有text類型字段的表來(lái)保存信息:
create table purchases (
id int not null auto_increment,
name varchar(100) not null,
last_five text,
primary key (id)
);
在轉(zhuǎn)換這個(gè)表的Active Record類中,我們要使用serialize()聲明,來(lái)告訴Active Record要排列對(duì)象:
class Purchase < ActiveRecord::Base
serialize :last_five
# ...
end
當(dāng)我們創(chuàng)建了一個(gè)新的Purchase對(duì)象,我們可以給last_five列賦任何值,在這個(gè)例子里,我們給last_five列設(shè)置一個(gè)字符串?dāng)?shù)組,
purchase = Purchase.new
purchase.name = "Dave Thomas"
purchase.last_five = [ 'shoes', 'shirt', 'socks', 'ski mask', 'shorts' ]
purchase.save
當(dāng)我們讀入它的時(shí)候,這個(gè)屬性已經(jīng)被設(shè)置為數(shù)組:
purchase = Purchase.find_by_name("Dave Thomas")
pp purchase.last_five
pp purchase.last_five[3]
代碼的輸出為:
["shoes", "shirt", "socks", "ski mask", "shorts"]
"ski mask"
盡管這個(gè)功能是很強(qiáng)大且便利的,但是只有當(dāng)你不打算在ruby以外的項(xiàng)目中使用這些序列化的信息,除非那個(gè)程序也能夠使用YMAL格式。特別 是,這些信息很難被SQL查詢所利用,你也許會(huì)考慮使用聚合(aggregation)來(lái)替代,在后面我們會(huì)介紹這種辦法來(lái)達(dá)到相同的效果。
(五主鍵和ID)
也許你已經(jīng)注意到了,在我們前面的代碼中,數(shù)據(jù)庫(kù)定義里都使用了一個(gè)integer型的字段id作為主鍵,這是Active Record的一個(gè)約定。
或許你要問(wèn),為什么不用訂單編號(hào)或者某個(gè)有意義的列來(lái)作為主鍵呢?使用id作為主鍵有一個(gè)很重要的原因,就是如果使用具有內(nèi)在格式的主鍵的 話,隨著時(shí)間推移,有可能其中的規(guī)則也會(huì)變化。例如,使用ISBN號(hào)碼來(lái)給book表做主鍵,畢竟ISBN號(hào)碼是唯一的,但是,有可能當(dāng)一本書寫完后,美 國(guó)的出版業(yè)已經(jīng)發(fā)展了并且在所有的ISBN號(hào)碼后又附加了一位數(shù)字。
如果我們使用了ISBN作為book表的主鍵,我們就要更新所有book表的記錄來(lái)反映這個(gè)變化,而且還有一個(gè)問(wèn)題,還有其他表引用了book表的主鍵,我們就要更新所有的引用,這還牽涉到要?jiǎng)h除外鍵,所有的這一切都是非常痛苦的。
如果使用有意義的值作為主鍵,那么我們將收到外界業(yè)務(wù)規(guī)則的影響,如果使用id,我們可以自己完全控制,而且如果象ISBN等一些東西改變的話,將不會(huì)影響到數(shù)據(jù)庫(kù)結(jié)構(gòu)。
如果你從一個(gè)新的數(shù)據(jù)庫(kù)結(jié)構(gòu)開(kāi)始,可能會(huì)遵循約定,給所有的表都使用id作為主鍵,但是,當(dāng)你使用的是一個(gè)既存的數(shù)據(jù)庫(kù)開(kāi)始的時(shí)候,Active Record提供了簡(jiǎn)單的方法來(lái)讓你重新給表指定主鍵,例如:
class BadBook < ActiveRecord::Base
set_primary_key "isbn"
end
通常,Active Record會(huì)注意給新創(chuàng)建的記錄生成主鍵值-使用自增長(zhǎng)的整數(shù)。不管怎樣,當(dāng)你override表的主鍵名字的時(shí)候,你就需要自己負(fù)責(zé)給新建記錄一個(gè)唯 一的主鍵值。也許有些讓人驚訝,你還是設(shè)置一個(gè)id的屬性來(lái)完成這件事,因?yàn)锳ctive Record所關(guān)心的是,主鍵的設(shè)置永遠(yuǎn)都使用名為id屬性,set_primary_key的聲明只是設(shè)置了使用的列名,下面的例子,我們使用ISBN 作為主鍵。
book = BadBook.new
book.id = "0-12345-6789"
book.title = "My Great American Novel"
book.save
# ...
book = BadBook.find("0-12345-6789")
puts book.title # => "My Great American Novel"
p book.attributes #=> {"isbn" =>"0-12345-6789",
"title"=>"My Great American Novel"}
也就是說(shuō),在設(shè)置主鍵的時(shí)候,使用id屬性,其他時(shí)候,使用真實(shí)的列名。
(六、連接數(shù)據(jù)庫(kù))
Active Record抽象了數(shù)據(jù)庫(kù)連接的概念,幫助應(yīng)用程序來(lái)處理底層的數(shù)據(jù)庫(kù)鏈接的細(xì)節(jié),作為替代,Active Record使用通用的調(diào)用,將細(xì)節(jié)委托給一組數(shù)據(jù)庫(kù)適配器。
可以使用establish_connection( )方法來(lái)制定連接,下面的例子創(chuàng)建了一個(gè)mysql數(shù)據(jù)庫(kù)連接,數(shù)據(jù)庫(kù)的名字是railsdb,服務(wù)器的Host名為dbserver.com,用戶名為railsuser,密碼為railspw。
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "dbserver.com",
:database => "railsdb",
:username => "railsuser",
:password => "railspw"
)
Active Record支持DB2,MySql,Oracle,Postgres,SqlServer,以及SqlLite,每一種數(shù)據(jù)庫(kù)適配器在鏈接的參數(shù)上都有一些細(xì)小的差別,下表列出了常用的參數(shù):
注意Oracle適配器的名字為oci。
數(shù)據(jù)庫(kù)連接和Model類是關(guān)聯(lián)的,每個(gè)類都從父類那里繼承了鏈接,ActiveRecord::Base作為所有的Active Record類的父類,設(shè)置這里的數(shù)據(jù)庫(kù)連接就給所有的活動(dòng)記錄類設(shè)置了鏈接,當(dāng)然,如果需要的話,你也可以復(fù)寫(override)鏈接配置。
下面的例子里,我們的大多數(shù)表都在MySql數(shù)據(jù)庫(kù)中,庫(kù)名為online,由于一些歷史原因,customers表在名為backend的數(shù)據(jù)庫(kù)中,
ActiveRecord::Base.establish_connection(
:adapter => "mysql",
:host => "dbserver.com",
:database => "online",
:username => "groucho",
:password => "swordfish")
class LineItem < ActiveRecord::Base
# ...
end
class Order < ActiveRecord::Base
# ...
end
class Product < ActiveRecord::Base
# ...
end
class Customer < ActiveRecord::Base
# ...
end
Customer.establish_connection(
:adapter => "mysql",
:host => "dbserver.com",
:database => "backend",
:username => "chicho",
:password => "piano")
在我們前面所寫的depot程序中,我們沒(méi)有使用establish_connection方法,而是在 config/database.yaml文件中指定了數(shù)據(jù)庫(kù)連接的參數(shù)信息,對(duì)于大多數(shù)rails程序來(lái)說(shuō),這是首選的方式,不僅因?yàn)閷⑴渲眯畔⒑痛a 分離,而且在測(cè)試和部署時(shí)也能帶來(lái)方便,上面的表格里列出的參數(shù)都可以應(yīng)用在YAML文件中,這一點(diǎn)我們?cè)谇懊娴呐渲梦募还?jié)已經(jīng)有介紹。
最后,如果你通過(guò)一個(gè)標(biāo)記訪問(wèn)establish_connection(),Rails會(huì)在database.yaml文件中查找名字對(duì)應(yīng)的配置節(jié),來(lái)獲取鏈接的參數(shù),這樣就可以將所有的數(shù)據(jù)庫(kù)連接配置從代碼中分離出來(lái)。
(七、創(chuàng)建記錄)
Active Record使得實(shí)現(xiàn)CRUD的數(shù)據(jù)庫(kù)基本操作變得簡(jiǎn)單,在下面的幾節(jié)里我們使用Mysql數(shù)據(jù)庫(kù)中的orders表來(lái)進(jìn)行CRUD的操作,這次先看創(chuàng)建(Create)。
我們假想有一個(gè)Model,名為Order:
class Order < ActiveRecord::Base
end
在面向?qū)ο蟮哪P屠?#xff0c;表對(duì)應(yīng)類,表中的行對(duì)應(yīng)類的對(duì)象。我們可以通過(guò)創(chuàng)建一個(gè)類的對(duì)象來(lái)創(chuàng)建一條記錄。對(duì)orders表,我們可以使用 Order.New()方法來(lái)創(chuàng)建一個(gè)Order的對(duì)象,也就對(duì)應(yīng)了orders表的一條記錄,然后我們給該對(duì)象的每個(gè)屬性賦值,最后,我們調(diào)用對(duì)象的 save()方法將數(shù)據(jù)寫回?cái)?shù)據(jù)庫(kù),如果不調(diào)用save()的話,那么這個(gè)對(duì)象僅僅在內(nèi)存中存在,而不是數(shù)據(jù)庫(kù)。
an_order = Order.new
an_order.name = "Dave Thomas"
an_order.email = "dave@pragprog.com"
an_order.address = "
123 Main St
"
an_order.pay_type = "check"
an_order.save
Active Record的構(gòu)造器有一個(gè)可選的塊(block),這個(gè)塊可以將創(chuàng)建的Order對(duì)象做為參數(shù),這樣就不需要再創(chuàng)建一個(gè)Order類的對(duì)象的變量了:
Order.new do |o|
o.name = "Dave Thomas"
# . . .
o.save
end
Active Record也可以接收一組哈希(Hash)參數(shù)的值來(lái)作為可選參數(shù),由屬性的名字和相對(duì)應(yīng)的值組成:
an_order = Order.new(
:name => "Dave Thomas",
:email => "dave@pragprog.com",
:address => "
123 Main St
",
:pay_type => "check")
an_order.save
注意到現(xiàn)在為止,我們還沒(méi)有任何關(guān)于id的設(shè)置,這是因?yàn)槲覀兪褂肁ctive Record的默認(rèn)約定,將orders表的主鍵為一個(gè)integer類型的列。在存入數(shù)據(jù)庫(kù)的時(shí)候,Active Record自動(dòng)給新建的對(duì)象生成一個(gè)唯一的值,并且設(shè)置到id屬性上,我們可以在save()之后查詢id的值:
an_order = Order.new
an_order.name = "Dave Thomas"
# ...
an_order.save
puts "The ID of this order is #{an_order.id}"
new()構(gòu)造函數(shù)在內(nèi)存中創(chuàng)建了一個(gè)Order類的對(duì)象,你需要在某個(gè)時(shí)候調(diào)用save()方法來(lái)保存到數(shù)據(jù)庫(kù)。Active Record還有一個(gè)約定的方法create(),下面的例子說(shuō)明這個(gè)方法的用法,同時(shí)展示了創(chuàng)建對(duì)象和存儲(chǔ)到數(shù)據(jù)庫(kù):
an_order = Order.create(
:name => "Dave Thomas",
:email => "dave@pragprog.com",
:address => "
123 Main St
",
:pay_type => "check")
也可以給create()方法傳遞哈希(hash)的數(shù)組,在數(shù)據(jù)庫(kù)中創(chuàng)建多條記錄,并且返回對(duì)應(yīng)的對(duì)象數(shù)組。
orders = Order.create(
[ { :name => "Dave Thomas",
:email => "dave@pragprog.com",
:address => "
123 Main St
",
:pay_type => "check"
},
{ :name => "Andy Hunt",
:email => "andy@pragprog.com",
:address => "
456 Gentle Drive
",
:pay_type => "po"
} ] )
方法new()和create()的真正目的就是讓我們可以通過(guò)一組參數(shù)就能夠創(chuàng)建Model對(duì)象:
order = Order.create(params)
(八、讀取記錄)
讀取記錄包括指定那些特定的數(shù)據(jù)是你感興趣的,你給Active Record指定標(biāo)準(zhǔn),Active Record再返回給你一些對(duì)象,其中包含了符合條件的記錄的數(shù)據(jù)。
在一個(gè)表中檢索數(shù)據(jù)的最簡(jiǎn)單的辦法就是指定主鍵,任何一個(gè)Model都支持find()方法,該方法支持一個(gè)或多個(gè)主鍵值,如果只指定了一個(gè) 主鍵,將會(huì)返回對(duì)應(yīng)的對(duì)象,如果指定了多個(gè)主鍵給find方法,該方法一組相應(yīng)的對(duì)象。注意,當(dāng)沒(méi)有任何符合條件的數(shù)據(jù)的時(shí)候,將會(huì)拋出一個(gè) RecordNotFound異常,所以如果find方法沒(méi)有拋出這個(gè)異常的話,返回的數(shù)組中的對(duì)象個(gè)數(shù)就等于給find方法指定的id數(shù)目。
an_order = Order.find(27) # find the order with id == 27
# Get a list of order ids from a form, then
# sum the total value
order_list = params[:order_ids]
orders = Order.find(order_list)
count = orders.size
通常,在查詢的時(shí)候都要用到除過(guò)id以外的值,Active Record提供了一組設(shè)置來(lái)執(zhí)行這些查詢,我們會(huì)介紹find使用方法,從基本的查詢,再到高階些的動(dòng)態(tài)查詢。
到現(xiàn)在我們只是了解了find方法的最基本的內(nèi)容,通過(guò)指定id來(lái)獲取一個(gè)或一組對(duì)象。另外,我們還可以使用一些標(biāo)記比如:first,:all來(lái)作為find方法的參數(shù)。
:first將返回符合條件的第一條記錄,:all將返回所有符合條件的記錄,下一篇我們來(lái)看看Active Record是如何處理sql的。
注:find在3.1版中建議不使用,改用where。by--biyeah
(九、行數(shù)和再加載數(shù)據(jù))
Active Record提供了兩個(gè)方法來(lái)獲取符合條件的記錄的條數(shù):count()和count_by_sql()。例如:
c1 = Order.count
c2 = Order.count(["name = ?", "Dave Thomas"])
c3 = LineItem.count_by_sql("select count(*) " +
" from line_items, orders " +
" where line_items.order_id = orders.id " +
" and orders.name = 'Dave Thomas' ")
puts "Dave has #{c3} line items in #{c2} orders (#{c1} orders in all)"
在一個(gè)程序中,數(shù)據(jù)庫(kù)有可能被多個(gè)進(jìn)程或多個(gè)程序訪問(wèn),隨時(shí)都有可能獲取最新的Model對(duì)象,這些對(duì)象有可能剛剛被編輯過(guò)。
從某種程度上講,這主要應(yīng)用在事務(wù)中,不管怎么說(shuō),當(dāng)你需要手動(dòng)刷新Model對(duì)象時(shí),Active Record可以幫助你,只需調(diào)用reload()方法,Model對(duì)象屬性的值就會(huì)被數(shù)據(jù)庫(kù)中的值更新。
stock = Market.find_by_ticker("RUBY")
loop do
puts "Price = #{stock.price}"
sleep 60
stock.reload
end
(十、更新記錄)
前面了解了檢索的方法,這次來(lái)看看Active Record怎樣更新數(shù)據(jù)庫(kù)中的記錄。
如果你有一個(gè)Active Record對(duì)象(或許對(duì)應(yīng)于order表),你可以通過(guò)調(diào)用save方法將它寫道數(shù)據(jù)庫(kù)中去,如果這個(gè)對(duì)象是先前從數(shù)據(jù)庫(kù)中讀取出來(lái)的,save方法將會(huì)更新既有的記錄,否則將會(huì)新建一條記錄。
如果一條既有記錄被更新,Active Record將會(huì)用它的主鍵和來(lái)匹配內(nèi)存中的對(duì)象,Active Record對(duì)象中的屬性被更新到對(duì)應(yīng)的列,即使一個(gè)列中的值沒(méi)有變化也會(huì)被更新,在下面的例子中,id為123的訂單所有的內(nèi)容都會(huì)被更新:
order = Order.find(123)
order.name = "Fred"
order.save
不管怎樣,在下面的例子里,Active Record對(duì)象只包含id,name,paytype,當(dāng)對(duì)象被保存的時(shí)候僅僅只有這些字段被更新,注意如果你想要把對(duì)象保存到數(shù)據(jù)庫(kù),那么在使用find_by_sql方法時(shí),一定要包含id字段。
orders = Order.find_by_sql("select id, name, pay_type from orders where id=123")
first = orders[0]
first.name = "Wilma"
first.save
另外,Active Record還提供了update_attribute()方法,該方法可以將Model對(duì)象的某個(gè)屬性保存到數(shù)據(jù)庫(kù)。
order = Order.find(123)
order.update_attribute(:name, "Barney")
order = Order.find(321)
order.update_attributes(:name => "Barney",
:email => "barney@bedrock.com")
我們可以把讀取和更新結(jié)合在一起,使用update()方法或update_all(),update()方法使用一個(gè)id和一組屬性,如果在數(shù)據(jù)庫(kù)中對(duì)應(yīng)的記錄,就更新指定的屬性,然后返回model對(duì)象。
order = Order.update(12, :name => "Barney", :email => "barney@bedrock.com")
也可以傳遞一組id或者屬性和值的hash給update()方法,這樣會(huì)更新所有匹配的記錄,并且返回一組model對(duì)象。
最后,update_all()方法允許你指定給update語(yǔ)句指定Where條件,下面的例子給所有標(biāo)題中含有java的商品漲價(jià)10%:
result = Product.update_all("price = 1.1*price", "title like '%Java%'")
這里的返回值依賴于具體的數(shù)據(jù)庫(kù)適配器,很多數(shù)據(jù)庫(kù)都返回被更新的記錄數(shù)目。
下面我們看看save()和save!()這兩個(gè)方法。
簡(jiǎn)單的save()方法在Model對(duì)象存在并且可以的保存的情況下返回true:
if order.save
# all OK
else
# validation failed
end
這樣會(huì)導(dǎo)致你在所有調(diào)用save方法的地方都要加上檢查,但是Active Record假定save方法是在Controler的Action的上下文中的,并且視圖里的代碼不進(jìn)行這些檢查。(這部分書上看不明白,不能確定)。
不管怎樣,如果你需要在上下文環(huán)境中保存Model對(duì)象,并且想確定是否所有的錯(cuò)誤都被處理了,你可以使用save!()方法,如果Model對(duì)象不能保存,那么這個(gè)方法會(huì)拋出一個(gè)RecordInvailid異常:
begin
order.save!
rescue RecordInvalid => error
# validation failed
end
轉(zhuǎn)載于:https://www.cnblogs.com/deepbreath/p/4153317.html
總結(jié)
以上是生活随笔為你收集整理的ActiveRecord教程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: MySQL数据库SQL层级优化
- 下一篇: DB2临时表空间的作用