2008-11-27 27 views
3

這是一個Rails/ActiveRecord的問題。分配虛擬屬性時出現信令驗證錯誤?

我有一個模型,基本上必須代表事件或表演。每個事件都有許多歸屬地:歸因基本上類似於「在此情況下,個人X具有角色Y」。

我的結論是,最好的方式,讓用戶編輯這個數據是通過提供一個希望將結構化的格式,我會打電話給一個角色串自由文本字段:

singer: Elvis Costello, songwriter: Paul McCartney, ...

我使用自動完成來完成角色名稱(歌手,歌曲作者...)和人名。角色和人員都存儲在數據庫中。

要實現這一點,我創建的事件模型中的虛擬屬性:

def role_string 
    # assemble a role string from the associations in the model 
end 

def role_string=(s) 
    # parse a string in the above role string format, 
    # look up the People and Events mentioned, and update 
    # what's in the database 
end 

這是所有罰款。整個事情工作得很好,當角色字符串格式良好並且角色字符串給出的關聯全部檢出時。

但是,如果角色字符串格式不正確呢?好吧,我想,我只是可以共同使用正則表達式與標準的驗證,以檢查格式:

validates_format_of :role_string, :with => /(\w+:\s*\w+)(,\s*\w+:\s*\w+)*/ 

但如果該角色串所隱含的關聯是無效的?例如,如果我給出上述角色字符串,並且Elvis Costello未引用有效的人員,會發生什麼情況?例如,如果給出的名稱之一不匹配任何內容,我認爲,我可以使用屬性:role_string上的validates_each來查找關聯並拋出錯誤。

我的問題是兩個:首先,我不喜歡這種方法,因爲爲了驗證關聯性,我將不得不解析字符串並查找它們,這些重複我在role_string=本身中做的事情,除了實際上將關聯保存到數據庫。

第二,...我如何指出分配給這個虛擬屬性時發生錯誤?

回答

3

首先,你錯誤地將人員歸因於事件。您應該將人員ID傳遞給該事件,而不是該人員姓名的字符串。例如,如果一個身份證號爲230404,姓名爲「Elvis Costello」的人將他的名字改爲「Britney Spears」?那麼,如果發生這種情況,ID將保持不變,但名稱會改變。但是,您將無法再引用該人員。

你必須讓你的協會,這樣的外鍵引用人多的情況下:

has_one :singer, :class_name => "Person", :foreign_key => "singer_id" 
has_one :songwriter, :class_name => "Person", :foreign_key => "songwriter_id" 

這種方式,你可以有一個事件在不同的角色相關聯,多個人,你可以參考多個Person可能擁有的屬性。例如:

Event.first.singer.name # => "Elvis Costello" 
Event.first.songwriter.name # => "Britney Spears" 

可以查詢可用的驗證爲關聯(validates_associated),一個ID以及是否存在於形式(validates_presence_of)。我會建議創建自己的自定義驗證以確保Person是有效的before_save。喜歡的東西(未經測試):

def before_save 
    unless Person.exists?(self.songwriter_id) 
    self.errors.add_to_base("Invalid songwriter. Please try again!") 
    return false 
    end 
end 

另外,我注意到你正在尋找一種方式供用戶選擇哪些應該用於在事件中的角色的用戶。這裏是你可以做你的形式部分:

select(:event, :singer_id, Person.find(:all).collect {|p| [ p.name, p.id ] }, { :include_blank => 'None' }) 

希望這可以幫助!

相關問題