2009-12-21 62 views
2

作爲一名長期使用Ruby和Rails的用戶,直到今天才真正想到了Rails中的get-and-redirect模式。這樣做的典型的例子是調用Create()行爲,然後將用戶重定向到一個節目()動作,以顯示新創建的項目:redirect_to對於RESTful應用程序無法正常工作?

 
class JournalEntries 

    def index 
    @entries = JournalEntry.all 
    end 

    def create 
    @entry = JournalEntry.new(:name => "to-do list") 
    @entry.save 
    redirect_to :action => "index" 
    end 
end 

然而,這有固有的缺點,你是雙倍的網絡流量。這既會降低用戶的網站體驗速度,也會增加您的帶寬費用。

那爲什麼不這樣做,而不是:

 
    def create 
    @entry = JournalEntry.new(:name => "to-do list") 
    @entry.save 
    index 

同樣的輸出,並且不需要額外的開銷。但除此之外,還有一個更重要的問題:redirect_to只能使用GET進行重定向。這對使用四種不同HTTP方法的RESTful應用程序造成嚴重問題。

就我而言,我希望用戶能夠調用/ journals/8並使用該ID檢索日誌。如果找不到,我想創建一個新的空白日記對象。無論哪種情況,Journal對象都會被髮送給調用者。

請注意,RESTful Rails中的create()方法是從「POST/players」路由的。但是由於redirect_to(和底層的HTTP重定向)只能發送GET請求,它實際上會重定向到「GET/players」,這是index()方法。這種行爲顯然是錯誤的。

我能想到的唯一解決方案就是簡單地調用create()而不是redirect_to(),如上面的示例中所示。它似乎工作正常。

有關爲什麼redirect_to優先於直接調用動作的任何想法?

回答

0

我是一個Python/Django的人,但對於重定向的原因是語言無關:「重新發送數據」

  1. 如果他們做了刷新頁面,他們沒有得到這樣的煩人彈出。
  2. 這爲您提供了一個完全乾淨的RESTful URL,用於他們正在查看的頁面。如果你使用POST可能無關緊要,但如果GET用於更新,那麼你肯定想要擺脫任何懸空參數。
+0

只是對第二點的評論。正如我所理解的那樣,REST的一點是絕對不要使用GET進行更新,所以這絕不應該是一個問題。 – 2009-12-21 23:07:59

+0

@Jimmy:同意,在適當的REST中它不應該發生。 – 2009-12-21 23:24:17

+0

所以基於你們都說,這聽起來像問題是,我想要做的事情本質上是不安寧的 - 如果一個人想要返回一個對象,如果它存在,並創建它,如果它不存在,那會需要兩個獨立的電話: GET/journal/1 (如果這不返回記錄,則客戶端調用): POST/journals/[POST data:journal.id = 5] 這是正確的嗎?也就是說,在REST中沒有一次性調用既可以作爲單個操作來執行? – mrjake2 2009-12-22 00:01:28

2

如果他們做頁面刷新,他們不會得到那個惱人的「重發數據?」彈出

它不只是彈出煩人(和毫無意義的大多數用戶) - 如果用戶點擊「是,重新做POST」,他最終會創造另一個日記帳分錄(管他呢)。

此外,由於用戶無法複製/重新使用它,因此很難讓URL讀取/posts/create而不是/posts

+0

在我的情況下,這實際上並不是真的 - 用戶在原始請求中傳遞他們想要創建的對象的ID(它來自另一個應用程序)。所以如果他們再次嘗試POST,它只會返回帶有該ID的對象的副本。 – mrjake2 2009-12-21 23:59:00

2

它的原因正如你指出的那樣。你重定向到一個GET請求,這對於REST來說是正確的(只用POST/PUT進行更新,只用GET來獲取數據)。

重定向肯定會給重定向帶來一點負擔,但由於除了POST數據和重定向(僅向瀏覽器發送新url),瀏覽器和服務器之間實際上沒有發送數據不要認爲帶寬問題值得關注。

但在另一個角度來說,你不應該重定向到/期刊(通過調用redirect_to :index),你應該把它重定向到新創建的日記帳分錄(通過調用redirect_to @entry)如果你設置了路線正確地將工作,爲例如map.resources :journals

更新:

我認爲,對於創建雜誌當一個人不存在,你應該要求用戶提供更多的投入。您創建該條目的原因是什麼?該條目應該有一些文本或來自用戶的其他輸入,所以我認爲從REST(和rails)的角度來看,您實際上應該將其重定向到new()方法(帶有GET請求),用戶可以在其中輸入附加信息,然後一個將POST輸入並創建條目並重定向到新創建的條目之後。

如果您沒有任何需要插入的額外信息,我不確定如何以REST方式執行此操作,但我可能會通過將創建邏輯放入單獨的方法我會從create()show()方法調用,然後繼續show(),根本不重定向,但也不調用資源方法。

+0

我想我應該從第一篇文章的後半部分開始 - 我的主要問題不是網絡開銷,而是實際調用的方法。從我的控制器的角度(根本不考慮如何調用方法),我想調用Journal.show()來調用Journal.create()的調用,如果找不到給定的Journal,然後返回創建的對象。 據我所見,絕對沒有辦法在REST應用程序中使用redirect_to來完成此操作,原因是在原始文章中陳述的原因。我錯過了什麼嗎? – mrjake2 2009-12-21 23:56:03

+0

Jimmy:在我的情況下,除了對象的ID(從單獨的應用程序中檢索到)之外,確實沒有任何用戶提供的數據。 create方法只是用一堆通用數據填充對象並返回它;調用者然後在客戶端應用程序中操縱對象。最終,我認爲在最後一段中它完全正確 - 我需要在控制器中使用show()和create()調用的受保護的initialize_with_defaults()方法。 – mrjake2 2009-12-22 01:45:55

相關問題