2016-02-24 62 views
0

我有一個Rails 4.2/Ruby 2.2應用程序,其中我有一個用戶表和一個服務器表。服務器「屬於」一個用戶(外部鍵入user_id),並且服務器名稱對於特定用戶必須是唯一的。它看起來像這樣在PostgreSQL的:Rails驗證:多字段唯一性:數據庫中的不必要查詢

CREATE TABLE users (
    id integer NOT NULL, 
    name character varying(255) 
); 

CREATE TABLE servers (
    id integer NOT NULL, 
    name character varying(255), 
    user_id integer NOT NULL 
); 

ALTER TABLE servers ADD CONSTRAINT servers_user_id_fk FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE RESTRICT; 

ALTER TABLE servers ADD PRIMARY KEY (user_id, name); 

SQL語句將阻止我將服務器指的是一個無效的用戶,它會阻止特定用戶使用的服務器的名稱不止一次。

Rails的模型看起來是這樣的:

class User << ActiveRecord::Base 
    has_many :servers 
end 

class Server << ActiveRecord::Base 
    belongs_to :user, foreign_key: "user_id" 

    validates :must_have_unique_name_and_user_id, on: :create 

    def must_have_unique_name_and_user_id 
    name_count = Server.where(user_id: user_id, name: name).count 
    if name_count > 0 
     errors[:base] << "Server name is already taken for name #{name}, and user #{user.name}" 
    end 
end 

我的問題是,當我運行測試套件的代碼覆蓋率,must_have_unique_name_and_user_id()被調用上百次,因爲這兩款機型基本以我的整體數據模型。這些驗證調用中的每一個都會導致數據庫查詢來檢查服務器名稱是否對用戶是唯一的。

這好像很多不必要的工作只是爲了保證一些東西,該數據庫將不允許不管在Rails的有效數據。

是如果用戶試圖具有用於服務器的複製(USER_ID,名稱)的組合,能夠構建滑軌驗證,使得錯誤消息我在滑軌驗證must_have_unique_name_and_user_id()顯示,但是,這種Rails驗證不是每次都運行?

回答

0

數據庫是你的哪些用戶和服務器一起出現真理的來源,所以沒有辦法Rails可以驗證不問。

你可以,但是,刪除軌驗證和通過把一個唯一索引servers.user_id, servers.name它留到DB。如果您嘗試更新或創建無效行,則會引發異常,然後您必須捕獲並處理該行。

所以,您的選擇是額外的查詢和代碼的複雜性之間的權衡。我的建議是:讓Rails執行額外的查詢,直到遇到性能問題。

如果這是特定於您的測試套件的問題(比如,你正在試圖獲得它運行得更快),你可以儘量避免在實際測試中創建對象。與在一個進程內存中執行所有操作相比,觸及數據庫往往受到很大的衝擊,所以如果您可以在不保存的情況下構建,連接和使用對象,那麼您可能會獲得穩定的加速。

+0

有一件事我沒有提到的是,我用的是SQL數據庫我的測試。我不只是使用Ruby schema.rb(例如config.active_record.schema_format =:sql)。測試套件大約有700次測試,大約需要4分鐘才能運行。我的喜好有點長。 –

+0

我認爲這一切仍然適用 - 你有具體的跟進問題嗎? –

+0

我無法避免在測試過程中觸摸數據庫,因爲我沒有使用schema.rb進行測試,因此我無法通過避免數據庫來加快速度。 –