2012-07-27 51 views
9

假設我有一個ActiveRecord的關聯,如:什麼時候應該驗證ActiveRecord關聯對象的存在與其ID?

class City < ActiveRecord::Base 
    belongs_to :state 
end 

有市無的狀態應該是無效的。看來,這兩個都是可能的驗證:

validates :state, presence: true 
# OR 
validates :state_id, presence: true 

我猜想它們是相同的,因爲:

  • belongs_to創建方法statestate=
  • state=設置state_id

但是,我通過將其更改爲c來修復了一個失敗的規範找到id而不是對象。

這兩種驗證方法都可以接受嗎?如果是這樣,你什麼時候使用其中一個?

+0

我們能否看到您的原始和固定規格? – deefour 2012-07-27 20:42:25

回答

12

validates :state將使用城市與州(belongs_to)之間的關係以及外鍵,而validates :state_id僅使用列state_id並查看它是否具有任何值。

我的首選方法是驗證state(關係),因爲這需要密鑰和關係都存在。

驗證state_id將起作用,因爲它將確保存在狀態ID,但是它不會檢查代碼的有效性,即對於City中的任何給定狀態鍵實際上「存在」狀態。

基本上,如果City中使用的外鍵(for state_id)在State中都是作爲實際記錄存在的,效果是一樣的。如果您的狀態中有無效的狀態碼,則會顯示不同之處。

+0

這是否使測試更加困難,因爲每個有效的'城市'也必須有一個有效的'國家'的ID?當你想創建一個'City'時,必須創建一個'State'似乎令人討厭。 – oregontrail256 2015-03-12 05:22:16

1

如果你不喜歡的東西

s = State.new 
c = City.new 
c.state = s 
c.valid? 

我還沒有試過,但我猜,如果你檢查c.state_id的存在,它將會丟失,即使c確實有一個狀態(因爲ID尚未生成,因爲狀態尚未保存)。

也就是說,如果你關心的是狀態的存在,你應該驗證狀態的存在。

1

就個人而言,我傾向於讓模型更強大,並接受或者。因此,在您的特定情況下,City可以接受State對象或state_id,但需要發送其中一個對象。

class City < ActiveRecord::Base 
    attr_accessible :state, :state_id 

    validates :state, presence: true, if: proc{|c| c.state_id.blank? } 
    validates :state_id, presence: true, if: proc{|c| c.state.blank? } 

    belongs_to :state 
end 

編輯:刪除在驗證語句中的雙重否定。原本unless: proc{|c| !c.state_id.blank? }

+0

我喜歡你的方法。 Nitpick:除非空白,否則不需要'; 「如果空白?」或「除非存在?」都可以。 – 2013-08-22 16:15:11

+0

這是非常真實的,我打算把'present',因爲這只是'!blank?'的倒數,但我更喜歡'!blank'的可讀性。但是如果沒有雙重否定,做'if blank'也可以工作:P – 2013-08-22 16:55:25

0

根據Rails 4 Way by Obie Fernandez

如果你想確保關聯存在,通過它 外鍵的屬性,而不是關聯變量本身

validates :region_id, :presence => true 
validate :region_exists 

def region_exists 
    errors.add(:region_id, "does not exist") unless Region.exists?(region_id) 
end 

這本書沒有解釋爲什麼你應該使用這個而不是

validates :region, :presence => true 

但我知道這些人知道他們的東西。

+0

這與'validate:region,presence:true'是一樣的,只是它也強制檢查數據庫中是否存在關聯。這樣做似乎有點奇怪,因爲它不提供對內存對象的驗證。在經驗中,僅僅驗證對象並添加外鍵約束以確保密鑰總是有效就會更容易。 – 2016-04-06 17:50:04

+0

就像我說的,這些傢伙知道他們的東西:)。雖然好點。 – wbeange 2016-04-06 17:55:45

+1

也許是因爲性能的原因,因爲驗證:每次驗證對象時,區域都會從數據庫加載區域,同時驗證:region_id不會這樣做。 – remo 2017-12-06 11:38:25

相關問題