一、心得體會(huì)
1蒸走、今天完成了什么?
- Rails guide 4 170頁 5個(gè)小時(shí)
- 重看了鎬頭書看了第一部分 1個(gè)小時(shí)
2玖瘸、今天收獲了什么?
- Active Record 數(shù)據(jù)驗(yàn)證胁后、嚴(yán)格驗(yàn)證。嗦枢。攀芯。
- 回調(diào) before_create、before_save文虏。侣诺。。
- 關(guān)聯(lián)
- belongs_to 一對(duì)一
- has_one 一對(duì)一
- has_many 一對(duì)多
- has_and_belongs_to_many 多對(duì)多
- has_many :through 多對(duì)多
- has_one :through 一對(duì)一
3氧秘、今天狀態(tài)如何年鸳?
- 今天狀態(tài)爆表
4、今天犯了哪些錯(cuò)誤丸相?
- 今天吃完飯又?jǐn)]了兩把王者搔确,回來之后,看了幾篇文章
5灭忠、明天還有哪些工作需要完成膳算?
- 明天要看鎬頭書的第二部分、第三部分
二弛作、讀書筆記
第三章 Active Record數(shù)據(jù)驗(yàn)證
本文介紹了如何使用Active Record提供的數(shù)據(jù)驗(yàn)證功能在數(shù)據(jù)存入數(shù)據(jù)庫之前驗(yàn)證對(duì)象的狀態(tài)涕蜂。
- 如何使用AR內(nèi)建的數(shù)據(jù)驗(yàn)證幫助方法
- 如何編寫自定義的數(shù)據(jù)驗(yàn)證方法
- 如何處理驗(yàn)證時(shí)產(chǎn)生的錯(cuò)誤消息
2、什么時(shí)候做數(shù)據(jù)驗(yàn)證映琳?
Active Record使用實(shí)例方法new_record?判斷對(duì)象是否已經(jīng)存入數(shù)據(jù)庫机隙。
- create
- create!
- save
- save!
- update
- update!
3蜘拉、跳過驗(yàn)證
下面方法會(huì)跳過驗(yàn)證,不過驗(yàn)證是否通過都會(huì)把對(duì)象存入數(shù)據(jù)庫有鹿,使用時(shí)要特別留意旭旭。
- decrement!
- decrement_counter
- increment!
- increment_counter
- toggle!
- touch
- update_all
- update_attribute
- update_column
- update_columns
- update_counters
注意,使用save時(shí)如果傳入validate: false印颤,也會(huì)跳過驗(yàn)證您机,使用時(shí)要特別留意。
- save(validate: false)
valid年局?和invalid?
Rails使用valid?方法檢查對(duì)象是否合法际看。valid?方法會(huì)觸發(fā)數(shù)據(jù)驗(yàn)證,如果對(duì)象上沒有錯(cuò)誤矢否,就返回true仲闽,否則返回false,前面我們已經(jīng)用過了:
class Person < ActiveRecord::Base
validates :name, presence: true
end
AR驗(yàn)證結(jié)束后僵朗,所有發(fā)現(xiàn)的錯(cuò)誤都可以通過實(shí)例方法errors.message獲取赖欣,該方法返回一個(gè)錯(cuò)誤集合。如果數(shù)據(jù)驗(yàn)證后验庙,這個(gè)集合為空顶吮,則說明對(duì)象是合法的。
注意粪薛,使用new方法初始化對(duì)象時(shí)悴了,即使不合法也不會(huì)報(bào)錯(cuò),因?yàn)檫@時(shí)還沒與做數(shù)據(jù)驗(yàn)證违寿。
errors[]
要檢查對(duì)象的某個(gè)屬性是否合法湃交,可以使用errors[:attribute]中包含:attribute的所有錯(cuò)誤。如果某個(gè)屬性沒有錯(cuò)誤藤巢,就會(huì)返回空數(shù)組搞莺。
這個(gè)方法只在數(shù)據(jù)驗(yàn)證之后才能使用,因?yàn)樗皇怯脕硎占e(cuò)誤的掂咒,并不會(huì)觸發(fā)驗(yàn)證才沧。而且,和前面介紹的ActiveRecord::Base#invalid?方法不一樣绍刮,因?yàn)閑rros[:attribute]不會(huì)驗(yàn)證整個(gè)對(duì)象糜工,值檢查對(duì)象的某個(gè)屬性是否出錯(cuò)。
數(shù)據(jù)驗(yàn)證幫助方法
AR預(yù)先定義了很多數(shù)據(jù)驗(yàn)證幫助方法录淡,可以直接在模型定義中使用捌木,這些幫助方法提供了常用的驗(yàn)證規(guī)則,每次驗(yàn)證失敗后嫉戚,都會(huì)向?qū)ο蟮膃rrors集合添加一個(gè)消息刨裆,這些消息和所驗(yàn)證的屬性相關(guān)聯(lián)澈圈。
每個(gè)幫助方法都可以接受任意數(shù)量的屬性名,所以一行代碼就能在多個(gè)屬性上做同一種驗(yàn)證帆啃。
所有的幫助方法都可指定:on和:message選項(xiàng)瞬女,指定何時(shí)做驗(yàn)證,以及驗(yàn)證失敗后向errors集合添加什么消息努潘,:on選項(xiàng)的可選值是:create和:update诽偷。
acceptance
這個(gè)方法檢查表單提交時(shí),用戶界面中的復(fù)選框是否被選中疯坤,這個(gè)功能一般用來要求用戶接受程序的服務(wù)條款报慕,閱讀一些文字,等等压怠。
class Person < ActiveRecord::Base
validates :name, acceptance: true
end
這個(gè)幫助方法的默認(rèn)錯(cuò)誤消息是“must be accepted”眠冈。
這個(gè)方法可以指定:accept選項(xiàng),決定可接受什么值菌瘫,默認(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)的模型對(duì)象雇盖,可以使用這個(gè)方法,保存對(duì)象是栖忠,會(huì)在相關(guān)聯(lián)的每個(gè)對(duì)象上調(diào)用valid?方法崔挖。
class Library < ActiveRecord::Base
has_many :books
validates_associated :books
end
這個(gè)幫助方法可用于所有關(guān)聯(lián)類型。
不要在關(guān)聯(lián)的兩端都使用validates_associated娃闲,這樣會(huì)生成一個(gè)循環(huán)虚汛。
validates_associated的默認(rèn)錯(cuò)誤消息是“is invalid”匾浪。注意皇帮,相關(guān)聯(lián)的每個(gè)對(duì)象都有各自的errors集合,錯(cuò)誤消息不會(huì)都集中在調(diào)用該方法的模型對(duì)象上蛋辈。
confirmation
如果要檢查兩個(gè)文本字段的值是否相同属拾,可以使用這個(gè)幫助方法,例如冷溶,確認(rèn)Email地址或密碼渐白,這個(gè)幫助方法回傳件一個(gè)虛擬屬性。
class Library < ActiveRecord::Base
validates :email, confirmation: true
end
視圖中這個(gè)寫
<%= text_field :Library, :email_confirmation %>
只有email_confirmation的值不是nil時(shí)才會(huì)做這個(gè)驗(yàn)證逞频。所以要確認(rèn)屬性加上存在性驗(yàn)證纯衍。
class Library < ActiveRecord::Base
validates :email, confirmation: true
validates :email_confirmation, presence: true
end
這個(gè)幫助方法的默認(rèn)錯(cuò)誤消息是“doesn't match confirmation”。
exclusion
這個(gè)幫助方法檢查屬性的值是否不在指定的集合中苗胀。集合可以是任何一種可枚舉的對(duì)象襟诸。
class Account < ActiveRecord::Base
validates :subdomain, exclusion: { in: %w(www us ca jp), message: "%{value} is reserved."}
end
exclusion方法指定:in選項(xiàng)瓦堵,設(shè)置哪些值不能作為屬性的值,:in選項(xiàng)有個(gè)別名:with歌亲,作用相同菇用,上面的例子設(shè)置了:message選項(xiàng),演示如何獲取屬性的值陷揪。
默認(rèn)的錯(cuò)誤消息是“is reserved”
format
這個(gè)幫助方法檢查屬性的值是否匹配:with選項(xiàng)指定的正則表達(dá)式惋鸥。
class Account < ActiveRecord::Base
validate :legacy_code, format: { with: /\A[a-zA-Z]+\z/, message: "only allows letters" }
end
默認(rèn)的錯(cuò)誤消息是“is invalid”。
inclusion
這個(gè)幫助方法檢查屬性的值是否在指定的集合中悍缠。集合可以是任何一種可枚舉的對(duì)象卦绣。
class Coffee < ActiveRecord::Base
validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" }
end
inclusion方法要指定:in選項(xiàng),設(shè)置可接受哪些值扮休。:in選項(xiàng)有個(gè)別名:with迎卤,作用相同。上面的例子設(shè)置了:message選項(xiàng)玷坠,演示如何獲取屬性的值蜗搔。
該方法的默認(rèn)錯(cuò)誤消息是“is not included in the list”。
length
這個(gè)幫助方法驗(yàn)證屬性值的長(zhǎng)度八堡,有多個(gè)選項(xiàng)樟凄,可以使用不同的方法指定長(zhǎng)度限制:
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
可用的長(zhǎng)度限制選項(xiàng)有:
- :minimum: 屬性的值不能比指定的長(zhǎng)度短;
- :maximum: 屬性的值不能比指定的長(zhǎng)度長(zhǎng)兄渺;
- :in (或:within):屬性值的長(zhǎng)度在指定值之間缝龄,該選項(xiàng)的值必須是一個(gè)范圍。
- :is:屬性值的長(zhǎng)度必須等于指定值挂谍;
默認(rèn)的錯(cuò)誤消息根據(jù)長(zhǎng)度驗(yàn)證類型而有所不同叔壤,還是可以:message定制。定制消息時(shí)口叙,可以使用:wrong_length炼绘、:too_long和:too_short選項(xiàng),%{count}表示長(zhǎng)度限制的值妄田。
class Person < ActiveRecord::Base
validates :bio, length: {maximum: 1000, too_long: "%{count} characters is the maximum allowed"}
end
這個(gè)幫助方法默認(rèn)統(tǒng)計(jì)字符數(shù)俺亮,但可以使用:tokenizer選項(xiàng)設(shè)置其他的統(tǒng)計(jì)方式:
numericality
這個(gè)幫助方法檢查屬性的值是否包含數(shù)字,默認(rèn)情況下疟呐,匹配的值是可選的正負(fù)符號(hào)后加整數(shù)或浮點(diǎn)數(shù)脚曾,如果只接受整數(shù),可以把:only_integer選項(xiàng)設(shè)為true启具。
/\A[+-]?\d+\Z/
否則本讥,會(huì)嘗試使用Float把值轉(zhuǎn)換成數(shù)字。
presence
這個(gè)幫助方法堅(jiān)持指定的屬性是否為非空值,調(diào)用blank?方法檢查是否為nil或空字符串拷沸。
absence
這個(gè)方法驗(yàn)證指定的屬性是否為空旨椒,使用present?方法檢測(cè)值是否為nil。
uniqueness
這個(gè)幫助方法會(huì)在保存對(duì)象之前驗(yàn)證屬性值是否唯一堵漱。
validates_with
這個(gè)幫助方法把記錄交給其他的類做驗(yàn)證综慎。
validates_each
這個(gè)幫助方法會(huì)把屬性值傳入代碼庫做驗(yàn)證,沒有預(yù)先定義驗(yàn)證的方式勤庐,你應(yīng)該在代碼庫中定義驗(yàn)證方式示惊。
常用的驗(yàn)證選項(xiàng)
:allow_nil
指定:allow_nil選項(xiàng)后,如果驗(yàn)證的值為nil就會(huì)跳過驗(yàn)證愉镰。
:allow_blank
:allow_blank選項(xiàng)和:allow_nil選項(xiàng)類似米罚,如果驗(yàn)證的值為空,就會(huì)跳過驗(yàn)證丈探。
:message
如果驗(yàn)證失敗录择,會(huì)把:message選項(xiàng)指定的字符串添加到errors集合中。
:on
指定什么時(shí)候做驗(yàn)證碗降。
嚴(yán)格驗(yàn)證
數(shù)據(jù)驗(yàn)證還可以使用嚴(yán)格驗(yàn)證模式隘竭,失敗后會(huì)拋出ActiveModel::StrictValidationFailed異常。
條件驗(yàn)證
有時(shí)只有滿足特定條件時(shí)做驗(yàn)證才說的通
指定Symbol
:if和:unless選項(xiàng)的值為Symbol時(shí)讼渊,表示要在驗(yàn)證之前執(zhí)行對(duì)應(yīng)的方法动看。
指定字符串
:if和:unless選項(xiàng)的值還可以是字符串
指定Proc
:if和:unless選項(xiàng)的值還可以是Proc
條件組合
有時(shí)同一個(gè)條件會(huì)用在多個(gè)驗(yàn)證上,這時(shí)可以使用with_options方法:
聯(lián)合條件
如果是否做某個(gè)驗(yàn)證要滿足多個(gè)條件時(shí)爪幻,可以使用數(shù)組菱皆,而且,都一個(gè)驗(yàn)證可以同時(shí)指定:if和:unless選項(xiàng)挨稿。
自定義驗(yàn)證方式
自定義驗(yàn)證使用的類
自定義驗(yàn)證使用的方法
還可以自定義方法驗(yàn)證模型的狀態(tài)仇轻,如果驗(yàn)證失敗,向errors集合添加錯(cuò)誤信息奶甘,然后還要使用類方法validate注冊(cè)這些方法篷店。
處理驗(yàn)證錯(cuò)誤
除了前面介紹的valid?和invalid?方法之外,Rails還提供了很多方法用來處理errors集合甩十,以及查詢對(duì)象的合法性船庇。
errors[:base]
在視圖中顯示驗(yàn)證錯(cuò)誤
Active Record 回調(diào)
- AR對(duì)象的生命周期
- 如何編寫回調(diào)方法響應(yīng)對(duì)象聲明周期內(nèi)發(fā)生的事件
- 如何把常用的回調(diào)封裝到特殊的類中吭产;
對(duì)象的生命周期
在Rails程序運(yùn)行過程中侣监,對(duì)象可以被創(chuàng)建、更新和銷毀臣淤。Active Record為對(duì)象的生命周期提供了很多鉤子橄霉,讓你控制程序及其數(shù)據(jù)。
回調(diào)可以在對(duì)象的狀態(tài)改變之前或之后觸發(fā)指定的邏輯操作邑蒋。
回調(diào)簡(jiǎn)介
注冊(cè)回調(diào)
這種類方法還可以接受一個(gè)代碼塊姓蜂,如果操作可以使用一行代碼表述按厘,可以考慮使用代碼塊形式。
class Person < ActiveRecord::Base
validates :login, :email, presence: true
before_create do
self.name = login.capitalize if name.blank?
end
end
注冊(cè)回調(diào)時(shí)可以指定只在對(duì)象生命周期的特定事件發(fā)生時(shí)執(zhí)行:
一般情況下钱慢,都把回調(diào)方法定義為受保護(hù)的方法或私有方法逮京,如果定義成公共方法,回調(diào)就可以在模型外部調(diào)用束莫。
可用的回調(diào)
創(chuàng)建對(duì)象
- before_validation
- after_validation
- before_save
- around_save
- before_create
- around_create
- after_create
- after_save
更新對(duì)象
- before_validation
- after_validation
- before_save
- around_save
after_initialize和after_find
after_initialize回調(diào)在Active Record對(duì)象初始化時(shí)執(zhí)行懒棉,包括直接使用new方法初始化和從數(shù)據(jù)庫中讀取記錄,after_initialize回調(diào)不用直接重定義Active Record的initialize方法览绿。
after_find回調(diào)在數(shù)據(jù)庫中讀取記錄時(shí)執(zhí)行策严,如果同時(shí)注冊(cè)了after_find和after_initialize
after_touch
after_touch回調(diào)在觸碰Active Record對(duì)象時(shí)執(zhí)行。
可以結(jié)合belongs_to一起使用
執(zhí)行回調(diào)
下面的方法會(huì)觸發(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í)行
在模型中注冊(cè)回調(diào)后,回調(diào)會(huì)加入一個(gè)執(zhí)行隊(duì)列怀各。
關(guān)聯(lián)回調(diào)
回調(diào)能在模型關(guān)聯(lián)中使用倔韭,甚至可由關(guān)聯(lián)定義,假如一個(gè)用戶發(fā)布了多篇文章瓢对,如果用戶刪除了狐肢,他發(fā)布的文章也應(yīng)該刪除,下面我們?cè)趐ost模型中注冊(cè)一個(gè)after_destroy回調(diào)沥曹,應(yīng)用在User模型上:
條件回調(diào)
和數(shù)據(jù)驗(yàn)證類似份名,也可以滿足指定條件時(shí)再調(diào)用回調(diào)方法。條件通過:if和:unless選項(xiàng)指定妓美,選項(xiàng)的值可以是Symbol僵腺、字符串、Proc或數(shù)組壶栋。
使用Symbol
:if和:unless選項(xiàng)的值為Symbol時(shí)辰如,表示要在調(diào)用回調(diào)之前執(zhí)行對(duì)應(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)?
讓代碼更簡(jiǎn)潔
怎么使用關(guān)聯(lián)贵试?
- belongs_to 一對(duì)一關(guān)系
- has_one 一對(duì)一關(guān)系
- has_many 一對(duì)多關(guān)系
- has_many :through 多對(duì)多關(guān)系
- has_one :through 關(guān)聯(lián)建立兩個(gè)模型之間一對(duì)一關(guān)系琉兜,這種關(guān)聯(lián)表示一個(gè)模型通過第三個(gè)模型擁有另一個(gè)模型的實(shí)例,例如毙玻,每個(gè)供應(yīng)商只有一個(gè)賬戶豌蟋,而且每個(gè)賬戶都有一個(gè)歷史賬戶,那么定義模型:
- has_and_belongs_to_many
使用belongs_to還是has_one
如果想建立兩個(gè)模型之間的一對(duì)一關(guān)系桑滩,可以在一個(gè)模型中聲明belongs_to梧疲,然后再另一個(gè)模型中聲明has_one。
使用has_many :through 還是has_and_belongs_to_many
如果需要做數(shù)據(jù)驗(yàn)證、回調(diào)幌氮,或者連接模型上要用到其他屬性缭受,此時(shí)就要使用has_many :through
第二種方法是使用has_many :through,但無法直接建立關(guān)聯(lián)该互,要通過第三個(gè)模型
多態(tài)關(guān)聯(lián)
關(guān)聯(lián)還有一種高級(jí)用法米者,“多態(tài)關(guān)聯(lián)”。在多態(tài)關(guān)聯(lián)中宇智,在同一個(gè)關(guān)聯(lián)中塘雳,模型可以屬于其他多個(gè)模型。例如普筹,圖片模型可以屬于雇員模型或者產(chǎn)品模型败明,模型的定義如下:
自連接
設(shè)計(jì)數(shù)據(jù)模型時(shí)會(huì)發(fā)現(xiàn),有時(shí)模型要和自己建立關(guān)聯(lián)太防,例如妻顶,在一個(gè)數(shù)據(jù)表中保存所有雇員的信息,但要建立經(jīng)理和下屬之間的關(guān)系蜒车,這種情況可以使用自連接關(guān)聯(lián)解決:
小技巧和注意事項(xiàng)
- 緩存控制
- 避免命名沖突
- 更新模式
- 控制關(guān)聯(lián)的作用域
- Bi-directional associations
1讳嘱、雙向關(guān)聯(lián)
默認(rèn)情況下,AR并不知道這個(gè)關(guān)聯(lián)中兩個(gè)模型之間的關(guān)系酿愧,可能導(dǎo)致同一對(duì)象的兩個(gè)副本不同步沥潭。
為了解決這個(gè)問題,引入了:inverse_of選項(xiàng)嬉挡,可以告知Rails兩者之間的關(guān)系钝鸽。
2、關(guān)聯(lián)詳解
belongs_to 關(guān)聯(lián)詳解
belongs_to關(guān)聯(lián)創(chuàng)建一個(gè)模型與另一個(gè)模型之間的一對(duì)一關(guān)系庞钢,用數(shù)據(jù)庫的行話來說拔恰,就是這個(gè)類包含了外鍵。如果外鍵在另一個(gè)類中基括,就應(yīng)該使用has_one關(guān)聯(lián)颜懊。
belongs_to 關(guān)聯(lián)添加的方法
如果關(guān)聯(lián)的對(duì)象存在,associate方法會(huì)返回關(guān)聯(lián)對(duì)象风皿。如果找不到關(guān)聯(lián)對(duì)象河爹,則返回nil。
belongs_to方法的選項(xiàng)
Rails的默認(rèn)設(shè)置足夠智能桐款,能滿足常見需求咸这,但有時(shí)還是需要定制belongs_to關(guān)聯(lián)的行文,定制的方法很簡(jiǎn)單鲁僚,聲明關(guān)聯(lián)時(shí)傳入選項(xiàng)或者使用代碼塊即可炊苫。
belongs_to 關(guān)聯(lián)支持以下選項(xiàng):
- :autosave
- :class_name
- :counter_cache
belongs_to的作用域
檢查關(guān)聯(lián)的對(duì)象是否存在
什么時(shí)候保存對(duì)象
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 方法的選項(xiàng)
has_one 的作用域
有時(shí)需要定制has_one關(guān)聯(lián)使用的查詢方式,定制的查詢可在作用域代碼塊中指定冰沙。
檢查關(guān)聯(lián)對(duì)象是否存在
什么時(shí)候保存對(duì)象侨艾?
has_many 關(guān)聯(lián)詳解
has_many 關(guān)聯(lián)添加的方法
聲明has_many后,自動(dòng)獲得16個(gè)關(guān)聯(lián)相關(guān)的方法:
- collection(force_reload = false)
- collection<<(object, ...)
- collection.delete(object, ...)
has_many 方法的選項(xiàng)
作用域
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)代理對(duì)象自動(dòng)創(chuàng)建的功能是死的,但是可以通過匿名模塊侥啤、新的查詢方法当叭、創(chuàng)建對(duì)象的方法等進(jìn)行擴(kuò)展。