2013-02-18 21 views
0

考慮以下在Rails中的父模型特定的ID列?

:company has_many :issues #ticket tracking example 

我想有路由,使得該公司任何用戶都可以去/問題/:(使用默認的ID列時,這是很簡單的)的標識。

但是,我想反而有一個特定於公司的問題編號(所以每個公司都有自己的問題1,2,3等不是唯一的(並且不會使用內部編號)

有沒有更好的方法比基於最後一個數據庫中的最後一個號碼在IssueController的創建和更新操作中爲該公司ID?(我可以想到在多條記錄是競爭條件時的各種問題提前更新/每公司創建)。

謝謝!

+0

所以你想'問題'有一個由'id'和'company_id'組成的複合主鍵? – PinnyM 2013-02-18 16:59:27

+0

不確定什麼是最好的方式來得到這個工作是(雖然我可以一起黑客攻擊) - 即當一個請求進入/問題/ 5701,@issue = Issue.where(company_id:current_user.company.id,issue_id: PARAMS [:ID])。我更關心的是,這是否是將這種事情存儲在數據庫中的最佳方式(以及前面提到的db查找以獲得該公司的下一個可用issue_id感覺很糟糕)。 – Tom 2013-02-18 17:08:51

回答

1

我想借此issue_id處理到模型級別。您可以使用before_validation回調來設置issue_id。即使save調用被封裝在一個事務中,也不會阻止競爭條件。正如@PinnyM所建議的那樣,您必須通過向您的issues表中添加索引/唯一約束來進一步確保夫婦[ :company_id, :issue_id ]的唯一性。因此,像這樣

class Issue < ActiveRecord::Base 
    attr_accessible :company_id, :issue_id 
    belongs_to :company 
    before_validation :set_issue_id 

    private 
    def set_issue_id 
     self.issue_id = self.company.issues.size + 1 
    end 
end 

class Company < ActiveRecord::Base 
    has_many :issues 
end 

和遷移內:

add_index :issues, [:issue_id, :company_id], :unique => true 

而且像你說的,你可以抓住正確的問題控制器:

@issue = Issue.where(company_id: current_user.company.id, issue_id: params[:id]) 

注意,這不提供一種方法來從約束違規異常中恢復,以防實際發生。有關如何處理此問題的建議,請參閱@PinnyM回答。

希望這會有所幫助。

+0

這與OP希望避免的競賽條件相同......即使事務包裝,「issues.size」也不能保證唯一性。 – PinnyM 2013-02-18 18:11:39

+0

你能詳細說明一下嗎?唯一的問題是,如果'issues.size'在分配給issue_id後並且在保存記錄之前更改,但這不會發生正確? – deivid 2013-02-18 18:13:06

+0

驗證執行時,多個請求可能會造成問題。因爲當前的'company.issues'集合大小是相同的,即使它們是不同的記錄,它們也將被分配相同的'issue_id'。 – PinnyM 2013-02-18 18:15:59

1

第一次誤解了這個問題之後,我會再試一次。

您正在尋找一種針對company_id特定問題'counter'(模擬id)的方法。儘管@deivid是正確的,但依靠issues.count只有在您可以保證公司從不一次發出多個請求時才能正常工作。這通常會是這種情況,但不能保證,不應該單獨用作此櫃檯背後的核心邏輯。

你需要的唯一約束/索引添加到您的issues表 - 這將確保計數器不能被複制:

add_index :issues, [:issue_id, :company_id], :unique => true 

在模型中添加:uniqueness約束只會緩解這一問題有點通過使比賽條件的窗口更小,但它不能完全保證唯一性。

請注意,如果數據庫中存在約束違規事件,ActiveRecord無法在事務中從其中恢復。您可以嘗試救援ActiveRecord::RecordNotUnique,重新創建issue(或僅使用新的count重新生成issue_id)並再次保存。

+0

我認爲我們應該將兩個答案合併爲一個,因爲它們是互補的。您可以將我的(更正後的)代碼整合到您的代碼中,然後我將刪除我的代碼。 – deivid 2013-02-18 18:58:29

+0

我很欣賞你的誠信,但如果你想要這個合併,你可以簡單地將約束信息複製到你的答案。 – PinnyM 2013-02-18 19:04:47

+0

謝謝,我會那樣做的 – deivid 2013-02-18 19:11:00

相關問題