2010-01-17 46 views
8

有一兩件事你可以在我的rap lyric explanation site做的是「喜歡」的解釋(一旦你登錄)後:提示用戶登錄,他需要一定的作用

http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1645.png

我想向未登錄的用戶顯示「贊」鏈接,然後,當未登錄的用戶點擊「贊」時,向他顯示具有「登錄或註冊」形式的Lightbox(如Digg/Reddit)

http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1650.png

什麼是最好的方法來完成t他?

目前我使用這種方法:

  1. 點擊「贊」的帖子,以/annotations/:id/vote(POST正文指示用戶是否喜歡或「取消頂」)。
  2. vote註解控制器操作有一個require_userbefore_filter看起來像這樣:

    def require_user 
        unless current_user 
        store_desired_location 
        flash[:notice] = "You'll need to login or register to do that" 
        redirect_to login_path # map.login '/login', :controller => 'user_sessions', :action => 'new' 
        return false 
        end 
    end 
    
  3. user_sessions#new看起來是這樣的:

    def new 
        @user_session = UserSession.new 
        respond_to do |format| 
        format.html {} 
        format.js { 
         render :layout => false 
        } 
        end 
    end 
    

的問題是,重定向不似乎在JavaScript上正常工作:

http://dl.getdropbox.com/u/2792776/screenshots/2010-01-17_1700.png

如何獲得此重定向?

此外,這是正確的一般方法?我想過的另一個想法是在沒有登錄用戶的情況下,將不同的處理程序附加到JavaScript中的「Like」鏈接(但我不認爲這種方法可以很好地適應其他操作,我希望以同樣的方式處理)

回答

3

這裏有幾個問題需要解決。

  1. 瀏覽器一般不允許重定向到POST請求。

  2. redirect_to不保存沒有額外輸入的格式。

  3. 存儲位置不保留表單數據。

所有這些問題都可以通過消除重定向來解決。

這裏是我如何遞了過去吧:

在required_user重定向相反的,渲染。如果之前的過濾器重定向或呈現掛起的操作被取消。 (不需要返回false)。不幸的是,這條路線模糊了控制器邊界。但是允許簡單的html回退,並且將自己借給DRYness。

新的工作流程的高級視圖將是:

  1. 請求註解#投票(POST)
  2. required_user過濾器失敗
  3. 呈現新的會話
  4. 提交登錄信息和原POST數據返回到註釋#投票(POST)
  5. 投票中的新過濾器捕獲會話信息並登錄。投票按預期進行。如果登錄失敗回到3
  6. 註釋#投票重定向/渲染,因爲它應該

開始通過再處理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個簡單步驟:

  1. 在vote_form_replica部分之後創建新的部分建模。
  2. 將相應的渲染語句添加到新的會話模板。
  3. 將過濾器應用於您的操作。
+0

我認爲你必須在過濾器之前結合':authenticate'和':require_user'。因爲你不能分別調用':require_user',因爲用戶永遠無法登錄。但是,我認爲這是總體上正確的方法 - 特別是用於「重放」用戶的'content_for'技巧他希望登錄時的動作以及通過'before_filter'登錄用戶的一般想法都非常聰明 – 2010-01-18 04:28:53

+0

謝謝。 content_for並不是真的有必要,我只是覺得它讓代碼更易於閱讀。它在你的partials中效果更好,所以爲其他控制器/動作調整它需要一個新的部分和相應的render:partial語句。我已經更新瞭解決方案以反映這一點。將authenticate和require_user過濾器組合成一個過濾器更實用。我覺得解決方案的解釋只是將其分解爲原子步驟,以便將當前的代碼適應該方案。 – EmFi 2010-01-18 04:53:29

+0

哦,還有 - 不應該'render:action =>'user_sessions/new''是'render:template =>'user_sessions/new''(in'require_user')?大概是 – 2010-01-18 05:39:00

0

我會用你在問題底部描述的方式來處理這個問題。在最初顯示頁面之前,請檢查用戶是否已登錄。如果是,則「Like」鏈接應使用其正常行爲。如果沒有,綁定一個點擊事件來顯示註冊/登錄面板。沒有關於這個不能被重複使用的東西。事實上,我們在工作中使用了這種確切的方法。任何需要身份驗證的用戶操作都會遵循其正常行爲,或者根據頁面加載時的登錄狀態彈出通用登錄面板。

+0

「如果沒有,綁定一個點擊事件來顯示註冊/登錄面板」 - 我只是不想爲每個需要用戶登錄的操作執行此操作(另外,當用戶請註冊,我如何確保他原先要求的任何操作?) – 2010-01-18 03:57:34

相關問題