2013-08-28 148 views
2

我有一個Rails 3.2應用程序需要用戶登錄(current_user)才能訪問事件頁面,這是子域名。我正在使用設計進行身份驗證。如何讓未登錄的用戶只訪問一次受限制的頁面?

如果我提供了直接鏈接到它,是否有任何方法允許用戶一次性訪問活動頁面?如果他們嘗試訪問不同的活動頁面,或者他們在將來的日期離開並回到同一活動頁面,我會希望他們被提示登錄(或註冊)。

我已經觀看了railscasts的訪客帳戶,但似乎用戶可以繼續以訪客身份登錄,而無需使用此方法註冊。

這裏是我的事件控制器代碼:

def show 
    @event = Event.find_by_name(request.subdomain) 
    if params[:id].present? 
     @event = Event.find(params[:id]) 
    end 
    # if @event.present? and @event.videos.present? 
     @video = Video.find_by_id(params[:video]) || @event.videos.first 
    # else 
    # @video = @event.videos.first 
    # end 
    # @json = Event.all.to_gmaps4rails 
    if @user = current_user 
    else 
     flash[:alert] = "Please sign in first" 
     redirect_to sign_up_url(:subdomain => false) 
    end 
end 

感謝所有幫助/意見...

編輯:只是提供一些更多的上下文:

  1. 我會試圖推動很多用戶每週訪問這一個活動頁面,如果我只是通過社交媒體和電子郵件發送一個鏈接等,我不確定將單獨的哈希值硬編碼到網址中是否可行/實用。

  2. 由於用戶將點擊此鏈接並直接進入相關頁面,因此不會觸發創建單獨的訪客模型的操作,所以我認爲答案必須基於會話,將一些列添加到現有的用戶模型,但確保每個用戶只使用一次。我想也許一個IP地址可以工作?

+0

如何設置'current_user'?您是否在使用Devise進行身份驗證? – zeantsoi

+0

是的,我正在使用設計來設置current_user – jfdimark

+0

瞭解。請參閱下面我提出的解決方案。 – zeantsoi

回答

2

最預見性的解決方案是創建用於包含布爾值來賓用戶會話變量指示它們是否已經訪問該頁面或沒有(如果它們還沒有參觀因此使得能夠訪問,反之亦然):

# in your controller 
before_filter :check_guest, :only => :show 

private 

def check_guest 
    # if user isn't logged in 
    if current_user.nil? 
    # if user has already viewed, redirect 
    if session[:viewed] == true 
     flash[:alert] = "Please sign in first" 
     redirect_to sign_up_url(:subdomain => false) 
    # if user hasn't viewed, allow access, but flag as having viewed 
    else 
     session[:viewed] = true 
    end 
    end 
end 

雖然使用會話是一個事實上的方法這個問題上,是有限制的執行:

  • 會議必須的秩序仍然有效來賓訪問跟蹤瀏覽器的具體
  • (在瀏覽器從而將有多個用戶共享同一個會話)
+0

謝謝zeantsoi。這個基於會話的答案看起來好像會對我所需要的最好。但是我已經嘗試過了,它會一直將我重定向到sign_up頁面,我假設因爲'session [:viewing] = true'會自動設置並觸發。我只有在頁面上時才能將其更新爲true? – jfdimark

+0

嘗試明確評估'session [:viewing] == true'。我已更新我的代碼以反映。這是否有用? – zeantsoi

+0

太好了。有用。我已經適應了一些,所以它還會持續超出會議時間(請參閱我自己的答案),但這幾乎是您的解決方案,所以我已經接受了您的答案,因爲它解決了我原來的問題。 – jfdimark

2

一解決方案,而不是設置會話變量,是使用url對一次哈希進行編碼,如下所示:

http://site.com/event?access_id=AKJHDA23fdsank 

然後,在訪問該事件時,訪問代碼被刪除。這將需要管理數據庫中的訪問代碼,但還有其他好處是萬無一失。

你可以很簡單地創建一個API生成這些鏈接來簡化共享的過程。

其他大部分事情都很容易被欺騙。

+0

謝謝達米安。這聽起來像是一個很好的解決方案,但實際上我不確定它會工作,因爲我只想每週發送一個鏈接,並且我不確定如何發送一個鏈接,但是它會生成多個硬編碼哈希。 。如果我誤解了你的答案,或者如果它可以用於這種情況,我知道。 – jfdimark

+0

@jfdimark你是對的,它不適合這種特殊情況。爲了使會話方法更健壯,您可以記錄他們的IP以及其他不易更改的客戶端數據。當然,擁有正確的技術訣竅仍然很容易規避。我想這主要取決於這個功能應該如何安全。 –

0

我不知道這個預構建的解決方案,但它不應該太難實現。我會做這樣的事情:

class GuestPass < ActiveRecord::Base 

    belongs_to :event 

    # the guest_passes table has a `code` column that contains a long arbitrary string token 
end 

class Event < ActiveRecord::Base 

    has_many :guest_passes 

    def authenticate_guest_pass!(token) 
    return false unless token 
    guest_passes.where(code: token).first 
    end 

end 

class EventsController < ActiveRecord::Base 

    before_action :load_event, only: [ :show ] 
    before_action :validate_guest_pass, unless: current_user 

    private 

    def load_event 
    @event = Event.find(params[:id]) 
    end 

    def validate_guest_pass 
    pass = @event.authenticate_guest_pass!(params[:pass]) 
    if pass 
     pass.delete 
    else 
     # redirect to sign in or whatever 
    end 
    end 

end 

然後,你剛纔生成的GuestPass記錄,並在您提供的鏈接堅持他們,他們會像/events/1?pass=xyzzy

(代碼在這裏可以使用一些潔淨但這是第一次)

+0

感謝gregates。看到我上面的編輯。由於訪客將點擊該應用以外的鏈接,因此不會觸發任何操作,因此無法創建單獨的guest_pass模型,因此我不確定此解決方案是否可行。 – jfdimark

+0

這個想法是,你會預先生成這些並分發包含它們的網址。但是我想我會發現你的用例與我想象中的用例略有不同 - 你希望鏈接是可重用的,但是對於任何特定用戶來說,只能工作一次? – gregates

0

這是我對zeantsoi解決方案稍作修改的版本,即使用戶退出瀏覽器會話,它仍然存在。

def check_guest 
    #if user is logged in 
    unless current_user 
    @event = Event.find_by_name(request.subdomain) 
    #if user has already viewed, redirect 
    if @event.guest_ip_address == request.remote_ip 
     flash[:alert] = "Please sign in first" 
     redirect_to sign_up_url(:subdomain => false) 
    #if user hasn't viewed, allow access, but flag as having viewed and store their ip address in the event model so it knows not to show the page again unless current_user 
    else 
     session[:viewed] = request.remote_ip 
     @event.guest_ip_address = session[:viewed] 
     @event.save! 
    end 
    end 
+0

這阻止了同一個NAT設備背後的所有訪問者,比如說星巴克的位置。 – Fred

+0

弗雷德 - 好點。有沒有這種變化,你可以想到,會實現相同的,但避免一旦有人從該NAT訪問該網站阻止整個咖啡館? – jfdimark

+0

你可以在瀏覽器的DOM中存儲一些值。我認爲現代瀏覽器都支持DOM存儲。 – Fred

相關問題