一、心得體會
1、今天完成了什么?
- Rails guide 4 170頁 5個小時
- 重看了鎬頭書看了第一部分 1個小時
2、今天收獲了什么?
- Active Record 數(shù)據(jù)驗(yàn)證、嚴(yán)格驗(yàn)證。。。
- 回調(diào) before_create、before_save。。。
- 關(guān)聯(lián)
- belongs_to 一對一
- has_one 一對一
- has_many 一對多
- has_and_belongs_to_many 多對多
- has_many :through 多對多
- has_one :through 一對一
3、今天狀態(tài)如何?
- 今天狀態(tài)爆表
4、今天犯了哪些錯誤?
- 今天吃完飯又?jǐn)]了兩把王者,回來之后,看了幾篇文章
5、明天還有哪些工作需要完成?
- 明天要看鎬頭書的第二部分、第三部分
二、讀書筆記
第三章 Active Record數(shù)據(jù)驗(yàn)證
本文介紹了如何使用Active Record提供的數(shù)據(jù)驗(yàn)證功能在數(shù)據(jù)存入數(shù)據(jù)庫之前驗(yàn)證對象的狀態(tài)。
- 如何使用AR內(nèi)建的數(shù)據(jù)驗(yàn)證幫助方法
- 如何編寫自定義的數(shù)據(jù)驗(yàn)證方法
- 如何處理驗(yàn)證時產(chǎn)生的錯誤消息
2、什么時候做數(shù)據(jù)驗(yàn)證?
Active Record使用實(shí)例方法new_record?判斷對象是否已經(jīng)存入數(shù)據(jù)庫。
- create
- create!
- save
- save!
- update
- update!
3、跳過驗(yàn)證
下面方法會跳過驗(yàn)證,不過驗(yàn)證是否通過都會把對象存入數(shù)據(jù)庫,使用時要特別留意。
- decrement!
- decrement_counter
- increment!
- increment_counter
- toggle!
- touch
- update_all
- update_attribute
- update_column
- update_columns
- update_counters
注意,使用save時如果傳入validate: false,也會跳過驗(yàn)證,使用時要特別留意。
- save(validate: false)
valid?和invalid?
Rails使用valid?方法檢查對象是否合法。valid?方法會觸發(fā)數(shù)據(jù)驗(yàn)證,如果對象上沒有錯誤,就返回true,否則返回false,前面我們已經(jīng)用過了:
class Person < ActiveRecord::Base
validates :name, presence: true
end
AR驗(yàn)證結(jié)束后,所有發(fā)現(xiàn)的錯誤都可以通過實(shí)例方法errors.message獲取,該方法返回一個錯誤集合。如果數(shù)據(jù)驗(yàn)證后,這個集合為空,則說明對象是合法的。
注意,使用new方法初始化對象時,即使不合法也不會報錯,因?yàn)檫@時還沒與做數(shù)據(jù)驗(yàn)證。
errors[]
要檢查對象的某個屬性是否合法,可以使用errors[:attribute]中包含:attribute的所有錯誤。如果某個屬性沒有錯誤,就會返回空數(shù)組。
這個方法只在數(shù)據(jù)驗(yàn)證之后才能使用,因?yàn)樗皇怯脕硎占e誤的,并不會觸發(fā)驗(yàn)證。而且,和前面介紹的ActiveRecord::Base#invalid?方法不一樣,因?yàn)閑rros[:attribute]不會驗(yàn)證整個對象,值檢查對象的某個屬性是否出錯。
數(shù)據(jù)驗(yàn)證幫助方法
AR預(yù)先定義了很多數(shù)據(jù)驗(yàn)證幫助方法,可以直接在模型定義中使用,這些幫助方法提供了常用的驗(yàn)證規(guī)則,每次驗(yàn)證失敗后,都會向?qū)ο蟮膃rrors集合添加一個消息,這些消息和所驗(yàn)證的屬性相關(guān)聯(lián)。
每個幫助方法都可以接受任意數(shù)量的屬性名,所以一行代碼就能在多個屬性上做同一種驗(yàn)證。
所有的幫助方法都可指定:on和:message選項,指定何時做驗(yàn)證,以及驗(yàn)證失敗后向errors集合添加什么消息,:on選項的可選值是:create和:update。
acceptance
這個方法檢查表單提交時,用戶界面中的復(fù)選框是否被選中,這個功能一般用來要求用戶接受程序的服務(wù)條款,閱讀一些文字,等等。
class Person < ActiveRecord::Base
validates :name, acceptance: true
end
這個幫助方法的默認(rèn)錯誤消息是“must be accepted”。
這個方法可以指定:accept選項,決定可接受什么值,默認(rèn)是“1”,很容易修改。
class Person < ActiveRecord::Base
validates :name, acceptance: { accept: "yes"}
end
validates_associated
如果模型和其他模型有關(guān)聯(lián),也要驗(yàn)證關(guān)聯(lián)的模型對象,可以使用這個方法,保存對象是,會在相關(guān)聯(lián)的每個對象上調(diào)用valid?方法。
class Library < ActiveRecord::Base
has_many :books
validates_associated :books
end
這個幫助方法可用于所有關(guān)聯(lián)類型。
不要在關(guān)聯(lián)的兩端都使用validates_associated,這樣會生成一個循環(huán)。
validates_associated的默認(rèn)錯誤消息是“is invalid”。注意,相關(guān)聯(lián)的每個對象都有各自的errors集合,錯誤消息不會都集中在調(diào)用該方法的模型對象上。
confirmation
如果要檢查兩個文本字段的值是否相同,可以使用這個幫助方法,例如,確認(rèn)Email地址或密碼,這個幫助方法回傳件一個虛擬屬性。
class Library < ActiveRecord::Base
validates :email, confirmation: true
end
視圖中這個寫
<%= text_field :Library, :email_confirmation %>
只有email_confirmation的值不是nil時才會做這個驗(yàn)證。所以要確認(rèn)屬性加上存在性驗(yàn)證。
class Library < ActiveRecord::Base
validates :email, confirmation: true
validates :email_confirmation, presence: true
end
這個幫助方法的默認(rèn)錯誤消息是“doesn't match confirmation”。
exclusion
這個幫助方法檢查屬性的值是否不在指定的集合中。集合可以是任何一種可枚舉的對象。
class Account < ActiveRecord::Base
validates :subdomain, exclusion: { in: %w(www us ca jp), message: "%{value} is reserved."}
end
exclusion方法指定:in選項,設(shè)置哪些值不能作為屬性的值,:in選項有個別名:with,作用相同,上面的例子設(shè)置了:message選項,演示如何獲取屬性的值。
默認(rèn)的錯誤消息是“is reserved”
format
這個幫助方法檢查屬性的值是否匹配:with選項指定的正則表達(dá)式。
class Account < ActiveRecord::Base
validate :legacy_code, format: { with: /\A[a-zA-Z]+\z/, message: "only allows letters" }
end
默認(rèn)的錯誤消息是“is invalid”。
inclusion
這個幫助方法檢查屬性的值是否在指定的集合中。集合可以是任何一種可枚舉的對象。
class Coffee < ActiveRecord::Base
validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" }
end
inclusion方法要指定:in選項,設(shè)置可接受哪些值。:in選項有個別名:with,作用相同。上面的例子設(shè)置了:message選項,演示如何獲取屬性的值。
該方法的默認(rèn)錯誤消息是“is not included in the list”。
length
這個幫助方法驗(yàn)證屬性值的長度,有多個選項,可以使用不同的方法指定長度限制:
class Person < ActiveRecord::Base
validates :name, length: {minimum: 2}
validates :bio, lenght: {maximum: 500}
validates :password, lenght: {in: 6..20}
validates :registration_number, length: {is: 6}
end
可用的長度限制選項有:
- :minimum: 屬性的值不能比指定的長度短;
- :maximum: 屬性的值不能比指定的長度長;
- :in (或:within):屬性值的長度在指定值之間,該選項的值必須是一個范圍。
- :is:屬性值的長度必須等于指定值;
默認(rèn)的錯誤消息根據(jù)長度驗(yàn)證類型而有所不同,還是可以:message定制。定制消息時,可以使用:wrong_length、:too_long和:too_short選項,%{count}表示長度限制的值。
class Person < ActiveRecord::Base
validates :bio, length: {maximum: 1000, too_long: "%{count} characters is the maximum allowed"}
end
這個幫助方法默認(rèn)統(tǒng)計字符數(shù),但可以使用:tokenizer選項設(shè)置其他的統(tǒng)計方式:
numericality
這個幫助方法檢查屬性的值是否包含數(shù)字,默認(rèn)情況下,匹配的值是可選的正負(fù)符號后加整數(shù)或浮點(diǎn)數(shù),如果只接受整數(shù),可以把:only_integer選項設(shè)為true。
/\A[+-]?\d+\Z/
否則,會嘗試使用Float把值轉(zhuǎn)換成數(shù)字。
presence
這個幫助方法堅持指定的屬性是否為非空值,調(diào)用blank?方法檢查是否為nil或空字符串。
absence
這個方法驗(yàn)證指定的屬性是否為空,使用present?方法檢測值是否為nil。
uniqueness
這個幫助方法會在保存對象之前驗(yàn)證屬性值是否唯一。
validates_with
這個幫助方法把記錄交給其他的類做驗(yàn)證。
validates_each
這個幫助方法會把屬性值傳入代碼庫做驗(yàn)證,沒有預(yù)先定義驗(yàn)證的方式,你應(yīng)該在代碼庫中定義驗(yàn)證方式。
常用的驗(yàn)證選項
:allow_nil
指定:allow_nil選項后,如果驗(yàn)證的值為nil就會跳過驗(yàn)證。
:allow_blank
:allow_blank選項和:allow_nil選項類似,如果驗(yàn)證的值為空,就會跳過驗(yàn)證。
:message
如果驗(yàn)證失敗,會把:message選項指定的字符串添加到errors集合中。
:on
指定什么時候做驗(yàn)證。
嚴(yán)格驗(yàn)證
數(shù)據(jù)驗(yàn)證還可以使用嚴(yán)格驗(yàn)證模式,失敗后會拋出ActiveModel::StrictValidationFailed異常。
條件驗(yàn)證
有時只有滿足特定條件時做驗(yàn)證才說的通
指定Symbol
:if和:unless選項的值為Symbol時,表示要在驗(yàn)證之前執(zhí)行對應(yīng)的方法。
指定字符串
:if和:unless選項的值還可以是字符串
指定Proc
:if和:unless選項的值還可以是Proc
條件組合
有時同一個條件會用在多個驗(yàn)證上,這時可以使用with_options方法:
聯(lián)合條件
如果是否做某個驗(yàn)證要滿足多個條件時,可以使用數(shù)組,而且,都一個驗(yàn)證可以同時指定:if和:unless選項。
自定義驗(yàn)證方式
自定義驗(yàn)證使用的類
自定義驗(yàn)證使用的方法
還可以自定義方法驗(yàn)證模型的狀態(tài),如果驗(yàn)證失敗,向errors集合添加錯誤信息,然后還要使用類方法validate注冊這些方法。
處理驗(yàn)證錯誤
除了前面介紹的valid?和invalid?方法之外,Rails還提供了很多方法用來處理errors集合,以及查詢對象的合法性。
errors[:base]
在視圖中顯示驗(yàn)證錯誤
Active Record 回調(diào)
- AR對象的生命周期
- 如何編寫回調(diào)方法響應(yīng)對象聲明周期內(nèi)發(fā)生的事件
- 如何把常用的回調(diào)封裝到特殊的類中;
對象的生命周期
在Rails程序運(yùn)行過程中,對象可以被創(chuàng)建、更新和銷毀。Active Record為對象的生命周期提供了很多鉤子,讓你控制程序及其數(shù)據(jù)。
回調(diào)可以在對象的狀態(tài)改變之前或之后觸發(fā)指定的邏輯操作。
回調(diào)簡介
注冊回調(diào)
這種類方法還可以接受一個代碼塊,如果操作可以使用一行代碼表述,可以考慮使用代碼塊形式。
class Person < ActiveRecord::Base
validates :login, :email, presence: true
before_create do
self.name = login.capitalize if name.blank?
end
end
注冊回調(diào)時可以指定只在對象生命周期的特定事件發(fā)生時執(zhí)行:
一般情況下,都把回調(diào)方法定義為受保護(hù)的方法或私有方法,如果定義成公共方法,回調(diào)就可以在模型外部調(diào)用。
可用的回調(diào)
創(chuàng)建對象
- before_validation
- after_validation
- before_save
- around_save
- before_create
- around_create
- after_create
- after_save
更新對象
- before_validation
- after_validation
- before_save
- around_save
after_initialize和after_find
after_initialize回調(diào)在Active Record對象初始化時執(zhí)行,包括直接使用new方法初始化和從數(shù)據(jù)庫中讀取記錄,after_initialize回調(diào)不用直接重定義Active Record的initialize方法。
after_find回調(diào)在數(shù)據(jù)庫中讀取記錄時執(zhí)行,如果同時注冊了after_find和after_initialize
after_touch
after_touch回調(diào)在觸碰Active Record對象時執(zhí)行。
可以結(jié)合belongs_to一起使用
執(zhí)行回調(diào)
下面的方法會觸發(fā)執(zhí)行回調(diào)
- create
- create!
跳過回調(diào)
和數(shù)據(jù)驗(yàn)證一樣,回調(diào)也可跳過,使用下列方法即可:
- decrement
- decrement_counter
- delete
- delete_all
- increment
- increment_all
- toggle
- touch
- update_column
- update_columns
- update_all
終止執(zhí)行
在模型中注冊回調(diào)后,回調(diào)會加入一個執(zhí)行隊列。
關(guān)聯(lián)回調(diào)
回調(diào)能在模型關(guān)聯(lián)中使用,甚至可由關(guān)聯(lián)定義,假如一個用戶發(fā)布了多篇文章,如果用戶刪除了,他發(fā)布的文章也應(yīng)該刪除,下面我們在post模型中注冊一個after_destroy回調(diào),應(yīng)用在User模型上:
條件回調(diào)
和數(shù)據(jù)驗(yàn)證類似,也可以滿足指定條件時再調(diào)用回調(diào)方法。條件通過:if和:unless選項指定,選項的值可以是Symbol、字符串、Proc或數(shù)組。
使用Symbol
:if和:unless選項的值為Symbol時,表示要在調(diào)用回調(diào)之前執(zhí)行對應(yīng)的判斷方法
使用字符串
使用Proc
回調(diào)的多重條件
回調(diào)類
事物回調(diào)
Active Record 關(guān)聯(lián)
- 如何聲明Active Record模型間的關(guān)聯(lián)
- 怎么理解不同的Active Record關(guān)聯(lián)類型
- 如何使用關(guān)聯(lián)添加的方法
為什么要使用關(guān)聯(lián)?
讓代碼更簡潔
怎么使用關(guān)聯(lián)?
- belongs_to 一對一關(guān)系
- has_one 一對一關(guān)系
- has_many 一對多關(guān)系
- has_many :through 多對多關(guān)系
- has_one :through 關(guān)聯(lián)建立兩個模型之間一對一關(guān)系,這種關(guān)聯(lián)表示一個模型通過第三個模型擁有另一個模型的實(shí)例,例如,每個供應(yīng)商只有一個賬戶,而且每個賬戶都有一個歷史賬戶,那么定義模型:
- has_and_belongs_to_many
使用belongs_to還是has_one
如果想建立兩個模型之間的一對一關(guān)系,可以在一個模型中聲明belongs_to,然后再另一個模型中聲明has_one。
使用has_many :through 還是has_and_belongs_to_many
如果需要做數(shù)據(jù)驗(yàn)證、回調(diào),或者連接模型上要用到其他屬性,此時就要使用has_many :through
第二種方法是使用has_many :through,但無法直接建立關(guān)聯(lián),要通過第三個模型
多態(tài)關(guān)聯(lián)
關(guān)聯(lián)還有一種高級用法,“多態(tài)關(guān)聯(lián)”。在多態(tài)關(guān)聯(lián)中,在同一個關(guān)聯(lián)中,模型可以屬于其他多個模型。例如,圖片模型可以屬于雇員模型或者產(chǎn)品模型,模型的定義如下:
自連接
設(shè)計數(shù)據(jù)模型時會發(fā)現(xiàn),有時模型要和自己建立關(guān)聯(lián),例如,在一個數(shù)據(jù)表中保存所有雇員的信息,但要建立經(jīng)理和下屬之間的關(guān)系,這種情況可以使用自連接關(guān)聯(lián)解決:
小技巧和注意事項
- 緩存控制
- 避免命名沖突
- 更新模式
- 控制關(guān)聯(lián)的作用域
- Bi-directional associations
1、雙向關(guān)聯(lián)
默認(rèn)情況下,AR并不知道這個關(guān)聯(lián)中兩個模型之間的關(guān)系,可能導(dǎo)致同一對象的兩個副本不同步。
為了解決這個問題,引入了:inverse_of選項,可以告知Rails兩者之間的關(guān)系。
2、關(guān)聯(lián)詳解
belongs_to 關(guān)聯(lián)詳解
belongs_to關(guān)聯(lián)創(chuàng)建一個模型與另一個模型之間的一對一關(guān)系,用數(shù)據(jù)庫的行話來說,就是這個類包含了外鍵。如果外鍵在另一個類中,就應(yīng)該使用has_one關(guān)聯(lián)。
belongs_to 關(guān)聯(lián)添加的方法
如果關(guān)聯(lián)的對象存在,associate方法會返回關(guān)聯(lián)對象。如果找不到關(guān)聯(lián)對象,則返回nil。
belongs_to方法的選項
Rails的默認(rèn)設(shè)置足夠智能,能滿足常見需求,但有時還是需要定制belongs_to關(guān)聯(lián)的行文,定制的方法很簡單,聲明關(guān)聯(lián)時傳入選項或者使用代碼塊即可。
belongs_to 關(guān)聯(lián)支持以下選項:
- :autosave
- :class_name
- :counter_cache
belongs_to的作用域
檢查關(guān)聯(lián)的對象是否存在
什么時候保存對象
has_one關(guān)聯(lián)詳解
has_one關(guān)聯(lián)添加的方法
- association(force_reload = false)
- association =(associate)
- build_association
- create_association(attributes = {})
has_one 方法的選項
has_one 的作用域
有時需要定制has_one關(guān)聯(lián)使用的查詢方式,定制的查詢可在作用域代碼塊中指定。
檢查關(guān)聯(lián)對象是否存在
什么時候保存對象?
has_many 關(guān)聯(lián)詳解
has_many 關(guān)聯(lián)添加的方法
聲明has_many后,自動獲得16個關(guān)聯(lián)相關(guān)的方法:
- collection(force_reload = false)
- collection<<(object, ...)
- collection.delete(object, ...)
has_many 方法的選項
作用域
has_and_belongs_to_many 關(guān)聯(lián)詳解
關(guān)聯(lián)回調(diào)
關(guān)聯(lián)回調(diào)和普通回調(diào)都差不多,只不過集合生命周期中的事件觸發(fā)的。關(guān)聯(lián)回調(diào)有四種:
- before_add
- after_add
- before_remove
- after_remove
關(guān)聯(lián)擴(kuò)展
Rails基于關(guān)聯(lián)代理對象自動創(chuàng)建的功能是死的,但是可以通過匿名模塊、新的查詢方法、創(chuàng)建對象的方法等進(jìn)行擴(kuò)展。