這裏有幾個問題需要解決。
瀏覽器一般不允許重定向到POST請求。
redirect_to不保存沒有額外輸入的格式。
存儲位置不保留表單數據。
所有這些問題都可以通過消除重定向來解決。
這裏是我如何遞了過去吧:
在required_user重定向相反的,渲染。如果之前的過濾器重定向或呈現掛起的操作被取消。 (不需要返回false)。不幸的是,這條路線模糊了控制器邊界。但是允許簡單的html回退,並且將自己借給DRYness。
新的工作流程的高級視圖將是:
- 請求註解#投票(POST)
- required_user過濾器失敗
- 呈現新的會話
- 提交登錄信息和原POST數據返回到註釋#投票(POST)
- 投票中的新過濾器捕獲會話信息並登錄。投票按預期進行。如果登錄失敗回到3
- 註釋#投票重定向/渲染,因爲它應該
開始通過再處理require_user呈現user_sessions#新模板。
def require_user
unless current_user
flash[:notice] = "You'll need to login or register to do that"
@user_session ||= UserSession.new
respond_to do |format|
format.html {render :template => 'user_sessions/new'}
format.js {
render :template => 'user_sessions/new', :layout => false
}
end
end
end
@user_session ||= UserSession.new
確保我們可以將驗證錯誤返回給表單。
現在我們必須加強您的user_session#新模板,以便它可以記住該操作。此外,如果您計劃使用Lightbox,則應該是由相關RJS或new.html.erb呈現的部分渲染。
首先我們創建一個部分來創建隱藏字段保存,將已經在重定向丟失的POST數據:
<% if params[:controller] == "annotations" %>
<% content_for :old_form do %>
<%= hidden_field_tag "annotation[song_id]", params[:annotation][:song_id] %>
<%= hidden_field_tag "annotation[vote]", params[:annotation][:vote] %>
<% end %>
<% end %>
然後呈現在登錄部分,將佔據你的收藏夾那部分:
<%= render :partial => vote_form_replica %>
<% url = params[:controller] == "user_sessions ? user_sessions_url : {} %>
<% form_tag @user_session, :url => url do |f| %>
<%= yield :old_form %>
<%= f.label :user_name %>
<%= f.text_field :user_name %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= submit_tag %>
<%end%>
form_tag中URL的空哈希看起來像一個錯誤,但不是。它確保將表單數據發佈到呈現表單的url。在這一點上應該是註釋/:編號/投票
現在爲新的過濾器登錄。從本質上講,它將做什麼UserSessionsController#create沒有渲染/重定向。以下是從RESTful身份驗證插件中複製的。
def authenticate
self.current_user = User.authenticate(params[:login], params[:password])
if logged_in?
if params[:remember_me] == "1"
current_user.remember_me unless current_user.remember_token?
cookies[:auth_token] = { :value => self.current_user.remember_token,
:expires => self.current_user.remember_token_expires_at }
end
end
end
剩下的就是確保過濾順序是正確的。
before_filter :authenticate, :require_user, :only => :vote
N.B:你可能不會使用此版本require_user沒有這個版本的身份驗證,因此它是有道理的將它們組合成一個單一的過濾器。
就是這樣。這種設置的方式允許強大的DRY輕鬆重用代碼。通過將新過濾器放置到ApplicationController中,它們可以在任何控制器中使用。從這一點開始,將此功能添加到任何其他控制器/操作只需3個簡單步驟:
- 在vote_form_replica部分之後創建新的部分建模。
- 將相應的渲染語句添加到新的會話模板。
- 將過濾器應用於您的操作。
我認爲你必須在過濾器之前結合':authenticate'和':require_user'。因爲你不能分別調用':require_user',因爲用戶永遠無法登錄。但是,我認爲這是總體上正確的方法 - 特別是用於「重放」用戶的'content_for'技巧他希望登錄時的動作以及通過'before_filter'登錄用戶的一般想法都非常聰明 – 2010-01-18 04:28:53
謝謝。 content_for並不是真的有必要,我只是覺得它讓代碼更易於閱讀。它在你的partials中效果更好,所以爲其他控制器/動作調整它需要一個新的部分和相應的render:partial語句。我已經更新瞭解決方案以反映這一點。將authenticate和require_user過濾器組合成一個過濾器更實用。我覺得解決方案的解釋只是將其分解爲原子步驟,以便將當前的代碼適應該方案。 – EmFi 2010-01-18 04:53:29
哦,還有 - 不應該'render:action =>'user_sessions/new''是'render:template =>'user_sessions/new''(in'require_user')?大概是 – 2010-01-18 05:39:00