10

我開始爲我所有模型的id字段使用Postgres UUID類型。在軌道4的偉大工程,支持(大部分):在Rails中使用Postgres UUID時避免PG :: InvalidTextRepresentation錯誤

create_table :users, id: :uuid do |t| 
    # ... 
end 

的問題是,如果你試圖找到一排,其中ID爲X Postgres將產生一個錯誤,但X不是格式正確的UUID字符串。

> User.find "3ac093e2-3a5e-4744-b49f-117b032adc6c" 
ActiveRecord::RecordNotFound # good, will cause a 404 
> User.find "foobar" 
PG::InvalidTextRepresentation: ERROR # bad, will cause a 500 

所以,如果我的用戶是一個頁面上,其中一個UUID是在URL,然後他們試圖改變UUID,他們會得到的,而不是404 500錯誤或者也許他們得到一個鏈接一個不再存在的對象。

我怎樣才能避免這種情況下乾的方式?我不能挽救並渲染404,因爲other things也會導致此錯誤。

UPDATE

我認爲,在ID參數的時格式的正則表達式是乾淨的,而且它提出了一個404,如果不匹配:

resources :users, id: /uuid-regex-here/ 

但我仍然有停留乾的問題;我不想把這個放在我的路線中的每一個資源上。我可以在一個語句中聲明多個資源,但前提是不要將其他選項用作成員操作。 所以也許更好的問題是:有沒有一種方法來設置所有路線的ID正則表達式?

+0

你爲什麼要通過foobar?你的路線在它落在你的模型之前是否應該抓住它? –

+0

@Denis我想我可以對id參數進行約束,以確保它匹配UUID正則表達式。但是我必須爲我的路線中的每一個資源都做到這一點......或者您還有其他想法嗎? – tybro0103

+0

也許你的控制器的'before_filter'可以工作。 –

回答

7

您可以通過constraints() do ... end一次將路由約束添加到多個路由。

我終於實現了這一點,並設置所有:id PARAMS一個全球性的約束匹配到一個UUID正則表達式:

MyApp::Application.routes.draw do 
    constraints(id: /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i) do 

    # my routes here 

    end 
end 

這樣,/職位/ 123或/職位/ foobar的不再匹配/職位/:id和404之前調用控制器操作,從而避免PG類型的錯誤。

我所有的模型都將使用UUID作爲它們的ID,所以這是乾淨而乾燥的。如果我也有一些帶有整數ID的模型,它會不太乾淨。

+0

如果你使用的是UUID gem,你可以使用他們的validate方法而不是自己滾動https://github.com/assaf/uuid/blob/master/lib/uuid.rb#L199 –

+0

@BrianHahn很高興知道,儘管我並沒有真的在滾動我的自己......這只是一個正則表達式。 – tybro0103

+0

我的意思是它會在已經擁有UUID gem的環境中滾動自己。當UUID gem不是項目中的依賴項時,您的正則表達式看起來很好! –

2

如果你不想限制添加到所有路線追趕無效的UUID,那麼你可以在一個before_filter雜牌,這樣的事情:

before_filter do 
    if(params.has_key?(:id)) 
    uuid = params[:id].strip.downcase.gsub('-', '').gsub(/\A\{?(\h{32})\}?\z/, '\1') 
    raise ActiveRecord::RecordNotFound if(uuid.blank?) 
    end 
end 

注意,UUID可有各種形式(請參閱the fine manual),因此最好在驗證它們之前對它們進行規範化,或者同時進行規範化和驗證。

你可以將它放入你的ApplicationController如果你知道你的所有:id參數應該是的UUID或把邏輯在需要它的控制器的ApplicationController方法和before_filter :make_sure_id_is_a_uuid

+0

這並不壞,如果我沒有找到一種方法將正則表達式添加到路由中,我將最終與此相關 – tybro0103

+0

另一個猴子修補的可能性是AR PostgreSQL驅動裏面的類型轉換的東西,在那裏有一個很大的'case'語句 –

相關問題